Skip to content

Commit d4cb92f

Browse files
aykevldeadprogram
authored andcommitted
compiler: fix passing weirdly-padded structs to new goroutines
The values were stored in the passed object as the values itself (not expanded like is common in the calling convention), and read back after assuming they were expanded. This often works for simple parameters (int, pointer, etc), but not for more complex parameters. Especially when there's padding. Found this while working on `//go:wasmexport`.
1 parent ee5bc65 commit d4cb92f

File tree

5 files changed

+28
-15
lines changed

5 files changed

+28
-15
lines changed

compiler/goroutine.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (b *builder) createGo(instr *ssa.Go) {
4949
// Get all function parameters to pass to the goroutine.
5050
var params []llvm.Value
5151
for _, param := range instr.Call.Args {
52-
params = append(params, b.getValue(param, getPos(instr)))
52+
params = append(params, b.expandFormalParam(b.getValue(param, getPos(instr)))...)
5353
}
5454

5555
var prefix string

compiler/testdata/goroutine-cortex-m-qemu-tasks.ll

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ source_filename = "goroutine.go"
33
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
44
target triple = "thumbv7m-unknown-unknown-eabi"
55

6-
%runtime._string = type { ptr, i32 }
7-
86
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
97

108
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -150,12 +148,12 @@ define hidden void @main.startInterfaceMethod(ptr %itf.typecode, ptr %itf.value,
150148
entry:
151149
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
152150
store ptr %itf.value, ptr %0, align 4
153-
%1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
151+
%1 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
154152
store ptr @"main$string", ptr %1, align 4
155-
%.repack1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1, i32 1
156-
store i32 4, ptr %.repack1, align 4
157-
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
158-
store ptr %itf.typecode, ptr %2, align 4
153+
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
154+
store i32 4, ptr %2, align 4
155+
%3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
156+
store ptr %itf.typecode, ptr %3, align 4
159157
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr undef) #9
160158
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
161159
ret void

compiler/testdata/goroutine-wasm-asyncify.ll

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ source_filename = "goroutine.go"
33
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
44
target triple = "wasm32-unknown-wasi"
55

6-
%runtime._string = type { ptr, i32 }
7-
86
@"main$string" = internal unnamed_addr constant [4 x i8] c"test", align 1
97

108
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
@@ -161,12 +159,12 @@ entry:
161159
%0 = call align 4 dereferenceable(16) ptr @runtime.alloc(i32 16, ptr null, ptr undef) #9
162160
call void @runtime.trackPointer(ptr nonnull %0, ptr nonnull %stackalloc, ptr undef) #9
163161
store ptr %itf.value, ptr %0, align 4
164-
%1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1
162+
%1 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 1
165163
store ptr @"main$string", ptr %1, align 4
166-
%.repack1 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 1, i32 1
167-
store i32 4, ptr %.repack1, align 4
168-
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
169-
store ptr %itf.typecode, ptr %2, align 4
164+
%2 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 2
165+
store i32 4, ptr %2, align 4
166+
%3 = getelementptr inbounds { ptr, ptr, i32, ptr }, ptr %0, i32 0, i32 3
167+
store ptr %itf.typecode, ptr %3, align 4
170168
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
171169
ret void
172170
}

testdata/goroutines.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ func main() {
8686
testCond()
8787

8888
testIssue1790()
89+
90+
done := make(chan int)
91+
go testPaddedParameters(paddedStruct{x: 5, y: 7}, done)
92+
<-done
8993
}
9094

9195
func acquire(m *sync.Mutex) {
@@ -243,3 +247,15 @@ func (f Foo) Wait() {
243247
time.Sleep(time.Microsecond)
244248
println(" ...waited")
245249
}
250+
251+
type paddedStruct struct {
252+
x uint8
253+
_ [0]int64
254+
y uint8
255+
}
256+
257+
// Structs with interesting padding used to crash.
258+
func testPaddedParameters(s paddedStruct, done chan int) {
259+
println("paddedStruct:", s.x, s.y)
260+
close(done)
261+
}

testdata/goroutines.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ called: Foo.Nowait
2626
called: Foo.Wait
2727
...waited
2828
done with 'go on interface'
29+
paddedStruct: 5 7

0 commit comments

Comments
 (0)