From 9fd0567fb5d2ffbf217e3417f77dce479509f92e Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 22 Dec 2022 00:48:12 +0000 Subject: [PATCH] compiler: fix stack overflow when creating recursive pointer types There were two types that could result in a compiler stack overflow. This is difficult to fix in LLVM 14, so I won't even bother. However, this is trivial to fix with opaque pointers in LLVM 15. Therefore, this fix is for LLVM 15 only. Fixes: https://github.com/tinygo-org/tinygo/issues/3341 --- compiler/channel.go | 4 ++-- compiler/compiler.go | 16 ++++++++++++---- compiler/testdata/basic.go | 6 ++++++ compiler/testdata/basic.ll | 2 ++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compiler/channel.go b/compiler/channel.go index 81f84565..0ce9aa66 100644 --- a/compiler/channel.go +++ b/compiler/channel.go @@ -43,7 +43,7 @@ func (b *builder) createChanSend(instr *ssa.Send) { } // Allocate blockedlist buffer. - channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList") + channelBlockedList := b.getLLVMRuntimeType("channelBlockedList") channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList") // Do the send. @@ -75,7 +75,7 @@ func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value { } // Allocate blockedlist buffer. - channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList") + channelBlockedList := b.getLLVMRuntimeType("channelBlockedList") channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList") // Do the receive. diff --git a/compiler/compiler.go b/compiler/compiler.go index 8b6e8661..903031fb 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -76,6 +76,7 @@ type compilerContext struct { i8ptrType llvm.Type // for convenience rawVoidFuncType llvm.Type // for convenience funcPtrAddrSpace int + hasTypedPointers bool // for LLVM 14 backwards compatibility uintptrType llvm.Type program *ssa.Program diagnostics []error @@ -123,6 +124,7 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C dummyFuncType := llvm.FunctionType(c.ctx.VoidType(), nil, false) dummyFunc := llvm.AddFunction(c.mod, "tinygo.dummy", dummyFuncType) c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace() + c.hasTypedPointers = c.i8ptrType != llvm.PointerType(c.ctx.Int16Type(), 0) // with opaque pointers, all pointers are the same type (LLVM 15+) c.rawVoidFuncType = dummyFunc.Type() dummyFunc.EraseFromParentAsFunction() @@ -422,14 +424,20 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type { } return c.getLLVMType(typ.Underlying()) case *types.Pointer: - ptrTo := c.getLLVMType(typ.Elem()) - return llvm.PointerType(ptrTo, 0) + if c.hasTypedPointers { + ptrTo := c.getLLVMType(typ.Elem()) + return llvm.PointerType(ptrTo, 0) + } + return c.i8ptrType // all pointers are the same case *types.Signature: // function value return c.getFuncType(typ) case *types.Slice: - elemType := c.getLLVMType(typ.Elem()) + ptrType := c.i8ptrType + if c.hasTypedPointers { + ptrType = llvm.PointerType(c.getLLVMType(typ.Elem()), 0) + } members := []llvm.Type{ - llvm.PointerType(elemType, 0), + ptrType, c.uintptrType, // len c.uintptrType, // cap } diff --git a/compiler/testdata/basic.go b/compiler/testdata/basic.go index d2b4a96d..6c6f983e 100644 --- a/compiler/testdata/basic.go +++ b/compiler/testdata/basic.go @@ -90,3 +90,9 @@ func foo() { // Use this type. func(b kv) {}(kv{}) } + +type T1 []T1 +type T2 [2]*T2 + +var a T1 +var b T2 diff --git a/compiler/testdata/basic.ll b/compiler/testdata/basic.ll index 6ef0dc92..4daf7b7c 100644 --- a/compiler/testdata/basic.ll +++ b/compiler/testdata/basic.ll @@ -7,6 +7,8 @@ target triple = "wasm32-unknown-wasi" %main.kv.0 = type { i8, i32, i32, i32 } @main.kvGlobal = hidden global %main.kv zeroinitializer, align 4 +@main.a = hidden global { ptr, i32, i32 } zeroinitializer, align 4 +@main.b = hidden global [2 x ptr] zeroinitializer, align 4 declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0