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

Skip to content

Commit ecf0a57

Browse files
committed
Add fuzzer for operator module
1 parent 71ede86 commit ecf0a57

3 files changed

Lines changed: 143 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-operator
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-operator:
45+
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"operator.py\"" -ldl $(LDFLAGS) -o fuzzer-operator

fuzz_targets.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ email email.py
77
html html.py
88
httpclient httpclient.py
99
json json.py
10+
operator operator.py
1011
plistlib plist.py
1112
re re.py
1213
tarfile tarfile.py

operator.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
from fuzzeddataprovider import FuzzedDataProvider
2+
import operator
3+
4+
MAX_LIST_SIZE = 50 # cap on generated list/sequence sizes to avoid OOM
5+
6+
# Top-level fuzzer operation targets
7+
OP_COMPARISONS = 0
8+
OP_ARITHMETIC = 1
9+
OP_UNARY = 2
10+
OP_SEQUENCE = 3
11+
OP_ITEMGETTER = 4
12+
OP_ATTRGETTER = 5
13+
OP_METHODCALLER = 6
14+
15+
# Sequence operation targets
16+
SEQ_CONTAINS = 0
17+
SEQ_COUNT_OF = 1
18+
SEQ_INDEX_OF = 2
19+
SEQ_GETITEM = 3
20+
SEQ_CONCAT = 4
21+
SEQ_SETITEM = 5
22+
SEQ_DELITEM = 6
23+
SEQ_LENGTH_HINT = 7
24+
25+
def op_comparisons(fdp):
26+
a = fdp.ConsumeRandomValue()
27+
b = fdp.ConsumeRandomValue()
28+
ops = [operator.lt, operator.le, operator.gt, operator.ge,
29+
operator.eq, operator.ne]
30+
op = fdp.PickValueInList(ops)
31+
op(a, b)
32+
33+
def op_arithmetic(fdp):
34+
a = fdp.ConsumeInt(4)
35+
b = fdp.ConsumeInt(4)
36+
ops = [operator.add, operator.sub, operator.mul, operator.mod,
37+
operator.floordiv, operator.truediv, operator.pow,
38+
operator.lshift, operator.rshift,
39+
operator.and_, operator.or_, operator.xor]
40+
op = fdp.PickValueInList(ops)
41+
if op == operator.pow and isinstance(b, (int, float)):
42+
b = b % 20 if isinstance(b, int) else b
43+
if op in (operator.lshift, operator.rshift) and isinstance(b, int):
44+
b = abs(b) % 64
45+
op(a, b)
46+
47+
def op_unary(fdp):
48+
a = fdp.ConsumeRandomValue()
49+
ops = [operator.neg, operator.pos, operator.abs, operator.invert,
50+
operator.index]
51+
op = fdp.PickValueInList(ops)
52+
op(a)
53+
54+
def op_sequence(fdp):
55+
n = fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 100))
56+
lst = fdp.ConsumeIntList(n, 1)
57+
target = fdp.ConsumeIntInRange(SEQ_CONTAINS, SEQ_LENGTH_HINT)
58+
if target == SEQ_CONTAINS:
59+
operator.contains(lst, fdp.ConsumeInt(1))
60+
elif target == SEQ_COUNT_OF:
61+
operator.countOf(lst, fdp.ConsumeInt(1))
62+
elif target == SEQ_INDEX_OF:
63+
try:
64+
operator.indexOf(lst, fdp.ConsumeInt(1))
65+
except ValueError:
66+
pass
67+
elif target == SEQ_GETITEM:
68+
idx = fdp.ConsumeIntInRange(0, max(len(lst) - 1, 0))
69+
operator.getitem(lst, idx)
70+
elif target == SEQ_CONCAT:
71+
operator.concat(lst, fdp.ConsumeIntList(fdp.ConsumeIntInRange(0, MAX_LIST_SIZE), 1))
72+
elif target == SEQ_SETITEM:
73+
idx = fdp.ConsumeIntInRange(0, max(len(lst) - 1, 0))
74+
operator.setitem(lst, idx, fdp.ConsumeInt(1))
75+
elif target == SEQ_DELITEM:
76+
idx = fdp.ConsumeIntInRange(0, max(len(lst) - 1, 0))
77+
operator.delitem(lst, idx)
78+
elif target == SEQ_LENGTH_HINT:
79+
operator.length_hint(lst)
80+
81+
def op_itemgetter(fdp):
82+
n = fdp.ConsumeIntInRange(1, MAX_LIST_SIZE)
83+
lst = fdp.ConsumeIntList(n, 1)
84+
if not lst:
85+
return
86+
num_keys = fdp.ConsumeIntInRange(1, len(lst))
87+
keys = [fdp.ConsumeIntInRange(0, len(lst) - 1) for _ in range(num_keys)]
88+
getter = operator.itemgetter(*keys) if len(keys) > 1 else operator.itemgetter(keys[0])
89+
getter(lst)
90+
91+
def op_attrgetter(fdp):
92+
class Obj:
93+
pass
94+
obj = Obj()
95+
attrs = ['x', 'y', 'z', 'w']
96+
for a in attrs:
97+
setattr(obj, a, fdp.ConsumeInt(1))
98+
num_attrs = fdp.ConsumeIntInRange(1, len(attrs))
99+
chosen = [fdp.PickValueInList(attrs) for _ in range(num_attrs)]
100+
getter = operator.attrgetter(*chosen) if len(chosen) > 1 else operator.attrgetter(chosen[0])
101+
getter(obj)
102+
103+
def op_methodcaller(fdp):
104+
s = fdp.ConsumeUnicode(fdp.ConsumeIntInRange(1, 100))
105+
methods = ['upper', 'lower', 'strip', 'title', 'swapcase']
106+
method = fdp.PickValueInList(methods)
107+
caller = operator.methodcaller(method)
108+
caller(s)
109+
110+
# Fuzzes the _operator C module (Modules/_operator.c). Exercises
111+
# comparison operators (lt/le/gt/ge/eq/ne), arithmetic operators
112+
# (add/sub/mul/mod/div/pow/shifts/bitwise), unary operators
113+
# (neg/pos/abs/invert/index), sequence operations (contains/countOf/
114+
# indexOf/getitem/concat/setitem/delitem/length_hint), and the
115+
# itemgetter, attrgetter, and methodcaller helpers.
116+
def FuzzerRunOne(FuzzerInput):
117+
if len(FuzzerInput) < 1 or len(FuzzerInput) > 0x10000:
118+
return
119+
fdp = FuzzedDataProvider(FuzzerInput)
120+
op = fdp.ConsumeIntInRange(OP_COMPARISONS, OP_METHODCALLER)
121+
try:
122+
if op == OP_COMPARISONS:
123+
op_comparisons(fdp)
124+
elif op == OP_ARITHMETIC:
125+
op_arithmetic(fdp)
126+
elif op == OP_UNARY:
127+
op_unary(fdp)
128+
elif op == OP_SEQUENCE:
129+
op_sequence(fdp)
130+
elif op == OP_ITEMGETTER:
131+
op_itemgetter(fdp)
132+
elif op == OP_ATTRGETTER:
133+
op_attrgetter(fdp)
134+
elif op == OP_METHODCALLER:
135+
op_methodcaller(fdp)
136+
except Exception:
137+
pass

0 commit comments

Comments
 (0)