fuzz_object_store.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import stat
  2. import sys
  3. from io import BytesIO
  4. from typing import Optional
  5. import atheris
  6. with atheris.instrument_imports():
  7. # We instrument `test_utils` as well, so it doesn't block coverage analysis in Fuzz Introspector:
  8. from test_utils import EnhancedFuzzedDataProvider, is_expected_exception
  9. from dulwich.errors import ObjectFormatException
  10. from dulwich.objects import S_IFGITLINK, Blob, Commit, Tree
  11. from dulwich.patch import write_tree_diff
  12. from dulwich.repo import (
  13. InvalidUserIdentity,
  14. MemoryRepo,
  15. )
  16. def TestOneInput(data) -> Optional[int]:
  17. fdp = EnhancedFuzzedDataProvider(data)
  18. repo = MemoryRepo()
  19. blob = Blob.from_string(fdp.ConsumeRandomBytes())
  20. tree = Tree()
  21. tree.add(
  22. fdp.ConsumeRandomBytes(),
  23. fdp.PickValueInList([stat.S_IFREG, stat.S_IFLNK, stat.S_IFDIR, S_IFGITLINK]),
  24. blob.id,
  25. )
  26. commit = Commit()
  27. commit.tree = tree.id
  28. commit.author = fdp.ConsumeRandomBytes()
  29. commit.committer = fdp.ConsumeRandomBytes()
  30. commit.commit_time = fdp.ConsumeRandomInt()
  31. commit.commit_timezone = fdp.ConsumeRandomInt()
  32. commit.author_time = fdp.ConsumeRandomInt()
  33. commit.author_timezone = fdp.ConsumeRandomInt()
  34. commit.message = fdp.ConsumeRandomBytes()
  35. object_store = repo.object_store
  36. try:
  37. object_store.add_object(blob)
  38. object_store.add_object(tree)
  39. object_store.add_object(commit)
  40. except (InvalidUserIdentity, ObjectFormatException):
  41. return -1
  42. except ValueError as e:
  43. expected_exceptions = [
  44. "subsection not found",
  45. "Unable to handle non-minute offset",
  46. ]
  47. if is_expected_exception(expected_exceptions, e):
  48. return -1
  49. else:
  50. raise e
  51. commit2 = Commit()
  52. commit2.tree = tree.id
  53. commit2.parents = [commit.id]
  54. commit2.author = commit.author
  55. commit2.committer = commit.committer
  56. commit2.commit_time = fdp.ConsumeRandomInt()
  57. commit2.commit_timezone = fdp.ConsumeRandomInt()
  58. commit2.author_time = fdp.ConsumeRandomInt()
  59. commit2.author_timezone = fdp.ConsumeRandomInt()
  60. commit2.message = fdp.ConsumeRandomBytes()
  61. try:
  62. blob.data = fdp.ConsumeRandomBytes()
  63. repo.object_store.add_object(blob)
  64. repo.object_store.add_object(tree)
  65. repo.object_store.add_object(commit2)
  66. out = BytesIO()
  67. write_tree_diff(out, repo.object_store, commit.tree, tree.id)
  68. except (InvalidUserIdentity, ObjectFormatException):
  69. return -1
  70. except ValueError as e:
  71. expected_exceptions = [
  72. "Unable to handle non-minute offset",
  73. ]
  74. if is_expected_exception(expected_exceptions, e):
  75. return -1
  76. else:
  77. raise e
  78. def main() -> None:
  79. atheris.Setup(sys.argv, TestOneInput)
  80. atheris.Fuzz()
  81. if __name__ == "__main__":
  82. main()