llvm / llvm/llvm-project

[BOLT] Gadget scanner reports incomplete CFG in exception-handling functions

Open
#178,058 1 comment 0 reactions 0 assignees View on GitHub
BOLT
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

When C++ function contains exception-handling logic, core BOLT is able to recognize basic blocks as landing pads, but Pointer Authentication analyzer in `llvm-bolt-binary-analysis` does not make use of such information yet.

As a result, "Warning: possibly imprecise CFG, ..." reports may be produced for such functions (at most once per function), even though CFG information may be perfectly valid.

## How to reproduce

Compile the following source

```cpp
void throwing_fn();
void callback(int);

class my_exception {};

int catching_fn() {
try {
throwing_fn();
} catch (const my_exception &) {
callback(1);
}
return 42;
}
```

with recent version of Clang:

```
clang -target aarch64-linux-pauthtest -march=v8.3-a -fuse-ld=lld \
-O3 --shared -nostdlib -Wl,--emit-relocs \
eh-test.cpp -o eh-test.so
```

Please note that `--shared` and `-nostdlib` options here are mostly used not to require custom sysroots to reproduce this bug.

This results in the following report generated by gadget scanner (built from recent mainline commit 3de4d32a7228519312a844bcd48a34124b1a718b):

```
$ ./bin/llvm-bolt-binary-analysis --scanners=pauth ./eh-test.so
BOLT-INFO: shared object or position-independent executable detected
BOLT-INFO: Target architecture: aarch64
BOLT-INFO: BOLT version: 3de4d32a7228519312a844bcd48a34124b1a718b
BOLT-INFO: first alloc address is 0x0
BOLT-INFO: creating new program header table at address 0x200000, offset 0x200000
BOLT-INFO: enabling relocation mode
BOLT-WARNING: Failed to analyze 2 relocations

GS-PAUTH: Warning: possibly imprecise CFG, the analysis quality may be degraded in this function. According to BOLT, unreachable code is found in function _Z11catching_fnv, basic block .LLP0, at address 10764
The instruction is 00010764: cmp w1, #0x1
```

Disassembled `jump_table_test_func` dumped with `-debug-only=bolt-pauth-scanner`

