Skip to content

Commit 9f96892

Browse files
committed
Add fuzzer for dbm module
Fuzzes CPython's dbm backend — whichever implementation dbm.open() selects on the build, typically the gdbm C module (Modules/_gdbmmodule.c) or _dbm (Modules/_dbmmodule.c). Opens a fresh GDBM-style database in a temp directory with mode "c", then drives a sequence of up to 20 fuzzed operations — store (with fuzzed-length keys and values), get, key listing via db.keys(), membership-guarded delete, and iteration with value lookup — to exercise the hash-table insert/lookup/delete paths and the on-disk file handling in the C backend.
1 parent a7e2ec1 commit 9f96892

3 files changed

Lines changed: 61 additions & 1 deletion

File tree

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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-binascii
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-binascii fuzzer-dbm
22

33
PYTHON_CONFIG_PATH=$(CPYTHON_INSTALL_PATH)/bin/python3-config
44
CXXFLAGS += $(shell $(PYTHON_CONFIG_PATH) --cflags)
@@ -43,3 +43,6 @@ fuzzer-zoneinfo:
4343

4444
fuzzer-binascii:
4545
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"binascii.py\"" -ldl $(LDFLAGS) -o fuzzer-binascii
46+
47+
fuzzer-dbm:
48+
clang++ $(CXXFLAGS) $(LIB_FUZZING_ENGINE) -std=c++17 fuzzer.cpp -DPYTHON_HARNESS_PATH="\"dbm.py\"" -ldl $(LDFLAGS) -o fuzzer-dbm

dbm.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from fuzzeddataprovider import FuzzedDataProvider
2+
import os
3+
import dbm
4+
import tempfile
5+
6+
OP_STORE = 0
7+
OP_GET = 1
8+
OP_LIST_KEYS = 2
9+
OP_DELETE = 3
10+
OP_ITERATE = 4
11+
12+
13+
# Fuzzes the _gdbm C module (Modules/_gdbmmodule.c).
14+
# Exercises key-value store operations on a temporary GDBM database:
15+
# store, get, key listing, deletion, and iteration with fuzzed
16+
# keys and values.
17+
def FuzzerRunOne(FuzzerInput):
18+
if len(FuzzerInput) < 1 or len(FuzzerInput) > 0x10000:
19+
return
20+
fdp = FuzzedDataProvider(FuzzerInput)
21+
try:
22+
with tempfile.TemporaryDirectory() as tmpdir:
23+
dbpath = os.path.join(tmpdir, "fuzzdb")
24+
with dbm.open(dbpath, "c") as db:
25+
num_ops = fdp.ConsumeIntInRange(1, 20)
26+
for _ in range(num_ops):
27+
if fdp.remaining_bytes() == 0:
28+
break
29+
op = fdp.ConsumeIntInRange(OP_STORE, OP_ITERATE)
30+
if op == OP_STORE:
31+
n = fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 100))
32+
key = fdp.ConsumeBytes(n)
33+
n2 = (
34+
fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 1000))
35+
if fdp.remaining_bytes() > 0
36+
else 0
37+
)
38+
val = fdp.ConsumeBytes(n2) if n2 > 0 else b""
39+
db[key] = val
40+
elif op == OP_GET:
41+
n = fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 100))
42+
key = fdp.ConsumeBytes(n)
43+
_ = db.get(key)
44+
elif op == OP_LIST_KEYS:
45+
_ = list(db.keys())
46+
elif op == OP_DELETE:
47+
n = fdp.ConsumeIntInRange(1, min(fdp.remaining_bytes(), 100))
48+
key = fdp.ConsumeBytes(n)
49+
if key in db:
50+
del db[key]
51+
elif op == OP_ITERATE:
52+
for k in db:
53+
_ = db[k]
54+
break
55+
except Exception:
56+
pass

fuzz_targets.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ ast ast.py
22
binascii binascii.py
33
configparser configparser.py
44
csv csv.py
5+
dbm dbm.py
56
decode decode.py
67
difflib difflib.py
78
email email.py

0 commit comments

Comments
 (0)