From e902c2a64fd6279baec68b7f3a2a4689f6ba66f9 Mon Sep 17 00:00:00 2001 From: Moses Narrow <36607567+0pcom@users.noreply.github.com> Date: Tue, 1 Sep 2026 15:16:54 -0500 Subject: [PATCH] crypto/tls: use Go's software TLS on the host target TinyGo's crypto/tls is a thin wrapper around a netdev-provided (hardware/firmware-offloaded) TLS socket, which only exists on the embedded/wasm targets that have such a netdev. On the host/native target the netdev is raw syscalls with no TLS offload, so crypto/tls could never actually work there. Link Go's full software crypto/tls on the host instead, keyed off needsSyscallPackage, which is true exactly for the embedded/wasm targets. Go's crypto/tls needs one runtime hook TinyGo lacked: weak.runtime_makeStrongFromWeak (Go 1.24 weak pointers). Add it next to the existing registerWeakPointer as a strong-reference no-op (weak pointers are never collected here, so the referent is always alive). --- loader/goroot.go | 12 +++++++++++- src/runtime/runtime.go | 8 ++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/loader/goroot.go b/loader/goroot.go index 0aab0a0e13..59385e3005 100644 --- a/loader/goroot.go +++ b/loader/goroot.go @@ -232,7 +232,6 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool { "": true, "crypto/": true, "crypto/rand/": false, - "crypto/tls/": false, "crypto/x509/": true, "crypto/x509/internal/": true, "crypto/x509/internal/macos/": false, @@ -279,6 +278,17 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool { paths["crypto/internal/entropy/v1.0.0/"] = false } + // crypto/tls: TinyGo's version is a thin wrapper around a netdev-provided + // (hardware/firmware-offloaded) TLS socket, which only makes sense on + // embedded/wasm targets that have such a netdev. On the host/native target + // (raw-syscall netdev, no TLS offload) there is no real TLS that way, so use + // Go's full software crypto/tls instead — leaving crypto/tls out of the + // overrides map makes the goroot link Go's implementation. needsSyscallPackage + // is true exactly for the embedded/wasm targets. + if needsSyscallPackage { + paths["crypto/tls/"] = false + } + if needsSyscallPackage { paths["syscall/"] = true // include syscall/js paths["internal/syscall/"] = true diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index 6ad14fe101..ba4c8a04f1 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -139,6 +139,14 @@ func registerWeakPointer(ptr unsafe.Pointer) unsafe.Pointer { return ptr } +//go:linkname makeStrongFromWeak weak.runtime_makeStrongFromWeak +func makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer { + // Counterpart to registerWeakPointer above. Because weak pointers are never + // collected here (the "weak" handle is just the pointer itself), the + // referent is always still alive, so return it unchanged. + return u +} + var godebugUpdate func(string, string) //go:linkname godebug_setUpdate internal/godebug.setUpdate