Coverage for /pythoncovmergedfiles/medio/medio/src/textdistance/fuzzing/textdistance_fuzzer.py: 57%

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

68 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 

12import itertools 

13import sys 

14from collections import defaultdict 

15from typing import List, Dict, Type 

16 

17import atheris 

18 

19from fuzz_helpers import EnhancedFuzzedDataProvider 

20from dataclasses import dataclass, field 

21 

22with atheris.instrument_imports(): 

23 import textdistance 

24 

25 

26@dataclass 

27class InitializationConstraints: 

28 """ 

29 Tracks if a given class has the qval and external construction parameters 

30 """ 

31 HAS_QVAL: bool = field(default=True) 

32 HAS_EXTERNAL: bool = field(default=True) 

33 

34 

35@dataclass 

36class FuzzTarget: 

37 """ 

38 Defines a class and method that is a possible fuzz candidate 

39 """ 

40 algo_cls: type 

41 fuzz_func_name: str 

42 

43 

44ALGORITHMS = [textdistance.Hamming, textdistance.Bag, textdistance.Gotoh, textdistance.MLIPNS, textdistance.Levenshtein, 

45 textdistance.DamerauLevenshtein, textdistance.Jaro, textdistance.JaroWinkler, textdistance.StrCmp95, 

46 textdistance.NeedlemanWunsch, 

47 textdistance.SmithWaterman, textdistance.Jaccard, textdistance.Sorensen, 

48 textdistance.Tversky, textdistance.Overlap, textdistance.Cosine, textdistance.Tanimoto, 

49 textdistance.MongeElkan, 

50 textdistance.LCSSeq, textdistance.LCSStr, textdistance.RatcliffObershelp, textdistance.ArithNCD, 

51 textdistance.RLENCD, 

52 textdistance.BWTRLENCD, textdistance.SqrtNCD, textdistance.BZ2NCD, textdistance.LZMANCD, 

53 textdistance.ZLIBNCD, textdistance.MRA, textdistance.Editex, textdistance.Prefix, textdistance.Length, 

54 textdistance.Identity, 

55 textdistance.Matrix] 

56 

57FUZZ_METHODS = ["__call__", "distance", "similarity", "normalized_distance", "normalized_similarity"] 

58 

59FUZZ_TARGETS: List[FuzzTarget] = [] 

60 

61CONSTRAINT_MEMORY: Dict[Type, InitializationConstraints] = defaultdict(InitializationConstraints) 

62 

63 

64def initialize_fuzz_options(): 

65 """ 

66 Initializes a cross-product of valid fuzzing targets and methods 

67 """ 

68 global FUZZ_TARGETS 

69 

70 FUZZ_TARGETS = [FuzzTarget(algo, func) for algo, func in itertools.product(ALGORITHMS, FUZZ_METHODS) if 

71 hasattr(algo, func)] 

72 

73 

74def pick_qval(fdp: EnhancedFuzzedDataProvider): 

75 """ 

76 Let atheris pick a qval to use for this current iteration (None, 1, or 2+) 

77 """ 

78 if fdp.ConsumeBool(): 

79 return fdp.ConsumeIntInRange(1, 100) 

80 else: 

81 return None 

82 

83 

84def TestOneInput(data): 

85 fdp = EnhancedFuzzedDataProvider(data) 

86 

87 # Pick a target 

88 fuzz_target: FuzzTarget = fdp.PickValueInList(FUZZ_TARGETS) 

89 constraints = CONSTRAINT_MEMORY[fuzz_target.algo_cls] 

90 

91 try: 

92 if constraints.HAS_QVAL and constraints.HAS_EXTERNAL: 

93 algo = fuzz_target.algo_cls(qval=pick_qval(fdp), external=False) 

94 elif constraints.HAS_QVAL: 

95 algo = fuzz_target.algo_cls(qval=pick_qval(fdp)) 

96 elif constraints.HAS_EXTERNAL: 

97 algo = fuzz_target.algo_cls(external=False) 

98 else: 

99 algo = fuzz_target.algo_cls() 

100 except TypeError as e: 

101 # Update our memory on if a given parameter is invalid 

102 if 'qval' in str(e): 

103 constraints.HAS_QVAL = False 

104 elif 'external' in str(e): 

105 constraints.HAS_EXTERNAL = False 

106 return -1 

107 

108 try: 

109 getattr(algo, fuzz_target.fuzz_func_name)(fdp.ConsumeRandomString(), fdp.ConsumeRandomString()) 

110 except AttributeError as e: 

111 # Pops too often, just catch and ignore 

112 if 'split' in str(e): 

113 return -1 

114 except ImportError: 

115 # Remove this algorithm from the list, since we don't have pre-reqs to use it 

116 FUZZ_TARGETS.remove(fuzz_target) 

117 return -1 

118 

119 

120def main(): 

121 initialize_fuzz_options() 

122 atheris.Setup(sys.argv, TestOneInput) 

123 atheris.Fuzz() 

124 

125 

126if __name__ == "__main__": 

127 main()