Skip to content

[WASM] __heap_base not always aligned #2009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fgsch opened this issue Jul 20, 2021 · 10 comments
Closed

[WASM] __heap_base not always aligned #2009

fgsch opened this issue Jul 20, 2021 · 10 comments
Labels
wasm WebAssembly

Comments

@fgsch
Copy link
Contributor

fgsch commented Jul 20, 2021

While investigating a crash using #2003 and with @aykevl help, we found the heap start (__heap_base) is not always aligned.
For example building with:

tinygo build -interp-pass=none -target wasi -o main.wasm code.go

And setting https://github.com/tinygo-org/tinygo/blob/dev/src/runtime/gc_conservative.go#L240 to true, I get:

heapStart:         0x00013551
heapEnd:           0x00040000
total size:        0x0002caaf
metadata size:     0x00000b2a
metadataStart:     0x0003f4d6
# of blocks:       0x00002bf8
# of block states: 0x00002ca8
@aykevl
Copy link
Member

aykevl commented Jul 20, 2021

This may be a LLVM bug, this might be a way to fix it:

diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 63e3dac5d298..5ceb4d76e981 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -312,6 +312,7 @@ void Writer::layoutMemory() {
     // Set `__heap_base` to directly follow the end of the stack or global data.
     // The fact that this comes last means that a malloc/brk implementation
     // can grow the heap at runtime.
+    memoryPtr = alignTo(memoryPtr, 4);
     log("mem: heap base   = " + Twine(memoryPtr));
     WasmSym::heapBase->setVA(memoryPtr);
   }

I haven't tested this patch yet (right now compiling LLVM).

@fgsch
Copy link
Contributor Author

fgsch commented Jul 21, 2021

I can confirm the patch fixes this issue.

@niaow
Copy link
Member

niaow commented Jul 21, 2021

According to #2010, it appears that we may actually need 8 byte alignment.

@aykevl
Copy link
Member

aykevl commented Jul 21, 2021

@fgsch thanks for verifying!

I've made a patch here: https://reviews.llvm.org/D106499, which aligns to 8 bytes.

@aykevl
Copy link
Member

aykevl commented Jul 21, 2021

There are two workarounds from the TinyGo side:

  • remove the --stack-first flag
  • manually align heapStart

The second workaround looks like this:

diff --git a/src/runtime/gc_conservative.go b/src/runtime/gc_conservative.go
index e9682592..b6d18455 100644
--- a/src/runtime/gc_conservative.go
+++ b/src/runtime/gc_conservative.go
@@ -228,6 +228,7 @@ func setHeapEnd(newHeapEnd uintptr) {
 // This function can be called again when the heap size increases. The caller is
 // responsible for copying the metadata to the new location.
 func calculateHeapAddresses() {
+       heapStart = (heapStart + 7) &^ 7
        totalSize := heapEnd - heapStart
 
        // Allocate some memory to keep 2 bits of information about every block.

This is a pretty ugly workaround as-is, but we might need a cleaned-up version of this until the wasm-ld bug is fixed.

@aykevl
Copy link
Member

aykevl commented Jul 24, 2021

I have pushed a change to LLVM to fix this, it should be part of LLVM 13: https://reviews.llvm.org/D106499

@fgsch
Copy link
Contributor Author

fgsch commented Jul 24, 2021

@aykevl great news. In the meantime, should we get the workaround committed?

@aykevl
Copy link
Member

aykevl commented Jul 25, 2021

Yes, but then it should be something like this to not impact other targets:

diff --git a/src/runtime/gc_conservative.go b/src/runtime/gc_conservative.go
index e9682592..935fa591 100644
--- a/src/runtime/gc_conservative.go
+++ b/src/runtime/gc_conservative.go
@@ -228,6 +228,10 @@ func setHeapEnd(newHeapEnd uintptr) {
 // This function can be called again when the heap size increases. The caller is
 // responsible for copying the metadata to the new location.
 func calculateHeapAddresses() {
+       if GOARCH == "wasm" {
+               const heapAlign = 16
+               heapStart = (heapStart + heapAlign - 1) &^ (heapAlign - 1)
+       }
        totalSize := heapEnd - heapStart
 
        // Allocate some memory to keep 2 bits of information about every block.

@aykevl
Copy link
Member

aykevl commented Jul 25, 2021

Fix: #2014
The manual alignment of heapStart should be removed in the future to avoid the increase in code size.

@deadprogram deadprogram added the wasm WebAssembly label Jul 26, 2021
@aykevl aykevl added the next-release Will be part of next release label Aug 15, 2021
@deadprogram
Copy link
Member

Released with 0.20.0 so now closing. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasm WebAssembly
Projects
None yet
Development

No branches or pull requests

4 participants