From b40703e9860ef5872bc57fff0cbb91ee6c964208 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 10 Jul 2021 12:17:43 +0200 Subject: [PATCH] wasm: override dlmalloc heap implementation from wasi-libc These two heaps conflict with each other, so that if any function uses the dlmalloc heap implementation it will eventually result in memory corruption. This commit fixes this by implementing all heap-related functions. This overrides the functions that are implemented in wasi-libc. That's why all of them are implemented (even if they just panic): to make sure no program accidentally uses the wrong one. --- main_test.go | 29 ++++++++++---------- src/runtime/arch_tinygowasm.go | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/main_test.go b/main_test.go index 51fd21fd2..9ed0c6c54 100644 --- a/main_test.go +++ b/main_test.go @@ -125,7 +125,7 @@ func TestCompiler(t *testing.T) { // Test with few optimizations enabled (no inlining, etc). t.Run("opt=1", func(t *testing.T) { t.Parallel() - runTestWithConfig("stdlib.go", "", t, &compileopts.Options{ + runTestWithConfig("stdlib.go", "", t, compileopts.Options{ Opt: "1", }, nil, nil) }) @@ -134,15 +134,14 @@ func TestCompiler(t *testing.T) { // TODO: fix this for stdlib.go, which currently fails. t.Run("opt=0", func(t *testing.T) { t.Parallel() - runTestWithConfig("print.go", "", t, &compileopts.Options{ + runTestWithConfig("print.go", "", t, compileopts.Options{ Opt: "0", }, nil, nil) }) t.Run("ldflags", func(t *testing.T) { t.Parallel() - runTestWithConfig("ldflags.go", "", t, &compileopts.Options{ - Opt: "z", + runTestWithConfig("ldflags.go", "", t, compileopts.Options{ GlobalValues: map[string]map[string]string{ "main": { "someGlobal": "foobar", @@ -188,20 +187,20 @@ func runBuild(src, out string, opts *compileopts.Options) error { } func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []string) { - options := &compileopts.Options{ - Target: target, - Opt: "z", - PrintIR: false, - DumpSSA: false, - VerifyIR: true, - Debug: true, - PrintSizes: "", - WasmAbi: "", + options := compileopts.Options{ + Target: target, } runTestWithConfig(name, target, t, options, cmdArgs, environmentVars) } -func runTestWithConfig(name, target string, t *testing.T, options *compileopts.Options, cmdArgs, environmentVars []string) { +func runTestWithConfig(name, target string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) { + // Set default config. + options.Debug = true + options.VerifyIR = true + if options.Opt == "" { + options.Opt = "z" + } + // Get the expected output for this test. // Note: not using filepath.Join as it strips the path separator at the end // of the path. @@ -230,7 +229,7 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O // Build the test binary. binary := filepath.Join(tmpdir, "test") - err = runBuild("./"+path, binary, options) + err = runBuild("./"+path, binary, &options) if err != nil { printCompilerError(t.Log, err) t.Fail() diff --git a/src/runtime/arch_tinygowasm.go b/src/runtime/arch_tinygowasm.go index 0ee3afd3b..753591e9c 100644 --- a/src/runtime/arch_tinygowasm.go +++ b/src/runtime/arch_tinygowasm.go @@ -55,3 +55,51 @@ func growHeap() bool { // Heap has grown successfully. return true } + +// The below functions override the default allocator of wasi-libc. +// Most functions are defined but unimplemented to make sure that if there is +// any code using them, they will get an error instead of (incorrectly) using +// the wasi-libc dlmalloc heap implementation instead. If they are needed by any +// program, they can certainly be implemented. + +//export malloc +func libc_malloc(size uintptr) unsafe.Pointer { + return alloc(size) +} + +//export free +func libc_free(ptr unsafe.Pointer) { + free(ptr) +} + +//export calloc +func libc_calloc(nmemb, size uintptr) unsafe.Pointer { + // Note: we could be even more correct here and check that nmemb * size + // doesn't overflow. However the current implementation should normally work + // fine. + return alloc(nmemb * size) +} + +//export realloc +func libc_realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer { + runtimePanic("unimplemented: realloc") + return nil +} + +//export posix_memalign +func libc_posix_memalign(memptr *unsafe.Pointer, alignment, size uintptr) int { + runtimePanic("unimplemented: posix_memalign") + return 0 +} + +//export aligned_alloc +func libc_aligned_alloc(alignment, bytes uintptr) unsafe.Pointer { + runtimePanic("unimplemented: aligned_alloc") + return nil +} + +//export malloc_usable_size +func libc_malloc_usable_size(ptr unsafe.Pointer) uintptr { + runtimePanic("unimplemented: malloc_usable_size") + return 0 +}