basic.txt just builds main.go without a module. Similarly, we leave
imports.txt without a GOPRIVATE, to test the 'go list -m' fallback.
For all other tests, explicitly set GOPRIVATE, to avoid two exec calls -
both 'go env GOPRIVATE' as well as 'go list -m'. Each of those calls
takes in the order of 10ms, so saving ~26 exec calls should easily add
to 200-300ms saved from 'go test -short'.
Error strings should never be capitalized.
A binsubstr line in one of the tests was duplicate and thus useless.
Remove duplicate or trailing spaces in test scripts.
Finally, add a TODO for an optimization I just spotted.
Fixes #2.
Line numbers are now obfuscated, via `//line` comments.
Filenames are now obfuscated via `//line` comments, instead of changing the actual filename.
New flag `-tiny` to reduce the binary size, at the cost of reversibility.
Fixes#93.
The second typecheck lead to the creation of different type objects,
which didn't match the types in the blacklist anymore.
It turns out we don't need the second typecheck,
therfore it is now removed.
Like other tests, importing fmt results in quite a lot of extra work,
due to the lack of build caching.
In this particular test, we wanted fmt.Println so that T.String would be
called in an indirect way, without defining or referencing Stringer
interface in the main package.
We can do that by rolling our own "tinyfmt" package in a dozen or so
lines of code.
Below is how 'go test -short -vet=off -run Script/implement' is
affected, measured via benchcmd and benchstat:
name old time/op new time/op delta
GoTestScriptImplement 3.67s ± 9% 2.65s ±11% -27.68% (p=0.008 n=5+5)
name old user-time/op new user-time/op delta
GoTestScriptImplement 8.18s ± 4% 4.55s ± 9% -44.35% (p=0.008 n=5+5)
name old sys-time/op new sys-time/op delta
GoTestScriptImplement 1.27s ±12% 0.71s ±13% -44.07% (p=0.008 n=5+5)
name old peak-RSS-bytes new peak-RSS-bytes delta
GoTestScriptImplement 145MB ± 1% 145MB ± 2% ~ (p=1.000 n=5+5)
All in all, we shave about one full second. It doesn't seem to affect
the total 'go test -short' noticeably, but every little bit counts.
The test case we had didn't have a realistic-looking module path with a
dot, so we hadn't noticed the bug with IndexByte.
Fix that. We verified that the new test fails if we undo the fix.
Otherwise any build flags like -tags won't be used, and we might easily
end up with errors or incorrect packages.
The common case with -tags is covered by one of the integration test
scripts. On top of that, we add a table-driven unit test to cover all
edge cases, since there are many we can do quickly in a unit test.
Fixes#82.
We don't really care about tools other than "compile" and "link". Stop
trying to keep a complete list.
Use "if err := f(); err != nil {" where it makes sense.
Simplify some declarations, and use a better variable name than "fW".
Instead of doing a 'go list' call every time we need to fetch a
dependency's export file, we now do a single 'go list' call before the
build begins. With the '-deps' flag, it gives us all the dependency
packages recursively.
We store that data in the gob format in a temporary file, and share it
with the future garble sub-processes via an env var.
This required lazy parsing of flags for the 'build' and 'test' commands,
since now we need to run 'go list' with the same package pattern
arguments.
Fixes#63.
The following identifiers are now skipped,
because they never show up in the binary:
- constant identifiers
- identifiers of local variables
(includes function params and named returns)
- identifiers of local types
Implement a literal obfuscator interface,
to allow the easy addition of new encodings.
Add literal obfuscation for byte literals.
Choose a random obfuscator on literal obfuscation,
useful when multiple obfuscators are implemented.
Fixes#62
Injected functions were mistaken for functions implemented outside go.
Asm functions:
obj.Scope().Pos() == 0
obj.Scope().End() == 0
Injected functions:
obj.Scope().Pos() == 0
obj.Scope().End() == 1
We now check for the End instead of the Pos.
This requires a bit of extra magic to replace one constant in
runtime/internal/sys, but that was simple enough given that we can reuse
a lot of the code to parse the files and write them to a temporary dir.
We can also drop the -X flags, as runtime.buildVersion is based on the
constant that we replace here.
Fixes#44, again.
Whilst it may not be particularly common, it is legal to embed fields
where the type has universe scope (e.g. int, error, etc). This can
cause a panic in 2 difference places:
- When embedding `error`, a named type is resolved but the package is
nil. The call to `pkg.Name()` results in a panic
- When embedding a basic type such as `int`, no named type is resolved
at all. The call to `namedType(obj.Type()).Obj()` results in a panic
I'm assuming it is OK to return early when a named type cannot be
resolved.. we could let it continue but I think `pkg` should be set to
nil to be correct, so it'd end up returning straight away anyway.
Since we introduced $GARBLE_DIR, we stopped recommending the use of
toolexec directly. It's still possible to set up the right flags and env
vars, but that will be a moving target.
In particular, string obfuscation in #16 will require using $GARBLE_DIR
in more scenarios. A work-in-progress patch for string obfuscation
triggered this test script to start failing for the reason above.
While at it, we don't care about what the second build contains, since
we already compare it with the previous build.
In the added test, the unexported field used to be garbled.
Reflection can only reach exported methods, exported fields, and
unexported fields. Exported methods and fields are currently never
garbled, so unexported fields was the only missing piece.
Also remove the -toolexec equivalent, as it's becoming longer now that
we have GARBLE_DIR, and it might become out of date in the future again.
We don't want users to assume it will work forever.
Carefully select a default that will do the right thing when inside a
module, as well as when building ad-hoc packages.
This means we no longer need to look at the compiler's -std flag, which
is nice.
Also replace foo.com/ with test/, as per golang/go#37641.
Fixes#7.
Spotted while trying to link a program using unix.Syscall, since its
implementation is assembly.
Telling if a function couldn't be garbled isn't trivial. If that
function belongs to an imported package, we only load its export data
instead of type-checking from source, so we don't have all the
information needed.
Instead, use the gc export data importer to import two versions of each
dependency: its original version, for the initial type-checking, and its
garbled version, to check if any of its exported names weren't garbled.
Updates #9.
We use 'go list -json -export' to locate required modules. This works
fine to locate direct module dependencies; since we're building in the
current module, we run 'go list' in the correct directory.
However, if we're building one of those module dependencies, and it has
other module dependencies of its own, we would fail with cryptic errors
like:
typecheck error: [...] go list error: updates to go.sum needed, disabled by -mod=readonly
This is because we would try to run 'go list' outside of the main
module, probably inside the module cache. Instead, use a $GARBLE_DIR env
var from the top-level 'garble build' call to always run 'go list' in
the original directory.
We add a few small modules to properly test this.
Updates #9.
In the added test case, we'd see a failure, since we garbled the name of
the "Embedded" type but not its use as an anonymous field. Garble both.
This might possibly break some reflect code, but it doesn't seem like we
have an option. When we garble a type, it's impossible to tell if it's
going to be used as an anonymous field later.
Updates #9.
The problem with the "grep" built-in command is that it prints the
entire data if there is an error. We don't want megabytes of binary
output for a test.