You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
See #403, for example. When we're obfuscating user code, we can fairly easily detect when they are using reflection on an obfuscated type.
Sometimes that pattern will not break the program. For example, using encoding/json on an obfuscated struct type can behave normally without a problem, as long as the fields have json:"..." field tags. Many other uses of reflection, such as reflect.Type.Kind, reflect.Type.Len, or reflect.Type.Comparable are largely unaffected by obfuscation.
However, some other times, that pattern will lead to the program misbehaving at run-time. For example, using encoding/json on a struct type without field tags will result in different JSON object keys.
We can't automatically fix these problems for the user, because it's basically impossible to tell the two scenarios apart at compile time. Reflection is arbitrary logic with Go types at run-time, after all.
However, we can give the developer hints or tools to better deal with this wrinkle. Here are some ideas:
Idea 1: build warnings
In garble build, print a warning whenever we detect that an obfuscated Go type is being used with reflection. For example:
$ garble build
# my-mod/main
my-mod/main/main.go:12:3: warning: use of reflection via json.Marshal on obfuscated type my-mod/types.RequestMessage; see https://github.com/burrowers/garble/blob/HEAD/docs/reflection.md
The docs would then tell the user to add one of two type hints to the types package to remove the warning:
// Hint option A: do not obfuscate, as it would break the program
var _ = reflect.TypeOf(RequestMessage{})
// Hint option B: do obfuscate, as it won't break the program.
var _ = garble.AlwaysObfuscate(RequestMessage{})
type RequestMessage struct { ... }
The main upside is that the warning would be printed automatically for all users, so they wouldn't have to do anything extra.
The main downside is that the warnings would probably be prone to false positives by warning about code that won't break.
Another downside is that removing some warnings might be hard or downright impossible, if the type declarations or the uses of reflection are in third party modules.
Idea 2: opt into warnings via a flag or garble vet
Essentially, the same warnings as Idea 1, being explicitly enabled as part of a garble vet or garble -strict build as opposed to just garble build. The mechanism would otherwise work the same, by encouraging the user to add hints.
The main upside is that, since this won't interfere with builds by default, we don't need to be as worried about false positives.
The main downside is that users might forget to use this. Ideally, garble build would mostly work by default, and intuitively guide the user to add any necessary hints otherwise.
--
One extra thought is that we could also reuse the solution we come up here for another kind of run-time logic - interfaces. #3 (comment) already outlines how we could improve our current heuristic, but at the end of the day, if an interface is defined in a package that imports a separate package where the implementation of said interface is defined, we just can't know about that upfront. We can't know about "downstream" uses of interfaces just like we can't know about "downstream" uses of reflection, but we could warn about both.
The text was updated successfully, but these errors were encountered:
Another downside is that removing some warnings might be hard or downright impossible, if the type declarations or the uses of reflection are in third party modules.
Another option, which you may call idea 1B, is to by default only print warnings for the current module. This way, we'd avoid the problem where the developer may be entirely unable to add the necessary type hints. We'd still not warn the user if an upstream library may break, but it's unclear what the user could do about such a warning if it's not their code.
mvdan
added a commit
to mvdan/garble-fork
that referenced
this issue
Oct 22, 2021
We recently improved the automatic detection of reflection.
However, note that a hint may still be needed in some cases,
in particular when the reflection usage happens in a downstream package.
Keep making that suggestion.
Also mention that we obfuscate one package at a time.
I've also written down burrowers#406 with more ideas on how we could polish this
rough edge for end users in the future.
Fixesburrowers#403.
We recently improved the automatic detection of reflection.
However, note that a hint may still be needed in some cases,
in particular when the reflection usage happens in a downstream package.
Keep making that suggestion.
Also mention that we obfuscate one package at a time.
I've also written down #406 with more ideas on how we could polish this
rough edge for end users in the future.
Fixes#403.
See #403, for example. When we're obfuscating user code, we can fairly easily detect when they are using reflection on an obfuscated type.
Sometimes that pattern will not break the program. For example, using
encoding/json
on an obfuscated struct type can behave normally without a problem, as long as the fields havejson:"..."
field tags. Many other uses of reflection, such asreflect.Type.Kind
,reflect.Type.Len
, orreflect.Type.Comparable
are largely unaffected by obfuscation.However, some other times, that pattern will lead to the program misbehaving at run-time. For example, using
encoding/json
on a struct type without field tags will result in different JSON object keys.We can't automatically fix these problems for the user, because it's basically impossible to tell the two scenarios apart at compile time. Reflection is arbitrary logic with Go types at run-time, after all.
However, we can give the developer hints or tools to better deal with this wrinkle. Here are some ideas:
Idea 1: build warnings
In
garble build
, print a warning whenever we detect that an obfuscated Go type is being used with reflection. For example:The docs would then tell the user to add one of two type hints to the
types
package to remove the warning:The main upside is that the warning would be printed automatically for all users, so they wouldn't have to do anything extra.
The main downside is that the warnings would probably be prone to false positives by warning about code that won't break.
Another downside is that removing some warnings might be hard or downright impossible, if the type declarations or the uses of reflection are in third party modules.
Idea 2: opt into warnings via a flag or
garble vet
Essentially, the same warnings as Idea 1, being explicitly enabled as part of a
garble vet
orgarble -strict build
as opposed to justgarble build
. The mechanism would otherwise work the same, by encouraging the user to add hints.The main upside is that, since this won't interfere with builds by default, we don't need to be as worried about false positives.
The main downside is that users might forget to use this. Ideally,
garble build
would mostly work by default, and intuitively guide the user to add any necessary hints otherwise.--
One extra thought is that we could also reuse the solution we come up here for another kind of run-time logic - interfaces. #3 (comment) already outlines how we could improve our current heuristic, but at the end of the day, if an interface is defined in a package that imports a separate package where the implementation of said interface is defined, we just can't know about that upfront. We can't know about "downstream" uses of interfaces just like we can't know about "downstream" uses of reflection, but we could warn about both.
The text was updated successfully, but these errors were encountered: