mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
builder: fix SIGSEGV when stripping duplicate function definitions
The previous approach of erasing basic blocks one-by-one from duplicate function definitions could crash with a segfault. When a function has complex control flow (branches, switches, PHI nodes), deleting a basic block that is still referenced by instructions in other blocks of the same function causes use-after-free in LLVM. LLVM's C++ Function::deleteBody() avoids this by calling dropAllReferences() on all blocks first, but that API is not exposed in the Go LLVM bindings. Fix this by using a completely different approach: instead of manually deleting the function body, set the duplicate function's linkage to LinkOnceODRLinkage. This tells the LLVM linker that the definition can be merged with another copy, causing it to prefer the already-linked ExternalLinkage definition in the destination module. The result is the same (the runtime's definition wins) but without any unsafe block manipulation.
This commit is contained in:
+3
-4
@@ -551,7 +551,8 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
// body in a standard library package that was previously
|
||||
// just a declaration provided by //go:linkname from the
|
||||
// runtime. In that case, keep the existing (runtime)
|
||||
// definition and turn the new one into a declaration.
|
||||
// definition by weakening the new one's linkage so the
|
||||
// LLVM linker discards it in favor of the existing one.
|
||||
for fn := pkgMod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
|
||||
if fn.IsDeclaration() {
|
||||
continue
|
||||
@@ -560,9 +561,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if existing.IsNil() || existing.IsDeclaration() {
|
||||
continue
|
||||
}
|
||||
for _, bb := range fn.BasicBlocks() {
|
||||
bb.EraseFromParent()
|
||||
}
|
||||
fn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
}
|
||||
err = llvm.LinkModules(mod, pkgMod)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user