From 96a02e7d2c71e1ceac6ff6cd5e6700191e0eb67c Mon Sep 17 00:00:00 2001 From: Pat Whittingslow Date: Sun, 28 Jun 2026 10:26:49 -0300 Subject: [PATCH] begin writing noipv6 test (#146) --- x/xnet/xnet_tinygo_test.go | 22 ---------- x/xnet/xnet_untinygo_test.go | 79 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 22 deletions(-) delete mode 100644 x/xnet/xnet_tinygo_test.go create mode 100644 x/xnet/xnet_untinygo_test.go diff --git a/x/xnet/xnet_tinygo_test.go b/x/xnet/xnet_tinygo_test.go deleted file mode 100644 index 219b418..0000000 --- a/x/xnet/xnet_tinygo_test.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build !tinygo - -// Exclude tinygo compiler from build since exec package and t.Skip() are unimplemented. -// Also: wouldn't including tinygo cause a recursive call to tinygo test? -package xnet - -import ( - "os/exec" - "testing" -) - -func TestTinyGoTest(t *testing.T) { - if exec.Command("tinygo", "version").Run() != nil { - t.Skip("tinygo not installed") - } - // This takes a long time. Consider running only important - // tests with -run=TestXxx flag: `go test ./... -run=TestXxx` - out, err := exec.Command("tinygo", "test", ".").CombinedOutput() - if err != nil { - t.Fatal("tinygo failed to test:", err, "\n", string(out)) - } -} diff --git a/x/xnet/xnet_untinygo_test.go b/x/xnet/xnet_untinygo_test.go new file mode 100644 index 0000000..36665ed --- /dev/null +++ b/x/xnet/xnet_untinygo_test.go @@ -0,0 +1,79 @@ +//go:build !tinygo + +// Exclude tinygo compiler from build since exec package and t.Skip() are unimplemented. +// Also: wouldn't including tinygo cause a recursive call to tinygo test? +package xnet + +import ( + "debug/elf" + "os" + "os/exec" + "strings" + "testing" +) + +func TestTinyGoTest(t *testing.T) { + if exec.Command("tinygo", "version").Run() != nil { + t.Skip("tinygo not installed") + } + // This takes a long time. Consider running only important + // tests with -run=TestXxx flag: `go test ./... -run=TestXxx` + out, err := exec.Command("tinygo", "test", ".").CombinedOutput() + if err != nil { + t.Fatal("tinygo failed to test:", err, "\n", string(out)) + } +} + +func TestStackAsyncNoIPv6(t *testing.T) { + const name = "mwe.elf" + cmd := exec.Command("go", "build", "-o="+name, "../../examples/min-working-example") + cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64") + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatal(err, "\n", string(out)) + } + defer os.Remove(name) + f, err := os.Open(name) + if err != nil { + t.Fatal(err) + } + defer f.Close() + file, err := elf.NewFile(f) + if err != nil { + t.Fatal(err) + } + syms, err := file.Symbols() + if err != nil { + t.Fatal(err) + } + // Sanity check that symbol/debug information was compiled in normally. + // If this exported method is missing the binary was likely stripped + // (e.g. -ldflags="-s -w") and the IPv6 absence check below would be + // meaningless since every symbol would be gone. + const wantSym = "(*StackAsync).AssimilateDHCPResults" + if !elfContainsSymbol(t, syms, wantSym) { + t.Fatalf("expected symbol %q in %s; symbol table may be stripped", wantSym, name) + } + + // Guarantee the compiler did not aggressively include the IPv6 stack in + // this IPv4-only example. Methods on the unexported stack6 type are the + // IPv6 implementation; their presence means IPv6 code leaked into the + // binary and was not dead-code eliminated. + const ipv6Sym = "(*stack6)" + if elfContainsSymbol(t, syms, ipv6Sym) { + t.Errorf("unexpected IPv6 symbol %q found in %s; IPv6 functionality was not eliminated from IPv4-only build", ipv6Sym, name) + } +} + +// elfContainsSymbol reports whether the ELF binary at path defines a symbol +// whose name contains identifier. It reads the symbol table (.symtab), which a +// normal go build retains. +func elfContainsSymbol(t *testing.T, syms []elf.Symbol, identifier string) bool { + t.Helper() + for i := range syms { + if strings.Contains(syms[i].Name, identifier) { + return true + } + } + return false +}