387 Commits

Author SHA1 Message Date
KismetDev 900696b816 do not create ./build in cwd when cache init is skipped (#1035)
sharedCache is allocated before goVersionOK runs, but CacheDir is
only set once the version check passes. The trim defer in mainErr
only checked sharedCache != nil, so on the too-new-version path
openCache joined an empty CacheDir with "build" and created the
directory in CWD.

Fixes #995.
2026-04-21 17:00:42 +01:00
Paul eef2eae50b fix reflection handling for foreign types and aliases (#1032)
Preserve reflected names for foreign named types, alias-backed unnamed structs,
and foreign struct fields by hashing names with the declaring package or struct
identity as appropriate. Extend the reflect script coverage to assert the
foreign type and field names that must now remain visible.

Fixes #996.

Co-Autored by: 0xKismetDev <131729061+0xKismetDev@users.noreply.github.com>
2026-04-18 17:52:09 +02:00
Daniel Martí b55fa77e31 simplify the typeparams test case added for #1027
The marshaler interface and some of the other types were unnecessary.
The remaining test still fails without the fix,
because the crux of the issue is the separate package
with the Result generic type having Data as a type parameter and field.
2026-04-16 11:19:43 +02:00
Golo Roden cdc4b23ac5 fix fieldToStruct for generics instantiated across package boundaries (#1028)
When compiling a package that instantiates a generic type from another
package, info.Types only contains the instantiated *types.Named. The
*types.Struct case in recordFieldToStruct returns early on instantiated
structs (field != field.Origin()), so the origin struct was never
recorded in fieldToStruct. At rewrite time, looking up the origin field
then failed with "could not find struct for field X".

Fix by also recursing into typ.Origin() for instantiated named types,
so the uninstantiated struct is visited and its fields are recorded.

Fixes #1027.
2026-04-16 00:03:37 +01:00
Daniel Martí cecc5d0017 testdata/script: stop checking that every literal obfuscator is used
This is an inherently flaky test, because even if we generate
thousands of literal strings of varying sizes,
we could still get unlucky and end up not using one of the obfuscators.

I briefly looked at a unit test instead, but at that point it's
a bit silly as the underlying logic picks a random element from a slice.
So the unit test looks almost exactly as the code it's testing.

Remove the test entirely. The code it's testing - that we select across
all of our available obfuscators - is simple enough where we can just
look at it if we want to double check that it does what we expect.
2026-04-15 23:24:06 +02:00
Daniel Martí 093f8688f8 stop testing garble -literals build std
This is very expensive; it takes over 30s to run on my laptop.
We already cover `garble build std` in gogarble.txtar,
so this is merely about testing literal obfuscation.

Given the huge cost, this doesn't seem worth it.
If any bugs are uncovered in the literal obfuscators,
we can always add more test cases here.
2026-04-14 10:32:47 +02:00
Daniel Martí ef2385ee97 internal/literals: restrict the use of expensive obfuscators
The added benchmark script shows these numbers for building and running
with vanilla go on literal sizes between 16B and 2048B,
showing that vanilla Go isn't affected at all by these sizes:

                │      go      │
                │    sec/op    │
    Build/16B     118.1m ± ∞ ¹
    Build/64B     123.1m ± ∞ ¹
    Build/256B    119.7m ± ∞ ¹
    Build/1024B   119.1m ± ∞ ¹
    Build/2048B   124.3m ± ∞ ¹
    Run/16B       1.671m ± ∞ ¹
    Run/64B       1.143m ± ∞ ¹
    Run/256B      1.190m ± ∞ ¹
    Run/1024B     1.222m ± ∞ ¹
    Run/2048B     1.080m ± ∞ ¹

Our simple and swap obfuscators scale pretty well to these same sizes,
only causing moderate slow-downs to build and runtime speeds:

                │                simple                │                 swap                 │
                │    sec/op     vs base                │    sec/op     vs base                │
    Build/16B     268.0m ± ∞ ¹  +126.88% (p=1.000 n=1)   262.0m ± ∞ ¹  +121.80% (p=1.000 n=1)
    Build/64B     253.8m ± ∞ ¹  +106.16% (p=1.000 n=1)   252.4m ± ∞ ¹  +105.00% (p=1.000 n=1)
    Build/256B    265.4m ± ∞ ¹  +121.78% (p=1.000 n=1)   276.7m ± ∞ ¹  +131.16% (p=1.000 n=1)
    Build/1024B   267.4m ± ∞ ¹  +124.44% (p=1.000 n=1)   315.0m ± ∞ ¹  +164.48% (p=1.000 n=1)
    Build/2048B   277.4m ± ∞ ¹  +123.11% (p=1.000 n=1)   383.8m ± ∞ ¹  +208.70% (p=1.000 n=1)
    Run/16B       1.740m ± ∞ ¹    +4.12% (p=1.000 n=1)   1.463m ± ∞ ¹   -12.47% (p=1.000 n=1)
    Run/64B       1.470m ± ∞ ¹   +28.66% (p=1.000 n=1)   1.455m ± ∞ ¹   +27.35% (p=1.000 n=1)
    Run/256B      1.729m ± ∞ ¹   +45.25% (p=1.000 n=1)   1.812m ± ∞ ¹   +52.26% (p=1.000 n=1)
    Run/1024B     1.315m ± ∞ ¹    +7.62% (p=1.000 n=1)   1.352m ± ∞ ¹   +10.60% (p=1.000 n=1)
    Run/2048B     1.425m ± ∞ ¹   +31.93% (p=1.000 n=1)   1.316m ± ∞ ¹   +21.88% (p=1.000 n=1)

However, the other three cause huge slow-downs in both build and runtime speeds:

                │                   split                    │                shuffle                 │                    seed                    │
                │     sec/op       vs base                   │    sec/op      vs base                 │     sec/op       vs base                   │
    Build/16B        326.6m ± ∞ ¹     +176.53% (p=1.000 n=1)    363.1m ± ∞ ¹   +207.44% (p=1.000 n=1)      217.4m ± ∞ ¹      +84.05% (p=1.000 n=1)
    Build/64B        400.6m ± ∞ ¹     +225.34% (p=1.000 n=1)    328.0m ± ∞ ¹   +166.39% (p=1.000 n=1)      262.1m ± ∞ ¹     +112.87% (p=1.000 n=1)
    Build/256B       824.7m ± ∞ ¹     +589.08% (p=1.000 n=1)    588.2m ± ∞ ¹   +391.45% (p=1.000 n=1)      873.7m ± ∞ ¹     +630.05% (p=1.000 n=1)
    Build/1024B     3257.7m ± ∞ ¹    +2634.84% (p=1.000 n=1)   1671.4m ± ∞ ¹  +1303.15% (p=1.000 n=1)     5000.0m ± ∞ ¹    +4097.53% (p=1.000 n=1)
    Build/2048B     5000.0m ± ∞ ¹    +3921.73% (p=1.000 n=1)   3936.4m ± ∞ ¹  +3066.21% (p=1.000 n=1)     5000.0m ± ∞ ¹    +3921.73% (p=1.000 n=1)
    Run/16B          1.680m ± ∞ ¹       +0.51% (p=1.000 n=1)    1.426m ± ∞ ¹    -14.67% (p=1.000 n=1)      1.908m ± ∞ ¹      +14.13% (p=1.000 n=1)
    Run/64B          1.560m ± ∞ ¹      +36.53% (p=1.000 n=1)    1.345m ± ∞ ¹    +17.74% (p=1.000 n=1)      1.704m ± ∞ ¹      +49.10% (p=1.000 n=1)
    Run/256B         2.133m ± ∞ ¹      +79.24% (p=1.000 n=1)    1.833m ± ∞ ¹    +53.98% (p=1.000 n=1)      1.838m ± ∞ ¹      +54.40% (p=1.000 n=1)
    Run/1024B        2.863m ± ∞ ¹     +134.21% (p=1.000 n=1)    1.786m ± ∞ ¹    +46.12% (p=1.000 n=1)   5000.000m ± ∞ ¹  +408975.92% (p=1.000 n=1)
    Run/2048B     5000.000m ± ∞ ¹  +462837.24% (p=1.000 n=1)    2.900m ± ∞ ¹   +168.54% (p=1.000 n=1)   5000.000m ± ∞ ¹  +462837.24% (p=1.000 n=1)

As such, limit the scope of when we apply our obfuscators in two ways.

First, always apply a limit of 2048 bytes for all obfuscators.
As we can see above, the two cheap obfuscators still add some overhead,
and we aren't testing what happens if they run on truly huge strings.
It's likely that they will still cause unexpected slow-down.

Second, split the obfuscators along this line and call them
"cheap" versus "expensive". The expensive ones are only used
for sizes of up to 256 bytes. We still measure moderate slow-downs
in build times of 400-600%, but this is a reasonable compromise for now.
We will be filing bugs with upstream Go about the compiler overhead.

We adjust generateLiterals accordingly;
it now generates 100 literals between MinSize and MaxSize,
which must be obfuscated in some way, and 5 literals past MaxSize,
which don't need to be obfuscated, to check for issues like crashes.

Fixes #928.
2026-04-14 10:32:47 +02:00
Daniel Martí f7b9166616 transform go_asm.h constant names in assembly files
The Go assembler generates go_asm.h with constants like TypeName__size
and TypeName_FieldName for struct types. When garble obfuscates type
and field names, these constants use the obfuscated names, but the
assembly source still refers to the originals, causing build failures.

During transformCompile, save the original-to-obfuscated name mapping
to the build cache. In the second asm pass (after compile has run),
load the mapping and rewrite the .s files with a strings.Replacer.

The work is shared between the compiler and assembler steps
because it would be too much work for the assembler step by itself.
These constants follow patterns like Type_field or Type__size,
so they don't use special characters that we can easily locate.

And the go_asm.h file that the compiler generates already uses
the obfuscated names, which we cannot reverse without the originals.
Fetching the original names and fields would require parsing
and typechecking, which is something that the compiler step does.

Without the fix, the added test fails as follows:

    > exec garble build
    [stderr]
    # test/with.many.dots/main
    ./.tmp/[...]/IQSArvqP.s:30: expected pseudo-register; found R11
    ./.tmp/[...]/IQSArvqP.s:31: expected pseudo-register; found R11
    ./.tmp/[...]/IQSArvqP.s:37: illegal or missing addressing mode for symbol Args__size
    asm: assembly of ./.tmp/[...]/IQSArvqP.s failed

Thanks to Golo Roden for figuring out a test reproducer
as well as the overall approach for a fix to the problem.
The test added here is simplified from his code,
and the fix is inspired by his approach.

Fixes #948.
2026-04-14 01:08:52 +02:00
dajinglingpake 2e5692934c fix random seed warning 2026-04-13 08:05:06 +01:00
Ariel Mashraki 8503b1b55a fix generic anonymous structs as return paramters (#1016) 2026-03-21 21:06:44 +01:00
Daniel Martí 7114403786 drop Go 1.25, support Go 1.26
Beyond the usual updating of version strings, re-running `go generate`,
and updating the patches for the linker, we needed extra changes.

First, the linker started being stricter about which packages
are allowed to linkname runtime names by import path.
Stop obfuscating import paths in runtimeAndLinknamed.

Second, the compiler's intrinsics code adds an "add" function
much like the existing "addF", so tweak the regular expression.

Third, note that there is a new runtimeAndDeps windows-only package,
which we find thanks to the recent improvement to cover many platforms.

Fourth, the code around magic numbers in the runtime has changed,
so rewrite the code which patches it via go/ast.

Fixes #990.
2026-03-15 23:36:56 +01:00
Daniel Martí 41b45f9a9c windows/arm is gone for Go 1.26, use GOARCH=386 instead
We still test GOARCH=arm64 as part of darwin/arm64 below.
2026-03-15 23:36:56 +01:00
Daniel Martí 45b248860e include runtime/pprof in the stdimporter testscript
This starts causing a failure on Go 1.26, which we only capture
in another test via `go test` by accident, so make sure we cover it.
Without a fix and on go1.26, I now see:

    > exec garble build -o=main$exe ./stdimporter
    [stderr]
    # test/main/stdimporter
    link: x9BrC6t: invalid reference to runtime.pprof_goroutineLeakProfileWithLabels
2026-03-15 23:36:56 +01:00
Paul Scheduikat cb98b4daab fix: canonicalize generic field objects for struct hashing
Use `types.Var.Origin()` when mapping and hashing struct fields so selector and
declaration sites share the same canonical field identity. This fixes build
failures for generic aliases and named types over those aliases.

Fixes #924
2026-03-01 22:55:02 +00:00
Paul Scheduikat 1b6cc14d93 fix reflection propagation for generic template calls
Ensure reflected arguments keep field names when passing through generic helpers by propagating through ssa.ChangeType and normalizing generic API call handling.

Also merge dependency reflection metadata correctly from cache hits.

fixes #912
2026-03-01 22:55:02 +00:00
Paul Scheduikat 53c5f022b4 Make -debugdir also output the unobfuscated source tree
This makes the unobfuscated state easily accessible, for debugging.

Obfuscated code is output to: `./<debugdir>/garbled`
The original source code is output to:
`./<debugdir>/source`

Also enable caching for debugdir to allow for faster iteration.
2026-03-01 22:55:02 +00:00
Daniel Martí e693cd0632 stabilize generic type param hashing for anonymous struct fields
Avoid hashing free type parameters by object/name identity in type
hashing and use traversal-local canonical IDs instead.
This keeps obfuscated field names stable across alpha-renamed generic
signatures (e.g. T vs newT), fixing interface/method mismatches.

The added test case fails without the fix:

    > exec garble build
    [stderr]
    # test/main
    YiaBFlNH.go:48: cannot use bT6psGs5O (variable of type *QdwRyqV[aEqmF4M, zpotHfQdnNB]) as E_OKfdHoPH[zpotHfQdnNB] value in return statement: *QdwRyqV[aEqmF4M, zpotHfQdnNB] does not implement E_OKfdHoPH[zpotHfQdnNB] (wrong type for method Redirect)
    		have Redirect(struct{palTavb zpotHfQdnNB})
    		want Redirect(struct{g3N8A_R zpotHfQdnNB})

The fix is Paul's; this is rebased on an updated version of typeutil,
and the test is now part of typeparams.txtar and much smaller.

Fixes #991.

Co-authored-by: Paul Scheduikat <lu4p@pm.me>
2026-02-28 01:22:11 +01:00
Daniel Martí 65ffaa0efb stop ignoring GODEBUG when -tiny is used
GODEBUG started being used for configuring the behavior of the Go
toolchain and standard library, for the sake of smoother transitions
in terms of backwards and forwards compatibility.
See: https://go.dev/doc/godebug

As such, it is not right to have `garble build -tiny` ignore all
GODEBUG settings, because many GODEBUG keys nowadays do not actually
involve debugging what a Go binary is doing.

Moreover, the mechanism we were using broke with Go 1.25.2,
which refactored `func parsedebugvars()` into
`func parseRuntimeDebugVars(godebug string)`,
so our test started breaking as our runtime patching was broken.
2025-10-18 06:42:52 +02:00
Daniel Martí 37e582d581 support Go versions with X: suffixes for GOEXPERIMENTs
A workaround until https://github.com/golang/go/issues/75953 is fixed.

See #978.
2025-10-18 06:42:52 +02:00
Daniel Martí 15a385283b reject invalid Go toolchain versions early
Otherwise we might do odd things, such as trying to open the linker
patches directory "patches/" given that go/version.Lang
returns an empty string for invalid versions.

See #978.
2025-10-18 06:42:52 +02:00
Daniel Martí 9d7c84b0c6 parse go env GOVERSION with go/version directly
We don't need to use a regular expression to find "goN.M" anymore,
as go/version seems to deal with "devel" versions from master just fine.
We can then also stop having two separate fields for the version
of the Go toolchain currently being used.
2025-10-18 06:42:52 +02:00
Daniel Martí 36fcc61c4e support testing/synctest when a non-test package imports "testing" too
As spotted by scripts/check-third-party.sh, it's possible to import
the testing package without using `go test`, so our previous solution
to only load testing/synctest when running `go test` was not enough.

Add a regression test via stdimporter in gogarble.txtar.
2025-08-30 21:38:24 +01:00
Daniel Martí aed2fd2659 add support for Go 1.25 and drop support for 1.24
While strictly speaking it would be okay to leave Go 1.24 support
in place for the time being, we are behind on a few tasks at the moment
so it's best to keep the setup at master simpler for the next release.
Go 1.25 already came out two weeks ago, and it seems to have been
a fairly smooth release, so I don't suspect any end users will have
trouble upgrading to it.

Note that two changes were necessary for garble to work on Go 1.25.0.

First, we stop deduplicating runtimeAndLinknamed with runtimeAndDeps.
Otherwise, for GOOS=windows, internal/runtime/cgroup would be missing
as it is a //go:linkname target from runtime on all platforms,
but it is not transitively imported from runtime on GOOS=windows.

Second, the testing/synctest package is now part of std,
and it is a //go:linkname target from the testing package
but not a transitive import from it. Teach appendListedPackages that,
when loading all packages for a `go test` run, it should load
the new testing/synctest package too.

Fixes #968.
2025-08-30 21:38:24 +01:00
bobo liu 1b9c305df2 obey build flags in garble reverse
Fixes an unintentional regression in 6ac80db02c.
2025-08-08 00:17:22 +01:00
Daniel Martí 59eee83beb clarify why TestScript sets GONOSUMDB (#958)
And unset it in gotoolchain.txtar, as that one testscript
does fetch modules from the real proxy.golang.org.

Closes #950.
2025-06-15 19:16:51 +02:00
Paul Scheduikat 87ebebb520 format testscript files with gofmt 2025-06-15 17:25:20 +01:00
Paul Scheduikat 8d8ba00515 properly handle controlflow obfuscation in code that uses unsafe
Due to unsafe not being a real dependency, type checking during control-flow obfuscation was performed incorrectly.
This is fixed by excluding unsafe from the dependency checks.


Fixes #903
2025-06-12 14:25:09 +02:00
pagran d47e0761eb Prevent automated plaintext extraction of literals with current tools (#930)
Some programs which could automatically reverse string literals obfuscated with `-literals` exist.

They currently work by emulating the string literal decryption functions we insert.

We prevent this naive emulation from succeeding by making the decryption functions dependent on global state.

This can still be broken with enough effort, we are curious which approach reverse-engineers come up with next, we certainly still have some ideas to make this harder.

Fixes #926
---------

Co-authored-by: Paul Scheduikat <lu4p@pm.me>
2025-06-03 02:37:51 +02:00
Daniel Martí 9cf2a6a77f properly patch the linker when GOROOT is a symlink
Some Go version managers like github.com/voidint/g use GOROOT symlinks,
which silently broke the way we patch the linker via go build -overlay.

Reproduced the original crash via the following testscript:

    env GARBLE_CACHE=${WORK}/garble-cache
    symlink goroot -> /usr/lib/go
    env GOROOT=${WORK}/goroot
    exec garble run main.go

    -- main.go --
    package main

    import "fmt"

    func main() {
        fmt.Println("hello world")
    }

We don't commit this testscript given how it's an expensive test
and for a relatively rare edge case whose fix is now well documented.
Moreover, as GOTOOLCHAIN is now available, I expect version managers
for Go to fade away with time.

While here, remove a debugging 'exec cat' from a testscript.

Fixes #915.
2025-04-26 16:42:15 +02:00
Daniel Martí aa67c654dc refuse to obfuscate bytedance/sonic/loader
Or any other package which uses a //go:linkname to the runtime names
"lastmoduledatap" or "moduledataverify1". These are used by sonic
to inject function headers to the runtime, which does not work
as garble patches the runtime as part of obfuscation.
The way it alters the magic number in function headers breaks this.

Add a summary of this as a comment too.

Fixes #898.
2025-04-22 14:55:58 +02:00
Daniel Martí db4c8e52d5 add a testscript with the linknames that bytedance/sonic/loader has
For #898.
2025-04-22 14:55:58 +02:00
Daniel Martí b34a7e3926 avoid patching our reflect code into _cgo_gotypes.go
When obfuscating a main package whose Go files all import "C",
the first Go file in CompiledGoFiles ends up being _cgo_gotypes.go.
We cannot add our code from reflect_abi_code.go there,
as it leads to the following error about its _trieNode type:

    typecheck error: $WORK/b001/_cgo_gotypes.go:185:10: cannot define new methods on non-local type _trieNode

Avoid patching any _cgo_*.go file with our reflect code,
as all of those files are special glue code for cgo.

While here, tweak reflectMainPrePatch to return a string
for consistency with abiNamePatch.

Fixes #916.
2025-04-21 07:41:15 +02:00
Daniel Martí b5d90cb1bd expose cgo issue 916
Seems to happen when the main package only has Go files importing "C",
meaning that it has zero "pure Go" files.

To avoid needing two main package Go builds for cgo.txtar,
switch our main package to this scenario as it seems more interesting.

While here, add a test case for a Go callback function taking a C param
as that is relatively common and we had no coverage for it.

This only reproduces the bug; the fix is coming separately.

For #916.
2025-04-21 07:41:15 +02:00
Daniel Martí 2bb1d49874 rely on go build stamping a version for local builds
Before Go 1.24, `go build` only stamped module versions for modules
resolved via GOPROXY, as the local module only had VCS information.
For that reason, we manually built a pseudo-version from the VCS
timestamp and revision stamped for local builds.

Go 1.24 started stamping the main module with a module version
derived from the local VCS information, much like we already did.
For example, comparing a clean build before this change
against a build with this uncommitted change:

    $ go install
    $ garble version
    mvdan.cc/garble v0.14.3-0.20250413182748-e97968ccae46
    [...]
    $ git stash pop
    $ go install
    $ garble version
    mvdan.cc/garble v0.14.3-0.20250413182748-e97968ccae46+dirty
    [...]

The only user-visible change is that local builds with any
uncommitted changes now get a `+dirty` suffix, but that's probably
a good thing for the majority of users, and provides a useful hint
in case a user forgot about local changes.

The test logic to inject VCS information via an env var
and see that the resulting pseudo-version is what we expect can go too,
as that was testing our own main module version logic.
We now rely on `go build` to do the right thing, so don't test that.
2025-04-13 23:10:38 +02:00
Daniel Martí ffed9e5438 drop support for Go 1.23
A pretty small patch, given that 1.23 and 1.24 are quite similar
in terms of what garble does.
2025-04-13 23:10:38 +02:00
Daniel Martí a3a92356d9 refuse to delete unknown files with -debugdir
When creating a new debugdir directory, add a sentinel .garble-debugdir
file at its root so that we can later know that we created it
and the user is very unlikely to have left important data there.

When emptying an existing debugdir directory, only do so if it has
that sentinel file, for added safety.

Fixes #932.
2025-04-05 15:51:00 +01:00
Daniel Martí 8ee4c91196 make gotoolchain.txtar upgrade to the host's GOVERSION
On CI we test on go1.23.x and go1.24.x, so if we always upgrade
to the latest go1.24.x, that will cause garble to complain
when running on go1.23.x:

    garble was built with "go1.23.7" and can't be used with the newer "go1.24.1"

Moreover, the test hard-coded go1.24.1, which is currently the latest
go1.24.x but will not be for long, so this test was brittle.
2025-03-31 01:34:31 +02:00
Daniel Martí db3003b9fa use the correct toolchain "go" tool under GOTOOLCHAIN=auto
We call `go list` to collect information about all the packages
to obfuscate and build, which is crucial to be able to perform
obfuscation of names used across packages.

However, when GOTOOLCHAIN causes a toolchain upgrade,
we must ensure that we use the upgraded Go tool;
otherwise we are mixing information from different toolchain versions.

Fixes #934.
2025-03-31 01:34:31 +02:00
Daniel Martí 7f80dfb59d rebuild cmd/link with the correct toolchain under GOTOOLCHAIN=auto
When we build the patched cmd/link binary for use by garble,
we perform this build in a temporary directory so that the Go module
from the user does not get in the way.

When the user module made us upgrade the toolchain per GOTOOLCHAIN,
leaving that module's directory stops upgrading the toolchain,
so we patch a newer toolchain and build it with an older toolchain.
This is largely harmless, but it makes the newer toolchain think
it is actually an older toolchain, which leads to those pesky
"linker object header mismatch" version errors.

Updates #934.
2025-03-31 01:34:31 +02:00
Daniel Martí 6f7af3b785 add test reproducing gotoolchain upgrade errors
While here, make link.version more readable by adding a newline
and document the assumption it makes about GOVERSION.

For #934.
2025-03-31 01:34:31 +02:00
Daniel Martí 2adfc43326 bump unsupportedGo to mark Go 1.24 as supported
debugdir.txtar also needed tweaking as runtime/map.go is gone
starting in Go 1.24.

Finally, modinfo.txtar needed tweaking since Go 1.24 started stamping
Go binaries with VCS-derived module versions, so we no longer end up
with empty "(devel)" versions.
2025-02-09 21:41:54 +01:00
Paul Scheduikat 97833204f8 skip all type parameters in recordType
We only did this for Container in the type switch, but not for Struct.
The added test case panics otherwise.
Just like in the previous case, we still don't need to recurse
into type parameters for fieldToStruct to be filled correctly.

Fixes #899
2025-01-19 14:13:55 +00:00
Daniel Martí e0dbea2b3d hash structs via the bundled and altered typeutil.hash
As spotted by the protobuf package via check-third-party.sh,
the two structs below are identical:

    type alias1 = int64
    type Struct1 struct { Alias alias1 }

    type alias2 = int64
    type Struct2 struct { Alias alias2 }

Our previous approach with stripStructTags dealt with struct tags,
but it did not deal with aliases, which are now present in go/types
thanks to the new alias tracking.

The new approach properly ignores struct tags and unaliases any
type aliases, resulting in correct hashes of any type.
2025-01-18 05:51:03 +01:00
Daniel Martí 83a06019be rely on go/types alias tracking
Allows us to remove EmbeddedAliasFields, recordedObjectString,
and all the logic around using them.

Resolves an issue where a user was running into a panic in
our logic to record embedded aliases.

Note that this means we require Go 1.23.5 or later now,
which also meant some changes to goversion.txtar to keep it green.

Fixes #827.
2025-01-18 05:51:03 +01:00
Daniel Martí 76905ba3bc use the latest testscript to drop func() int
And don't fail when requesting help, which is what Go's flag package
has been moving towards.
2024-12-26 15:10:14 +01:00
Paul Scheduikat 926f3de60d obfuscate all names used in reflection
Go code can retrieve and use field and method names via the `reflect` package.
For that reason, historically we did not obfuscate names of fields and methods
underneath types that we detected as used for reflection, via e.g. `reflect.TypeOf`.

However, that caused a number of issues. Since we obfuscate and build one package
at a time, we could only detect when types were used for reflection in their own package
or in upstream packages. Use of reflection in downstream packages would be detected
too late, causing one package to obfuscate the names and the other not to, leading to a build failure.

A different approach is implemented here. All names are obfuscated now, but we collect
those types used for reflection, and at the end of a build in `package main`,
we inject a function into the runtime's `internal/abi` package to reverse the obfuscation
for those names which can be used for reflection.

This does mean that the obfuscation for these names is very weak, as the binary
contains a one-to-one mapping to their original names, but they cannot be obfuscated
without breaking too many Go packages out in the wild. There is also some amount
of overhead in `internal/abi` due to this, but we aim to make the overhead insignificant.

Fixes #884, #799, #817, #881, #858, #843, #842

Closes #406
2024-11-27 22:38:43 +01:00
Daniel Martí acec5954ce clarify and test that runtime.GOROOT is not available
Closes #878.
2024-11-24 01:55:13 +01:00
Daniel Martí 30357af923 drop Go 1.22 and require Go 1.23.0 or later (#876)
This lets us start taking advantage of featurs from Go 1.23,
particularly tracking aliases in go/types and iterators.

Note that we need to add code to properly handle or skip over the new
*types.Alias type which go/types produces for Go type aliases.
Also note that we actually turn this mode off entirely for now,
due to the bug reported at https://go.dev/issue/70394.

We don't yet remove our own alias tracking code yet due to the above.
We hope to be able to remove it very soon.
2024-11-17 16:06:57 +01:00
NHAS 69d7b84f35 Fix reflection detection for linknamed methods (#883) 2024-11-02 05:46:03 +01:00
Daniel Martí 48fac78ecc set up go/types.Config.Sizes according to GOARCH
Otherwise we miscalculate int sizes, type sizes, alignments, and so on.
Caught by the GOARCH=386 go test on CI, since the os package imports
internal/syscall/unix, which uses arch-dependent padding.

The different padding between our incorrect use of go/types
and the correct typechecking done by the compiler caused different
obfuscation of fields, as the struct types stringified differently,
and they are used as a hash salt for field name obfuscation.
2024-09-04 21:37:06 +01:00