Skip to content

Commit 778801c

Browse files
authored
[BOLT] Never call fixBranches() on non-simple functions (#141112)
We should never call fixBranches() on a function with invalid CFG. E.g., ValidateInternalCalls modifies CFG for its internal analysis purposes. At the same time, it marks the function as non-simple with an assumption that fixBranches() will never run on that function. However, calculateEmittedSize() by default calls fixBranches() which can lead to all sorts of issues, including assertions firing in fixBranches(). The fix is to use the original size for non-simple functions in calculateEmittedSize() since we are supposed to emit the function unmodified. Additionally, add an assertion at the start of fixBranches().
1 parent 19a4e52 commit 778801c

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

bolt/lib/Core/BinaryContext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,6 +2425,10 @@ BinaryContext::createInstructionPatch(uint64_t Address,
24252425

24262426
std::pair<size_t, size_t>
24272427
BinaryContext::calculateEmittedSize(BinaryFunction &BF, bool FixBranches) {
2428+
// Use the original size for non-simple functions.
2429+
if (!BF.isSimple() || BF.isIgnored())
2430+
return std::make_pair(BF.getSize(), 0);
2431+
24282432
// Adjust branch instruction to match the current layout.
24292433
if (FixBranches)
24302434
BF.fixBranches();

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3579,6 +3579,8 @@ bool BinaryFunction::validateCFG() const {
35793579
}
35803580

35813581
void BinaryFunction::fixBranches() {
3582+
assert(isSimple() && "Expected function with valid CFG.");
3583+
35823584
auto &MIB = BC.MIB;
35833585
MCContext *Ctx = BC.Ctx.get();
35843586

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Check that fixBranches() is not invoked on a broken CFG which could lead to
2+
## unintended consequences including a firing assertion.
3+
4+
# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o
5+
# RUN: link_fdata %s %t.o %t.fdata
6+
# RUN: llvm-strip --strip-unneeded %t.o
7+
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q
8+
# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=cdsplit \
9+
# RUN: --data=%t.fdata --reorder-blocks=ext-tsp 2>&1 | FileCheck %s
10+
11+
# CHECK: internal call detected
12+
13+
.text
14+
15+
.globl foo
16+
.type foo, @function
17+
foo:
18+
ret
19+
.size foo, .-foo
20+
21+
## main contains an internal call. ValidateInternalCalls pass will modify CFG
22+
## (making it invalid) and mark the function as non-simple. After that, we
23+
## cannot make any assumption about the CFG.
24+
25+
.globl main
26+
.type main, @function
27+
main:
28+
call .L1
29+
ret
30+
.L1:
31+
pushq %rbp
32+
movq %rsp, %rbp
33+
movl $1, %edi
34+
LLmain_foo1:
35+
call foo
36+
# FDATA: 1 main #LLmain_foo1# 1 foo 0 0 600
37+
movl $4, %edi
38+
xorl %eax, %eax
39+
popq %rbp
40+
retq
41+
.Lmain_end:
42+
.size main, .Lmain_end-main

0 commit comments

Comments
 (0)