Skip to content

Commit 488b038

Browse files
committed
UA11-008 enhance gnatfuzz testing
Fix errors in the 'analyze_generate' test, and add a new test to check the 'fuzz' workflow. Change-Id: Ib27a9d4953c2a82c96300afbfcb0420e6664fd32
1 parent 27db96f commit 488b038

File tree

8 files changed

+126
-3
lines changed

8 files changed

+126
-3
lines changed

share/support/ui/gnatfuzz_view.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def _selected_row(self):
109109
def debug_candidate(self, task):
110110
"""Workflow to launch a debugger session on the given crash"""
111111
t = TargetWrapper("Build Main")
112-
yield t.wait_on_execute(main_name="fuzz_test_harness.adb")
112+
yield t.wait_on_execute(main_name="gnatfuzz-fuzz_test_harness.adb")
113113
proj = GPS.Project.root()
114114
exec = fuzz_executable()
115115
d = GPS.Debugger.spawn(

testsuite/tests/gnatfuzz.analyze_generate/test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def driver():
3030
if len(messages) > 0:
3131
break
3232

33-
gps_assert(len(messages) > 0, "No messages found after analyze")
33+
gps_assert(len(messages) > 0, True, "No messages found after analyze")
3434
m = messages[0]
3535

3636
# We have one "Fuzzable program" message: click on the action
@@ -44,4 +44,4 @@ def driver():
4444
yield wait_tasks()
4545

4646
# Check that we've switched to the harness project
47-
gps_assert(GPS.Project.root().name() == "Fuzz Testing", "wrong project name after generation")
47+
gps_assert(GPS.Project.root().name(), "Fuzz_Test", "wrong project name after generation")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package body a is
2+
procedure fuzzable (X : Integer) is
3+
Y : Integer;
4+
begin
5+
Y := X + 1;
6+
if Y > 2 then
7+
Y := 2;
8+
end if;
9+
end;
10+
11+
12+
end a;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package a is
2+
procedure fuzzable (X : Integer);
3+
end a;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
project p is
2+
for Object_Dir use "obj";
3+
end p;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
if [ "`type gnatfuzz 2>/dev/null`" = "" ]; then
2+
# Mark test as DEAD if gnatfuzz is not found
3+
exit 99
4+
fi
5+
6+
export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
7+
export AFL_SKIP_CPUFREQ=1
8+
9+
# gnatfuzz analyze to find the fuzzable subprograms
10+
gnatfuzz analyze -Pp.gpr > /dev/null
11+
12+
# gnatfuzz generate to generate a fuzz harness
13+
gnatfuzz generate -Pp.gpr --analysis obj/gnatfuzz/analyze.json --subprogram-id 1 -o harness > /dev/null
14+
15+
# Run the test
16+
$GNATSTUDIO --load=python:test.py -P harness/fuzz_testing/fuzz_test.gpr
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""Tests the behavior of the GNATfuzz integration, on the
2+
"fuzz" parts of the workflow.
3+
"""
4+
5+
from distutils.log import debug
6+
from gs_utils.internal.utils import (
7+
run_test_driver,
8+
timeout,
9+
get_button_from_label,
10+
get_widget_by_name,
11+
get_window_by_title,
12+
gps_assert,
13+
idle_modal_dialog,
14+
wait_for_mdi_child,
15+
)
16+
from pygps import double_click_events
17+
from pygps.tree import click_in_tree
18+
19+
INCREMENTS_MS = 1000 # Timeout increments
20+
MAX_TIME_MS = 20 * 1000 # Max timeout wait
21+
22+
@run_test_driver
23+
def driver():
24+
# Launch a fuzzing session
25+
yield idle_modal_dialog(lambda: GPS.execute_action("gnatfuzz fuzz workflow"))
26+
yield wait_for_mdi_child("gnatfuzz fuzz")
27+
dialog = get_window_by_title("gnatfuzz fuzz")
28+
get_button_from_label("Execute", dialog).clicked()
29+
30+
yield wait_for_mdi_child("Fuzz Crashes")
31+
32+
view = get_widget_by_name("fuzz_crash_list_view")
33+
model = view.get_model()
34+
35+
# Wait 20 seconds at most, until messages appear in the "Fuzz crashes" view
36+
37+
time_waited = 0
38+
39+
while time_waited < MAX_TIME_MS:
40+
if len(model) > 0:
41+
break
42+
yield timeout(INCREMENTS_MS)
43+
time_waited += INCREMENTS_MS
44+
45+
# Test the contents of the model: presence of the crash...
46+
gps_assert(model[0][0], "1 (Crash)", "wrong contents in the first row")
47+
48+
# ... and the fact that the faulty parameter (causing integer overflow)
49+
# is properly found by the fuzzer and displayed in the view.
50+
gps_assert(
51+
int(model[0, 0][1]),
52+
2**31 - 1,
53+
"wrong value for the parameter which causes the crash",
54+
)
55+
56+
# We can stop fuzzing now that we've had one crash
57+
GPS.execute_action("gnatfuzz fuzz workflow")
58+
59+
# Click in the view to launch a debug workflow
60+
click_in_tree(view, path="0", events=double_click_events)
61+
62+
# Wait 20 seconds at most, until we have the right data in the debugger view
63+
64+
debugger_text = None
65+
66+
time_waited = 0
67+
68+
expected_text = "Y := X + 1"
69+
70+
while time_waited < MAX_TIME_MS:
71+
yield timeout(INCREMENTS_MS)
72+
time_waited += INCREMENTS_MS
73+
d = None
74+
try:
75+
d = GPS.Debugger.get()
76+
except GPS.Exception:
77+
pass
78+
if d is None:
79+
continue
80+
debugger_text = d.get_console().get_text()
81+
82+
# The debugger console should contain this
83+
if expected_text in debugger_text:
84+
break
85+
86+
87+
gps_assert(expected_text in debugger_text, True,
88+
f"{expected_text} didn't appear in output:\n{debugger_text}")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
title: 'gnatfuzz.fuzz_simple'

0 commit comments

Comments
 (0)