Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5c0fec7

Browse files
committed
Add fuzzer for array module
1 parent 71ede86 commit 5c0fec7

3 files changed

Lines changed: 110 additions & 2 deletions

File tree

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
all : fuzzer-html fuzzer-email fuzzer-httpclient fuzzer-json fuzzer-difflib fuzzer-csv fuzzer-decode fuzzer-ast fuzzer-tarfile fuzzer-tarfile-hypothesis fuzzer-zipfile fuzzer-zipfile-hypothesis fuzzer-re fuzzer-configparser fuzzer-tomllib fuzzer-plistlib fuzzer-xml fuzzer-zoneinfo
1+
all : fuzzer-html fuzzer-email fuzzer-httpclient fuzzer-json fuzzer-difflib fuzzer-csv fuzzer-decode fuzzer-ast fuzzer-tarfile fuzzer-tarfile-hypothesis fuzzer-zipfile fuzzer-zipfile-hypothesis fuzzer-re fuzzer-configparser fuzzer-tomllib fuzzer-plistlib fuzzer-xml fuzzer-zoneinfo fuzzer-array
22

33
PYTHON_CONFIG_PATH=$(CPYTHON_INSTALL_PATH)/bin/python3-config
44
CXXFLAGS += $(shell $(PYTHON_CONFIG_PATH) --cflags)
5-
LDFLAGS += -rdynamic $(shell $(PYTHON_CONFIG_PATH) --ldflags --embed)
5+
LDFLAGS += -rdynamic $(shell $(PYTHON_CONFIG_PATH) --ldflags --embed) $(CPYTHON_MODLIBS) -Wl,--allow-multiple-definition
66

77
fuzzer-html:
88
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"html.py\"" -ldl $(LDFLAGS) -o fuzzer-html
@@ -40,3 +40,6 @@ fuzzer-xml:
4040
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"xml.py\"" -ldl $(LDFLAGS) -o fuzzer-xml
4141
fuzzer-zoneinfo:
4242
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"zoneinfo.py\"" -ldl $(LDFLAGS) -o fuzzer-zoneinfo
43+
44+
fuzzer-array:
45+
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"array.py\"" -ldl $(LDFLAGS) -o fuzzer-array

array.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from fuzzeddataprovider import FuzzedDataProvider
2+
import array
3+
4+
TYPECODES = list("bBhHiIlLqQfd")
5+
6+
# Top-level operation constants for FuzzerRunOne
7+
OP_FROMBYTES = 0
8+
OP_METHODS = 1
9+
OP_SLICE = 2
10+
11+
# Array method operation constants for op_array_methods
12+
METHOD_REVERSE = 0
13+
METHOD_BYTESWAP = 1
14+
METHOD_POP = 2
15+
METHOD_COUNT = 3
16+
METHOD_INDEX = 4
17+
METHOD_INSERT = 5
18+
METHOD_REMOVE = 6
19+
METHOD_TOBYTES = 7
20+
21+
22+
def _consume_array(fdp):
23+
tc = fdp.PickValueInList(TYPECODES)
24+
itemsize = array.array(tc).itemsize
25+
n_items = fdp.ConsumeIntInRange(0, min(fdp.remaining_bytes() // itemsize, 200))
26+
data = fdp.ConsumeBytes(n_items * itemsize)
27+
a = array.array(tc)
28+
a.frombytes(data)
29+
return a, tc
30+
31+
32+
def op_array_frombytes(fdp):
33+
a, tc = _consume_array(fdp)
34+
a.tobytes()
35+
a.tolist()
36+
37+
38+
def op_array_methods(fdp):
39+
a, tc = _consume_array(fdp)
40+
if len(a) == 0:
41+
return
42+
num_ops = fdp.ConsumeIntInRange(1, 20)
43+
for _ in range(num_ops):
44+
if fdp.remaining_bytes() == 0:
45+
break
46+
op = fdp.ConsumeIntInRange(METHOD_REVERSE, METHOD_TOBYTES)
47+
if op == METHOD_REVERSE:
48+
a.reverse()
49+
elif op == METHOD_BYTESWAP:
50+
a.byteswap()
51+
elif op == METHOD_POP and len(a) > 0:
52+
a.pop()
53+
elif op == METHOD_COUNT and len(a) > 0:
54+
val = fdp.ConsumeRandomValue()
55+
a.count(val)
56+
elif op == METHOD_INDEX and len(a) > 0:
57+
val = fdp.ConsumeRandomValue()
58+
try:
59+
a.index(val)
60+
except ValueError:
61+
pass
62+
elif op == METHOD_INSERT and len(a) > 0:
63+
idx = fdp.ConsumeIntInRange(0, len(a) - 1)
64+
val = fdp.ConsumeRandomValue()
65+
a.insert(idx, val)
66+
elif op == METHOD_REMOVE and len(a) > 0:
67+
val = fdp.ConsumeRandomValue()
68+
try:
69+
a.remove(val)
70+
except ValueError:
71+
pass
72+
elif op == METHOD_TOBYTES:
73+
a.tobytes()
74+
75+
76+
def op_array_slice(fdp):
77+
a, tc = _consume_array(fdp)
78+
if len(a) < 2:
79+
return
80+
start = fdp.ConsumeIntInRange(0, len(a) - 1)
81+
end = fdp.ConsumeIntInRange(start, len(a))
82+
_ = a[start:end]
83+
b = array.array(tc, a[start:end])
84+
a[start:end] = b
85+
86+
87+
# Fuzzes the array module's C implementation (Modules/arraymodule.c).
88+
# Exercises array construction from raw bytes via frombytes(), element-level
89+
# operations (reverse, byteswap, pop, count, index, insert, remove), and
90+
# slice read/write across all 12 typecodes (b/B/h/H/i/I/l/L/q/Q/f/d).
91+
def FuzzerRunOne(FuzzerInput):
92+
if len(FuzzerInput) < 1 or len(FuzzerInput) > 0x10000:
93+
return
94+
fdp = FuzzedDataProvider(FuzzerInput)
95+
op = fdp.ConsumeIntInRange(OP_FROMBYTES, OP_SLICE)
96+
try:
97+
if op == OP_FROMBYTES:
98+
op_array_frombytes(fdp)
99+
elif op == OP_METHODS:
100+
op_array_methods(fdp)
101+
elif op == OP_SLICE:
102+
op_array_slice(fdp)
103+
except Exception:
104+
pass

fuzz_targets.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
array array.py
12
ast ast.py
23
configparser configparser.py
34
csv csv.py

0 commit comments

Comments
 (0)