|
|
|
[!cgo] skip 'this test requires cgo to be enabled'
|
|
|
|
|
|
|
|
garble build
|
|
|
|
! stderr 'warning' # check that the C toolchain is happy
|
|
|
|
exec ./main
|
|
|
|
cmp stdout main.stdout
|
|
|
|
! binsubstr main$exe 'PortedField' 'test/main'
|
|
|
|
|
|
|
|
[short] stop # no need to verify this with -short
|
|
|
|
|
|
|
|
# Ensure that reversing works with cgo.
|
|
|
|
env GARBLE_TEST_REVERSING=true
|
|
|
|
exec ./main
|
|
|
|
cp stdout reversing.stdout
|
|
|
|
stdin reversing.stdout
|
|
|
|
garble reverse .
|
|
|
|
cmp stdout reversed.stdout
|
|
|
|
env GARBLE_TEST_REVERSING=false
|
|
|
|
|
|
|
|
garble -tiny build
|
|
|
|
exec ./main
|
|
|
|
cmp stdout main.stdout
|
|
|
|
|
|
|
|
go build
|
|
|
|
! stderr 'warning' # check that the C toolchain is happy
|
|
|
|
exec ./main
|
|
|
|
cmp stdout main.stdout
|
stop loading obfuscated type information from deps
If package P1 imports package P2, P1 needs to know which names from P2
weren't obfuscated. For instance, if P2 declares T2 and does
"reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and
neither should P1.
This information should flow from P2 to P1, as P2 builds before
P1. We do this via obfuscatedTypesPackage; P1 loads the type information
of the obfuscated version of P2, and does a lookup for T2. If T2 exists,
then it wasn't obfuscated.
This mechanism has served us well, but it has downsides:
1) It wastes CPU; we load the type information for the entire package.
2) It's complex; for instance, we need KnownObjectFiles as an extra.
3) It makes our code harder to understand, as we load both the original
and obfuscated type informaiton.
Instead, we now have each package record what names were not obfuscated
as part of its cachedOuput file. Much like KnownObjectFiles, the map
records incrementally through the import graph, to avoid having to load
cachedOutput files for indirect dependencies.
We shouldn't need to worry about those maps getting large;
we only skip obfuscating declared names in a few uncommon scenarios,
such as the use of reflection or cgo's "//export".
Since go/types is relatively allocation-heavy, and the export files
contain a lot of data, we get a nice speed-up:
name old time/op new time/op delta
Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5)
name old bin-B new bin-B delta
Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal)
name old cached-time/op new cached-time/op delta
Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5)
name old sys-time/op new sys-time/op delta
Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5)
name old user-time/op new user-time/op delta
Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5)
Fixes #456.
Updates #475.
3 years ago
|
|
|
binsubstr main$exe 'privateAdd'
|
|
|
|
-- go.mod --
|
|
|
|
module test/main
|
|
|
|
|
|
|
|
go 1.19
|
|
|
|
-- main.go --
|
|
|
|
package main
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
regularFunc()
|
|
|
|
cgoFunc()
|
|
|
|
}
|
|
|
|
-- regular_main.go --
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"runtime"
|
|
|
|
)
|
|
|
|
|
|
|
|
func regularFunc() {
|
|
|
|
if os.Getenv("GARBLE_TEST_REVERSING") == "true" {
|
|
|
|
_, filename, _, _ := runtime.Caller(0)
|
|
|
|
fmt.Println("regular filename:", filename)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
-- cgo_main.go --
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/user"
|
|
|
|
"runtime"
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include "separate.h"
|
|
|
|
|
|
|
|
static int privateAdd(int a, int b) {
|
|
|
|
return a + b;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void goCallback();
|
|
|
|
|
|
|
|
static void callGoCallback() {
|
|
|
|
goCallback();
|
|
|
|
separateFunction();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct portedStruct {
|
stop loading obfuscated type information from deps
If package P1 imports package P2, P1 needs to know which names from P2
weren't obfuscated. For instance, if P2 declares T2 and does
"reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and
neither should P1.
This information should flow from P2 to P1, as P2 builds before
P1. We do this via obfuscatedTypesPackage; P1 loads the type information
of the obfuscated version of P2, and does a lookup for T2. If T2 exists,
then it wasn't obfuscated.
This mechanism has served us well, but it has downsides:
1) It wastes CPU; we load the type information for the entire package.
2) It's complex; for instance, we need KnownObjectFiles as an extra.
3) It makes our code harder to understand, as we load both the original
and obfuscated type informaiton.
Instead, we now have each package record what names were not obfuscated
as part of its cachedOuput file. Much like KnownObjectFiles, the map
records incrementally through the import graph, to avoid having to load
cachedOutput files for indirect dependencies.
We shouldn't need to worry about those maps getting large;
we only skip obfuscating declared names in a few uncommon scenarios,
such as the use of reflection or cgo's "//export".
Since go/types is relatively allocation-heavy, and the export files
contain a lot of data, we get a nice speed-up:
name old time/op new time/op delta
Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5)
name old bin-B new bin-B delta
Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal)
name old cached-time/op new cached-time/op delta
Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5)
name old sys-time/op new sys-time/op delta
Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5)
name old user-time/op new user-time/op delta
Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5)
Fixes #456.
Updates #475.
3 years ago
|
|
|
char* PortedField;
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
func cgoFunc() {
|
|
|
|
fmt.Println(C.privateAdd(C.int(1), C.int(2)))
|
|
|
|
_, _ = user.Current()
|
|
|
|
|
stop loading obfuscated type information from deps
If package P1 imports package P2, P1 needs to know which names from P2
weren't obfuscated. For instance, if P2 declares T2 and does
"reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and
neither should P1.
This information should flow from P2 to P1, as P2 builds before
P1. We do this via obfuscatedTypesPackage; P1 loads the type information
of the obfuscated version of P2, and does a lookup for T2. If T2 exists,
then it wasn't obfuscated.
This mechanism has served us well, but it has downsides:
1) It wastes CPU; we load the type information for the entire package.
2) It's complex; for instance, we need KnownObjectFiles as an extra.
3) It makes our code harder to understand, as we load both the original
and obfuscated type informaiton.
Instead, we now have each package record what names were not obfuscated
as part of its cachedOuput file. Much like KnownObjectFiles, the map
records incrementally through the import graph, to avoid having to load
cachedOutput files for indirect dependencies.
We shouldn't need to worry about those maps getting large;
we only skip obfuscating declared names in a few uncommon scenarios,
such as the use of reflection or cgo's "//export".
Since go/types is relatively allocation-heavy, and the export files
contain a lot of data, we get a nice speed-up:
name old time/op new time/op delta
Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5)
name old bin-B new bin-B delta
Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal)
name old cached-time/op new cached-time/op delta
Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5)
name old sys-time/op new sys-time/op delta
Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5)
name old user-time/op new user-time/op delta
Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5)
Fixes #456.
Updates #475.
3 years ago
|
|
|
st := C.struct_portedStruct{}
|
|
|
|
fmt.Println(st.PortedField == nil)
|
|
|
|
|
|
|
|
C.callGoCallback()
|
|
|
|
}
|
|
|
|
|
|
|
|
//export goCallback
|
|
|
|
func goCallback() {
|
|
|
|
fmt.Println("go callback")
|
|
|
|
// TODO: support reversing filenames in cgo files
|
|
|
|
if false && os.Getenv("GARBLE_TEST_REVERSING") == "true" {
|
|
|
|
_, filename, _, _ := runtime.Caller(0)
|
|
|
|
fmt.Println("cgo filename:", filename)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
-- separate.h --
|
|
|
|
void separateFunction();
|
|
|
|
-- separate.c --
|
|
|
|
#include "_cgo_export.h"
|
|
|
|
|
|
|
|
void separateFunction() {
|
|
|
|
goCallback();
|
|
|
|
}
|
|
|
|
-- main.stdout --
|
|
|
|
3
|
stop loading obfuscated type information from deps
If package P1 imports package P2, P1 needs to know which names from P2
weren't obfuscated. For instance, if P2 declares T2 and does
"reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and
neither should P1.
This information should flow from P2 to P1, as P2 builds before
P1. We do this via obfuscatedTypesPackage; P1 loads the type information
of the obfuscated version of P2, and does a lookup for T2. If T2 exists,
then it wasn't obfuscated.
This mechanism has served us well, but it has downsides:
1) It wastes CPU; we load the type information for the entire package.
2) It's complex; for instance, we need KnownObjectFiles as an extra.
3) It makes our code harder to understand, as we load both the original
and obfuscated type informaiton.
Instead, we now have each package record what names were not obfuscated
as part of its cachedOuput file. Much like KnownObjectFiles, the map
records incrementally through the import graph, to avoid having to load
cachedOutput files for indirect dependencies.
We shouldn't need to worry about those maps getting large;
we only skip obfuscating declared names in a few uncommon scenarios,
such as the use of reflection or cgo's "//export".
Since go/types is relatively allocation-heavy, and the export files
contain a lot of data, we get a nice speed-up:
name old time/op new time/op delta
Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5)
name old bin-B new bin-B delta
Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal)
name old cached-time/op new cached-time/op delta
Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5)
name old sys-time/op new sys-time/op delta
Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5)
name old user-time/op new user-time/op delta
Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5)
Fixes #456.
Updates #475.
3 years ago
|
|
|
true
|
|
|
|
go callback
|
|
|
|
go callback
|
|
|
|
-- reversed.stdout --
|
|
|
|
regular filename: test/main/regular_main.go
|
|
|
|
3
|
|
|
|
true
|
|
|
|
go callback
|
|
|
|
go callback
|