```
Binary Function "_Z11catching_fnv" {
Number : 1
State : CFG constructed
Address : 0x10740
Size : 0x68
MaxSize : 0x68
Offset : 0x740
Section : .text
Orc Section : .local.text._Z11catching_fnv
LSDA : 0x640
IsSimple : 1
IsMultiEntry: 0
IsSplit : 0
BB Count : 6
Personality : DW.ref.__gxx_personality_v0/1
Hash : 2767dbf2af332197
CFI Instrs : 21
BB Layout : .LBB00, .LLP0, .LFT0, .LLP1, .Ltmp0, .LLP2
}
.LBB00 (26 instructions, align : 1)
Entry Point
CFI State : 0
00000000: pacibsp
00000004: stp x29, x30, [sp, #-0x20]!
00000008: !CFI $0 ; OpDefCfaOffset 32
00000008: str x19, [sp, #0x10]
0000000c: mov x29, sp
00000010: !CFI $1 ; OpDefCfa Reg29 32
00000010: !CFI $2 ; OpOffset Reg19 -16
00000010: !CFI $3 ; OpOffset Reg30 -24
00000010: !CFI $4 ; OpOffset Reg29 -32
00000010: !CFI $5 ; OpRememberState
00000010: bl _Z11throwing_fnv@PLT # handler: .LLP0; action: 1
00000014: mov w0, #0x2a
00000018: !CFI $6 ; OpDefCfa Reg31 32
00000018: ldr x19, [sp, #0x10]
0000001c: ldp x29, x30, [sp], #0x20
00000020: !CFI $7 ; OpDefCfaOffset 0
00000020: !CFI $8 ; OpRestore Reg19
00000020: !CFI $9 ; OpRestore Reg30
00000020: !CFI $10 ; OpRestore Reg29
00000020: retab
00000024: !CFI $19 ; OpDefCfa Reg29 32
00000024: !CFI $2 ; OpOffset Reg19 -16
00000024: !CFI $3 ; OpOffset Reg30 -24
00000024: !CFI $4 ; OpOffset Reg29 -32
00000024: !CFI $11 ; OpRestoreState
00000024: !CFI $12 ; OpRememberState
Landing Pads: .LLP0
CFI State: 13

.LLP0 (3 instructions, align : 1)
Landing Pad
CFI State : 13
Throwers: .LBB00
00000024: cmp w1, #0x1
00000028: mov x19, x0
0000002c: b.ne .Ltmp0
Successors: .Ltmp0, .LFT0
CFI State: 13

.LFT0 (19 instructions, align : 1)
CFI State : 13
Predecessors: .LLP0
00000030: mov x0, x19
00000034: bl __cxa_begin_catch@PLT # handler: 0; action: 0
00000038: mov w0, #0x1
0000003c: bl _Z8callbacki@PLT # handler: .LLP1; action: 0
00000040: bl __cxa_end_catch@PLT # handler: 0; action: 0
00000044: mov w0, #0x2a
00000048: !CFI $13 ; OpDefCfa Reg31 32
00000048: ldr x19, [sp, #0x10]
0000004c: ldp x29, x30, [sp], #0x20
00000050: !CFI $14 ; OpDefCfaOffset 0
00000050: !CFI $15 ; OpRestore Reg19
00000050: !CFI $16 ; OpRestore Reg30
00000050: !CFI $17 ; OpRestore Reg29
00000050: retab
00000054: !CFI $20 ; OpDefCfa Reg29 32
00000054: !CFI $2 ; OpOffset Reg19 -16
00000054: !CFI $3 ; OpOffset Reg30 -24
00000054: !CFI $4 ; OpOffset Reg29 -32
00000054: !CFI $18 ; OpRestoreState
Landing Pads: .LLP1
CFI State: 5

.LLP1 (2 instructions, align : 1)
Landing Pad
CFI State : 5
Throwers: .LFT0
00000054: mov x19, x0
00000058: bl __cxa_end_catch@PLT # handler: .LLP2; action: 3
Successors: .Ltmp0
Landing Pads: .LLP2
CFI State: 5

.Ltmp0 (2 instructions, align : 1)
CFI State : 5
Predecessors: .LLP0, .LLP1
0000005c: mov x0, x19
00000060: bl _Unwind_Resume@PLT # handler: 0; action: 0
Successors: .LLP2
CFI State: 5

.LLP2 (1 instructions, align : 1)
Landing Pad
CFI State : 5
Predecessors: .Ltmp0
Throwers: .LLP1
00000064: bl "__clang_call_terminate/1" # handler: 0; action: 0
CFI State: 5

DWARF CFI Instructions:
0: OpDefCfaOffset 32
1: OpDefCfa Reg29 32
2: OpOffset Reg19 -16
3: OpOffset Reg30 -24
4: OpOffset Reg29 -32
5: OpRememberState
6: OpDefCfa Reg31 32
7: OpDefCfaOffset 0
8: OpRestore Reg19
9: OpRestore Reg30
10: OpRestore Reg29
11: OpRestoreState
12: OpRememberState
13: OpDefCfa Reg31 32
14: OpDefCfaOffset 0
15: OpRestore Reg19
16: OpRestore Reg30
17: OpRestore Reg29
18: OpRestoreState
19: OpDefCfa Reg29 32
20: OpDefCfa Reg29 32
End of Function "_Z11catching_fnv"
```

Note that `.LLP0` basic block has no `Predecessors:` field (i.e. the list is empty), but is marked as `Landing Pad`.

## Possible solutions

The easiest solution would probably be to initialize the state of landing pads to all-registers-are-unsafe. This way, we would mark them as *not unexpected*. Some registers may be marked as safe-to-dereference or trusted, according to the ABI, but I'm not aware of any such guaranties.

Contributor guide

Open the contributing guide

Research direction

Start with the Pointer Authentication analyzer in llvm-bolt-binary-analysis and reproduce the warning using the provided C++ exception-handling example and --scanners=pauth command. Inspect how landing pads such as .LLP0 are represented and initialized; done means valid exception-handling CFGs no longer produce the imprecise-CFG warning while the analyzer remains correct for other functions.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.