Skip to content

Commit 8502efe

Browse files
authored
Merge pull request #1922 from DaveLak/fix-fuzz-submodule-expected-exceptions-handling
Add graceful handling of expected exceptions in fuzz_submodule.py
2 parents 2345c1a + 2b64dee commit 8502efe

File tree

2 files changed

+44
-11
lines changed

2 files changed

+44
-11
lines changed

‎fuzzing/fuzz-targets/fuzz_submodule.py‎

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,23 @@
33
importos
44
importtempfile
55
fromconfigparserimportParsingError
6-
fromutilsimportis_expected_exception_message
6+
fromutilsimportis_expected_exception_message, get_max_filename_length
7+
fromgitimportRepo, GitCommandError, InvalidGitRepositoryError
78

8-
ifgetattr(sys, "frozen", False) andhasattr(sys, "_MEIPASS"):
9+
ifgetattr(sys, "frozen", False) andhasattr(sys, "_MEIPASS"):# pragma: no cover
910
path_to_bundled_git_binary=os.path.abspath(os.path.join(os.path.dirname(__file__), "git"))
1011
os.environ["GIT_PYTHON_GIT_EXECUTABLE"] =path_to_bundled_git_binary
1112

12-
withatheris.instrument_imports():
13-
fromgitimportRepo, GitCommandError, InvalidGitRepositoryError
13+
ifnotsys.warnoptions: # pragma: no cover
14+
# The warnings filter below can be overridden by passing the -W option
15+
# to the Python interpreter command line or setting the `PYTHONWARNINGS` environment variable.
16+
importwarnings
17+
importlogging
18+
19+
# Fuzzing data causes some modules to generate a large number of warnings
20+
# which are not usually interesting and make the test output hard to read, so we ignore them.
21+
warnings.simplefilter("ignore")
22+
logging.getLogger().setLevel(logging.ERROR)
1423

1524

1625
defTestOneInput(data):
@@ -42,12 +51,12 @@ def TestOneInput(data):
4251
writer.release()
4352

4453
submodule.update(init=fdp.ConsumeBool(), dry_run=fdp.ConsumeBool(), force=fdp.ConsumeBool())
45-
4654
submodule_repo=submodule.module()
47-
new_file_path=os.path.join(
48-
submodule_repo.working_tree_dir,
49-
f"new_file_{fdp.ConsumeUnicodeNoSurrogates(fdp.ConsumeIntInRange(1, 512))}",
55+
56+
new_file_name=fdp.ConsumeUnicodeNoSurrogates(
57+
fdp.ConsumeIntInRange(1, max(1, get_max_filename_length(submodule_repo.working_tree_dir)))
5058
)
59+
new_file_path=os.path.join(submodule_repo.working_tree_dir, new_file_name)
5160
withopen(new_file_path, "wb") asnew_file:
5261
new_file.write(fdp.ConsumeBytes(fdp.ConsumeIntInRange(1, 512)))
5362
submodule_repo.index.add([new_file_path])
@@ -67,16 +76,24 @@ def TestOneInput(data):
6776
)
6877
repo.index.commit(f"Removed submodule {submodule_name}")
6978

70-
except (ParsingError, GitCommandError, InvalidGitRepositoryError, FileNotFoundError, BrokenPipeError):
79+
except (
80+
ParsingError,
81+
GitCommandError,
82+
InvalidGitRepositoryError,
83+
FileNotFoundError,
84+
FileExistsError,
85+
IsADirectoryError,
86+
NotADirectoryError,
87+
BrokenPipeError,
88+
):
7189
return-1
72-
except(ValueError, OSError)ase:
90+
exceptValueErrorase:
7391
expected_messages= [
7492
"SHA is empty",
7593
"Reference at",
7694
"embedded null byte",
7795
"This submodule instance does not exist anymore",
7896
"cmd stdin was empty",
79-
"File name too long",
8097
]
8198
ifis_expected_exception_message(e, expected_messages):
8299
return-1
@@ -85,6 +102,7 @@ def TestOneInput(data):
85102

86103

87104
defmain():
105+
atheris.instrument_all()
88106
atheris.Setup(sys.argv, TestOneInput)
89107
atheris.Fuzz()
90108

‎fuzzing/fuzz-targets/utils.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
importatheris# pragma: no cover
2+
importos# pragma: no cover
23
fromtypingimportList# pragma: no cover
34

45

@@ -20,3 +21,17 @@ def is_expected_exception_message(exception: Exception, error_message_list: List
2021
iferror.lower() inexception_message:
2122
returnTrue
2223
returnFalse
24+
25+
26+
@atheris.instrument_func
27+
defget_max_filename_length(path: str) ->int: # pragma: no cover
28+
"""
29+
Get the maximum filename length for the filesystem containing the given path.
30+
31+
Args:
32+
path (str): The path to check the filesystem for.
33+
34+
Returns:
35+
int: The maximum filename length.
36+
"""
37+
returnos.pathconf(path, "PC_NAME_MAX")

0 commit comments

Comments
(0)