Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework reflection detection with ssa #644

Closed
wants to merge 1 commit into from

Conversation

lu4p
Copy link
Member

@lu4p lu4p commented Jan 13, 2023

This is significantly more robust, than the ast based detection and can record very complex cases of indirect parameter reflection.

Fixes #554

@lu4p
Copy link
Member Author

lu4p commented Jan 13, 2023

Generics don't seem to like ssa

Copy link
Member

@mvdan mvdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First review - would like to see perf numbers with our benchmark. I can do that if you're not able to.

It would also be interesting to build std and do a diff of what names are obfuscated, to see how large the difference is, and whether we're now leaving too many unobfuscated names. I think using -debugdir with a fixed seed and diffing the source would be enough, but there might be an easier way like having the old and new versions print how they are obfuscating type declarations.

main.go Show resolved Hide resolved
main.go Outdated Show resolved Hide resolved
reflect.go Show resolved Hide resolved
reflect.go Outdated Show resolved Hide resolved
reflect.go Outdated Show resolved Hide resolved
reflect.go Show resolved Hide resolved
reflect.go Outdated Show resolved Hide resolved
@mvdan
Copy link
Member

mvdan commented Jan 18, 2023

Also, very nice to see that with ~250 lines of ssa code, we're already getting pretty good detection!

@lu4p
Copy link
Member Author

lu4p commented Jan 18, 2023

There might be a lot more types getting flagged as being in a fmt.Printf call is now enough, but it's right nonetheless. We might need a obfuscate this anyway mechanism similar to what we told the users when our detection didn't work, maybe now it works to well 😂.

@mvdan
Copy link
Member

mvdan commented Feb 7, 2023

I'm not sure whether detecting fmt print calls is something we should do. For example, neither Println(x) nor Printf("%v", x) break with obfuscation, and they are pretty common. Something similar could happen with Sprintf or log.Printf. I don't think we should avoid obfuscating types just because they are being printed.

I think we should avoid obfuscating types when it's likely that doing so would break the program. I think that's the case with encoding/json or ORMs, since those often rely on field names to match the structure of input data. But for print-like APIs, the worst that can happen is that %#v now prints gibberish instead of the real field names, but that shouldn't completely break a program.

By the way, please note that in 2ee9cf7 I taught garble to not mark types in the reflect package itself as "used for reflection". You should keep that behavior in place, I think.

@mvdan
Copy link
Member

mvdan commented Feb 7, 2023

Happy to do another review if you fix the conflicts. Thanks again for being patient.

@mvdan
Copy link
Member

mvdan commented Feb 12, 2023

Thanks for your patience. Let's get this reviewed and merged this coming week; I don't want to hold up master for v0.9.x any longer.

By the way, please note that in 2ee9cf7 I taught garble to not mark types in the reflect package itself as "used for reflection". You should keep that behavior in place, I think.

I reverted that bit in 5effe20, so I don't think you need to worry about that anymore. Just make sure to break none of the updated tests.

If you can resolve the conflicts and reply to my concern about fmt APIs above, I can do a second review.

This is significantly more robust, than the ast based detection and can
record very complex cases of indirect parameter reflection.

Fixes burrowers#554
Copy link
Member

@mvdan mvdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI appears to be failing?

Also, I typically won't be nitpicky with documenting functions, but the reflection detection with SSA is now pretty darn complex, so please briefly document what ignoreReflectedTypes and checkCalls are doing at a high level.


var reflectSkipPkg = map[string]bool{
"fmt": true,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why code generate this at all, if it's a static map? in fact, why have a map when you can just do path == "fmt" :)

we might want to expand the logic to also consider other reflect APIs as "harmless" by default, but I don't think we should worry about that for now. I don't think we'll need anything more than just fmt for the time being.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like having everything which can't be obfuscated at the same place

reflect.go Show resolved Hide resolved
reflect.go Show resolved Hide resolved
reflect.go Show resolved Hide resolved
return nil
}

/* fmt.Printf("val: %v %T %v\n", val, val, val.Type()) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use // comments for debugging code, for consistency with the rest of the codebase. same elsewhere.

Copy link
Member Author

@lu4p lu4p May 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find a visual distinction between comments and debug prints easier to read.

reflect.go Show resolved Hide resolved
// methods aren't package members only their reciever types are
// so some logic is required to find the methods a type has

// yes, finding all methods really only works with both loops
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that would be surprising to me, and at least misleading documentation in the go/ssa package.

https://go.dev/ref/spec#Method_sets says:

The method set of a pointer to a defined type T (where T is neither a pointer nor an interface) is the set of all methods declared with receiver *T or T.

That is, if you ask for the method set of *T, it should give you both kinds of methods at the same time, avoiding the need for two calls.

I think we should raise a bug upstream (ideally with a small reproducer) and link it here as a TODO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested it again right now still the case

Comment on lines +76 to +79
if fun.Synthetic == "loaded from gc object file" {
// fun.WriteTo crashes otherwise
return
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this ought to be a TODO; either we need better logic in our code, or we should raise a bug upstream to avoid that crash.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still a problem needs to be fixed upstream

Comment on lines +158 to +165
case *ssa.Slice:
return tf.recordArgReflected(val.X, visited)
case *ssa.MakeInterface:
return tf.recordArgReflected(val.X, visited)
case *ssa.UnOp:
return tf.recordArgReflected(val.X, visited)
case *ssa.FieldAddr:
return tf.recordArgReflected(val.X, visited)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this can be replaced by .Operands()? It does exactly same thing and eliminates need for type switch

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this looks a bit repetitive but .Operands often doesn't do what I'm trying to achieve

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

using GORM results in obfuscated table names due to its indirect use of reflection
3 participants