Skip to content

Commit 7d2c2af

Browse files
authored
[lld][WebAssembly] Return 0 for synthetic function offsets (#96134)
When two or more functions' signatures differ, one of them is selected and for other signatures `unreachable` stubs are generated: https://github.com/llvm/llvm-project/blob/57778ec36c9c7e96b76a167f19dccbe00d49c9d4/lld/wasm/SymbolTable.cpp#L975 https://github.com/llvm/llvm-project/blob/57778ec36c9c7e96b76a167f19dccbe00d49c9d4/lld/wasm/SymbolTable.cpp#L852-L870 And when these `SyntheticFunction`s are generated, this constructor is used, https://github.com/llvm/llvm-project/blob/57778ec36c9c7e96b76a167f19dccbe00d49c9d4/lld/wasm/InputChunks.h#L266-L269 which does not set its `function` field: https://github.com/llvm/llvm-project/blob/57778ec36c9c7e96b76a167f19dccbe00d49c9d4/lld/wasm/InputChunks.h#L304 As a result, the `function` field contains a garbage value for these stub functions. `InputFunction::getFunctionCodeOffset()` is called when relocations are resolved for `.debug_info` section to get functions' PC locations. But because these stub functions don't have their `function` field set, this function segfaults: https://github.com/llvm/llvm-project/blob/57778ec36c9c7e96b76a167f19dccbe00d49c9d4/lld/wasm/InputChunks.h#L282 This bug seems to be triggered when these conditions are met: - There is a signature mismatch warning with multiple different definitions (one definition with other declarations is not sufficient) with weak linkage with the same name - The 'stub' function containing unreachable has a callsite, meaning it isn't DCE'd - .debug_info section is generated (i.e., DWARF is used) This PR initializes the field with `nullptr`, and in `InputFunction::getFunctionCodeOffset`, checks if `function` is `nullptr`, and if so, just returns 0. This function is called only for resolving relocations in the `.debug_info` section, and addresses of these stub functions, which are not the functions users wrote in the first place, are not really meaningful anyway.
1 parent 4356356 commit 7d2c2af

File tree

5 files changed

+79
-2
lines changed

5 files changed

+79
-2
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.functype foo (i32) -> ()
2+
.functype test0 () -> ()
3+
4+
.section .text.foo,"",@
5+
.weak foo
6+
.type foo,@function
7+
foo:
8+
.functype foo (i32) -> ()
9+
end_function
10+
11+
.section .text.test0,"",@
12+
.globl test0
13+
.type test0,@function
14+
test0:
15+
.functype test0 () -> ()
16+
i32.const 3
17+
call foo
18+
end_function
19+
20+
.section .debug_info,"",@
21+
.int32 foo
22+
.int32 test0
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.functype foo (i32, i32) -> ()
2+
.functype test1 () -> ()
3+
4+
.section .text.foo,"",@
5+
.weak foo
6+
.type foo,@function
7+
foo:
8+
.functype foo (i32, i32) -> ()
9+
end_function
10+
11+
.section .text.test1,"",@
12+
.globl test1
13+
.type test1,@function
14+
test1:
15+
.functype test1 () -> ()
16+
i32.const 4
17+
i32.const 5
18+
call foo
19+
end_function
20+
21+
.section .debug_info,"",@
22+
.int32 foo
23+
.int32 test1
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.functype test0 () -> ()
2+
.functype test1 () -> ()
3+
.functype main (i32, i32) -> (i32)
4+
5+
.section .text.main,"",@
6+
.globl main
7+
.type main,@function
8+
main:
9+
.functype main (i32, i32) -> (i32)
10+
call test0
11+
call test1
12+
i32.const 0
13+
end_function
14+
15+
.section .debug_info,"",@
16+
.int32 test0
17+
.int32 test1
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This is a regression test that ensures a function signature mismatch in
2+
# functions with debug info does not cause does not cause a segmentation fault
3+
# when writing .debug_info section.
4+
5+
; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/signature-mismatch-debug-info-a.s -o %t.a.o
6+
; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/signature-mismatch-debug-info-b.s -o %t.b.o
7+
; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/signature-mismatch-debug-info-main.s -o %t.main.o
8+
; RUN: wasm-ld -o %t.wasm %t.a.o %t.b.o %t.main.o --export=main --no-entry

lld/wasm/InputChunks.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,14 @@ class InputFunction : public InputChunk {
279279
}
280280
void setExportName(std::string exportName) { this->exportName = exportName; }
281281
uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
282-
uint32_t getFunctionCodeOffset() const { return function->CodeOffset; }
282+
uint32_t getFunctionCodeOffset() const {
283+
// For generated synthetic functions, such as unreachable stubs generated
284+
// for signature mismatches, 'function' reference does not exist. This
285+
// function is used to get function offsets for .debug_info section, and for
286+
// those generated stubs function offsets are not meaningful anyway. So just
287+
// return 0 in those cases.
288+
return function ? function->CodeOffset : 0;
289+
}
283290
uint32_t getFunctionIndex() const { return *functionIndex; }
284291
bool hasFunctionIndex() const { return functionIndex.has_value(); }
285292
void setFunctionIndex(uint32_t index);
@@ -301,7 +308,7 @@ class InputFunction : public InputChunk {
301308
return compressedSize;
302309
}
303310

304-
const WasmFunction *function;
311+
const WasmFunction *function = nullptr;
305312

306313
protected:
307314
std::optional<std::string> exportName;

0 commit comments

Comments
 (0)