Coverage for /pythoncovmergedfiles/medio/medio/src/hypothesis_structured_fuzzer.py: 17%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

24 statements  

1###### Coverage stub 

2import atexit 

3import coverage 

4cov = coverage.coverage(data_file='.coverage', cover_pylib=True) 

5cov.start() 

6# Register an exist handler that will print coverage 

7def exit_handler(): 

8 cov.stop() 

9 cov.save() 

10atexit.register(exit_handler) 

11####### End of coverage stub 

12#!/usr/bin/python3 

13 

14# Copyright 2021 Zac Hatfield-Dodds 

15# 

16# Licensed under the Apache License, Version 2.0 (the "License"); 

17# you may not use this file except in compliance with the License. 

18# You may obtain a copy of the License at 

19# 

20# http://www.apache.org/licenses/LICENSE-2.0 

21# 

22# Unless required by applicable law or agreed to in writing, software 

23# distributed under the License is distributed on an "AS IS" BASIS, 

24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

25# See the License for the specific language governing permissions and 

26# limitations under the License. 

27 

28"""This fuzzer is an example harness using Hypothesis for structured inputs. 

29 

30It would be possible, though more difficult, to write this test in terms 

31of Atheris' `FuzzedDataProvider` instead of Hypothesis strategies. 

32 

33As well as defining structured inputs however, the call to 

34`test_ujson_roundtrip()` will replay, deduplicate, and minimize any known 

35failing examples from previous runs - which is great when debugging. 

36Hypothesis uses a separate cache to Atheris/LibFuzzer seeds, so this is 

37strictly complementary to your traditional fuzzing workflow. 

38 

39For more details on Hypothesis, see: 

40https://hypothesis.readthedocs.io/en/latest/data.html 

41https://hypothesis.readthedocs.io/en/latest/details.html#use-with-external-fuzzers 

42""" 

43 

44import sys 

45import atheris 

46import ujson 

47from hypothesis import given, strategies as st 

48 

49# We could define all these inline within the call to @given(), 

50# but it's a bit easier to read if we name them here instead. 

51JSON_ATOMS = st.one_of( 

52 st.none(), 

53 st.booleans(), 

54 st.integers(min_value=-(2 ** 63), max_value=2 ** 63 - 1), 

55 st.floats(allow_nan=False, allow_infinity=False), 

56 st.text(), 

57) 

58JSON_OBJECTS = st.recursive( 

59 base=JSON_ATOMS, 

60 extend=lambda inner: st.lists(inner) | st.dictionaries(st.text(), inner), 

61) 

62UJSON_ENCODE_KWARGS = { 

63 "ensure_ascii": st.booleans(), 

64 "encode_html_chars": st.booleans(), 

65 "escape_forward_slashes": st.booleans(), 

66 "sort_keys": st.booleans(), 

67 "indent": st.integers(0, 20), 

68} 

69 

70 

71@given(obj=JSON_OBJECTS, kwargs=st.fixed_dictionaries(UJSON_ENCODE_KWARGS)) 

72@atheris.instrument_func 

73def test_ujson_roundtrip(obj, kwargs): 

74 """Check that all JSON objects round-trip regardless of other options.""" 

75 assert obj == ujson.decode(ujson.encode(obj, **kwargs)) 

76 

77 

78if __name__ == "__main__": 

79 # Running `pytest hypothesis_structured_fuzzer.py` will replay, deduplicate, 

80 # and minimize any failures discovered by earlier runs or by OSS-Fuzz, or 

81 # briefly search for new failures if none are known. 

82 # Or, when running via OSS-Fuzz, we'll execute it via the fuzzing hook: 

83 atheris.Setup(sys.argv, atheris.instrument_func(test_ujson_roundtrip.hypothesis.fuzz_one_input)) 

84 atheris.Fuzz()