Skip to content

Commit fd71dff

Browse files
author
Craig Ringer
committed
Demonstrate how to trick llvm scan-build's core.StackAddressEscape
1 parent 64e5d52 commit fd71dff

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

c/clang_return_stack_checks/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ sigjmp_escape_noinner
77
sigjmp_escape_noinner_fake*
88
sigjmp_escape_hdr
99
sigjmp_escape_inner_pop
10+
mask_local_escape
1011
scan-build-*/

c/clang_return_stack_checks/Makefile

+8-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@ sigjmp_escape_hdr: sigjmp_escape_hdr.c sigjmp_escape_hdr_try.c | tmpdir
4747
$(CC) $(CFLAGS) -DUSE_FINALLY -c sigjmp_escape_hdr.c -o sigjmp_escape_hdr.o
4848
$(CC) $(CFLAGS_LINK) sigjmp_escape_hdr.o sigjmp_escape_hdr_try.o -o $@
4949

50+
mask_local_escape: mask_local_escape.c | tmpdir
51+
$(CC) $(CFLAGS) $< -o $@
52+
5053
clean:
51-
rm -f *.o guard.so return_stack_escape sigjmp_escape sigjmp_escape_fake* sigjmp_escape_guard sigjmp_escape_guard_fake* sigjmp_escape_guard_inner_pop sigjmp_escape_hdr
54+
rm -f *.o guard.so return_stack_escape sigjmp_escape sigjmp_escape_fake* sigjmp_escape_guard sigjmp_escape_guard_fake* sigjmp_escape_guard_inner_pop sigjmp_escape_hdr mask_local_escape
5255
rm -rf scan-build-*
5356

5457
run_return_stack_escape: return_stack_escape
@@ -67,6 +70,9 @@ run_sigjmp_escape_hdr: sigjmp_escape_hdr
6770
if ./sigjmp_escape_hdr 0 1; then exit 1; fi
6871
./sigjmp_escape_hdr 1 1
6972

70-
run: run_return_stack_escape run_sigjmp_escape run_sigjmp_escape_hdr
73+
run_mask_local_escape: mask_local_escape
74+
./mask_local_escape
75+
76+
run: run_return_stack_escape run_sigjmp_escape run_sigjmp_escape_hdr run_mask_local_escape
7177

7278
check: run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Demonstrate how to trick llvm scan-build's core.StackAddressEscape checker
3+
* via simple indirection.
4+
*/
5+
6+
#include <stdio.h>
7+
#include <assert.h>
8+
9+
struct chain_container {
10+
int * leaky_member;
11+
struct chain_container * previous;
12+
};
13+
14+
struct chain_container * sneaky_chain_container = 0;
15+
16+
void
17+
escape_via_sneaky_chain_assignment_1(void)
18+
{
19+
struct chain_container new_entry = {0,0};
20+
int g = 1;
21+
fprintf(stderr, "&g = %p\n", &g);
22+
/* g escapes into global scope */
23+
sneaky_chain_container->leaky_member = &g;
24+
/* Pointer to container is replaced with indirect pointer via chain */
25+
new_entry.previous = sneaky_chain_container;
26+
sneaky_chain_container = &new_entry;
27+
28+
/*
29+
* Restore container pointer from caller.
30+
*
31+
* scan-build has lost track of &g in its leaky_member now.
32+
*/
33+
sneaky_chain_container = sneaky_chain_container->previous;
34+
35+
/* even though we definitely leak it */
36+
assert(sneaky_chain_container->leaky_member == &g);
37+
}
38+
39+
void
40+
escape_via_sneaky_chain_assignment(void)
41+
{
42+
struct chain_container parent_sneaky = {0,0};
43+
sneaky_chain_container = &parent_sneaky;
44+
escape_via_sneaky_chain_assignment_1();
45+
/*
46+
* pointer to auto variable from escape_via_sneaky_chain_assignment_1
47+
* has escaped. Dereferencing it would be a memory error.
48+
*/
49+
fprintf(stderr, "&g has escaped: %p\n",
50+
sneaky_chain_container->leaky_member);
51+
52+
/*
53+
* Ensure we don't complain about &parent_sneaky escaping.
54+
*/
55+
sneaky_chain_container = 0;
56+
}
57+
58+
int
59+
main(void)
60+
{
61+
escape_via_sneaky_chain_assignment();
62+
return 0;
63+
}

0 commit comments

Comments
 (0)