fuzz_object_store.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  2. import stat
  3. import sys
  4. from io import BytesIO
  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) -> int | None:
  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()