-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_gdb.py
More file actions
179 lines (160 loc) · 4.5 KB
/
test_gdb.py
File metadata and controls
179 lines (160 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env python3
"""Test GDB tracing and memory tracking on all example programs."""
import subprocess
import sys
sys.path.insert(0, "/app/srcs")
from gdb_tracer import trace_pointer, check_gdb_available
from memory_tracker import find_root_cause_from_trace
print("GDB available:", check_gdb_available())
print()
# Test cases: (name, executable, alloc_file, alloc_line, alloc_var,
# backtrace_functions, caller_file, caller_line,
# expected_type, expected_function)
TESTS = [
(
"test_nofree (never freed)",
"/app/examples/test_nofree/leaky",
"leaky.c", 9, "temp",
["type1_example", "main"],
"leaky.c", 18,
2, "type1_example",
),
(
"test_lost (pointer lost)",
"/app/examples/test_lost/leaky",
"leaky.c", 20, "p",
["ft_a", "main"],
"leaky.c", 35,
2, "ft_a",
),
(
"test_struct (container freed before content)",
"/app/examples/test_struct/leaky",
"leaky.c", 53, "data",
["level_5_alloc", "level_4", "level_3", "level_2", "level_1", "main"],
"leaky.c", 60,
3, "level_1",
),
(
"test_linked_list (loop + indirect free)",
"/app/examples/test_linked_list/leaky",
"leaky.c", 20, "n",
["create_node", "build_list", "main"],
"leaky.c", 38,
3, "partial_cleanup",
),
(
"test_cond (conditional leak)",
"/app/examples/test_cond/leaky",
"leaky.c", 9, "buf",
["create_buffer", "process", "main"],
"leaky.c", 18,
2, "process",
),
(
"test_reuse (pointer reuse)",
"/app/examples/test_reuse/leaky",
"leaky.c", 9, "ptr",
["main"],
"", 0,
2, "main",
),
(
"test_scope (scope leak)",
"/app/examples/test_scope/leaky",
"leaky.c", 9, "tmp",
["init_data", "main"],
"leaky.c", 15,
2, "init_data",
),
(
"test_chain (conditional path)",
"/app/examples/test_chain/leaky",
"leaky.c", 9, "buf",
["allocate", "run", "main"],
"leaky.c", 30,
2, "run",
),
(
"test_swap (struct content forgotten)",
"/app/examples/test_swap/leaky",
"leaky.c", 18, "p->value",
["create_pair", "main"],
"leaky.c", 27,
3, "main",
),
(
"test_array (off-by-one cleanup)",
"/app/examples/test_array/leaky",
"leaky.c", 14, "arr[i]",
["create_array", "main"],
"leaky.c", 39,
3, "cleanup",
),
(
"test_pass (pointer passed as argument)",
"/app/examples/test_pass/leaky",
"leaky.c", 9, "buf",
["create", "main"],
"leaky.c", 23,
1, "main",
),
]
passed = 0
failed = 0
errors = []
for name, exe, af, al, av, bt, cf, cl, exp_type, exp_func in TESTS:
print(f"=== {name} ===")
# Compile
src = exe + ".c"
subprocess.run(["gcc", "-g", "-O0", "-o", exe, src], check=True)
# Trace
result = trace_pointer(exe, af, al, av, bt, cf, cl)
if not result["success"]:
print(f" FAIL: trace failed — {result['error']}")
failed += 1
errors.append(f"{name}: trace failed")
print()
continue
# Run tracker
root_cause = find_root_cause_from_trace(
result["trace"], result["free_events"]
)
if not root_cause:
print(f" FAIL: no root cause found")
failed += 1
errors.append(f"{name}: no root cause found")
print()
continue
# Check results
got_type = root_cause["leak_type"]
got_func = root_cause["function"]
ok = True
if got_type != exp_type:
print(f" FAIL: expected type {exp_type}, got {got_type}")
ok = False
if got_func != exp_func:
print(f" FAIL: expected function '{exp_func}', got '{got_func}'")
ok = False
if ok:
print(f" PASS (type={got_type}, function={got_func})")
passed += 1
else:
failed += 1
errors.append(f"{name}: type={got_type} func={got_func}")
# Print debug info for failed tests
print(f" trace steps: {len(result['trace'])}")
for s in root_cause["steps"]:
print(f" {s}")
print()
# Summary
print("=" * 50)
print(f"Results: {passed} passed, {failed} failed, {len(TESTS)} total")
if errors:
print("\nFailed tests:")
for e in errors:
print(f" - {e}")
sys.exit(1)
else:
print("\nAll tests passed!")
sys.exit(0)