llvm-project

Форк
0
/
modfuzz.py 
193 строки · 4.4 Кб
1
#!/usr/bin/env python
2

3
# To use:
4
#  1) Update the 'decls' list below with your fuzzing configuration.
5
#  2) Run with the clang binary as the command-line argument.
6

7
from __future__ import absolute_import, division, print_function
8
import random
9
import subprocess
10
import sys
11
import os
12

13
clang = sys.argv[1]
14
none_opts = 0.3
15

16

17
class Decl(object):
18
    def __init__(self, text, depends=[], provides=[], conflicts=[]):
19
        self.text = text
20
        self.depends = depends
21
        self.provides = provides
22
        self.conflicts = conflicts
23

24
    def valid(self, model):
25
        for i in self.depends:
26
            if i not in model.decls:
27
                return False
28
        for i in self.conflicts:
29
            if i in model.decls:
30
                return False
31
        return True
32

33
    def apply(self, model, name):
34
        for i in self.provides:
35
            model.decls[i] = True
36
        model.source += self.text % {"name": name}
37

38

39
decls = [
40
    Decl("struct X { int n; };\n", provides=["X"], conflicts=["X"]),
41
    Decl('static_assert(X{.n=1}.n == 1, "");\n', depends=["X"]),
42
    Decl("X %(name)s;\n", depends=["X"]),
43
]
44

45

46
class FS(object):
47
    def __init__(self):
48
        self.fs = {}
49
        self.prevfs = {}
50

51
    def write(self, path, contents):
52
        self.fs[path] = contents
53

54
    def done(self):
55
        for f, s in self.fs.items():
56
            if self.prevfs.get(f) != s:
57
                f = file(f, "w")
58
                f.write(s)
59
                f.close()
60

61
        for f in self.prevfs:
62
            if f not in self.fs:
63
                os.remove(f)
64

65
        self.prevfs, self.fs = self.fs, {}
66

67

68
fs = FS()
69

70

71
class CodeModel(object):
72
    def __init__(self):
73
        self.source = ""
74
        self.modules = {}
75
        self.decls = {}
76
        self.i = 0
77

78
    def make_name(self):
79
        self.i += 1
80
        return "n" + str(self.i)
81

82
    def fails(self):
83
        fs.write(
84
            "module.modulemap",
85
            "".join(
86
                'module %s { header "%s.h" export * }\n' % (m, m)
87
                for m in self.modules.keys()
88
            ),
89
        )
90

91
        for m, (s, _) in self.modules.items():
92
            fs.write("%s.h" % m, s)
93

94
        fs.write("main.cc", self.source)
95
        fs.done()
96

97
        return (
98
            subprocess.call(
99
                [clang, "-std=c++11", "-c", "-fmodules", "main.cc", "-o", "/dev/null"]
100
            )
101
            != 0
102
        )
103

104

105
def generate():
106
    model = CodeModel()
107
    m = []
108

109
    try:
110
        for d in mutations(model):
111
            d(model)
112
            m.append(d)
113
        if not model.fails():
114
            return
115
    except KeyboardInterrupt:
116
        print()
117
        return True
118

119
    sys.stdout.write("\nReducing:\n")
120
    sys.stdout.flush()
121

122
    try:
123
        while True:
124
            assert m, "got a failure with no steps; broken clang binary?"
125
            i = random.choice(list(range(len(m))))
126
            x = m[0:i] + m[i + 1 :]
127
            m2 = CodeModel()
128
            for d in x:
129
                d(m2)
130
            if m2.fails():
131
                m = x
132
                model = m2
133
            else:
134
                sys.stdout.write(".")
135
                sys.stdout.flush()
136
    except KeyboardInterrupt:
137
        # FIXME: Clean out output directory first.
138
        model.fails()
139
        return model
140

141

142
def choose(options):
143
    while True:
144
        i = int(random.uniform(0, len(options) + none_opts))
145
        if i >= len(options):
146
            break
147
        yield options[i]
148

149

150
def mutations(model):
151
    options = [create_module, add_top_level_decl]
152
    for opt in choose(options):
153
        yield opt(model, options)
154

155

156
def create_module(model, options):
157
    n = model.make_name()
158

159
    def go(model):
160
        model.modules[n] = (model.source, model.decls)
161
        (model.source, model.decls) = ("", {})
162

163
    options += [lambda model, options: add_import(model, options, n)]
164
    return go
165

166

167
def add_top_level_decl(model, options):
168
    n = model.make_name()
169
    d = random.choice([decl for decl in decls if decl.valid(model)])
170

171
    def go(model):
172
        if not d.valid(model):
173
            return
174
        d.apply(model, n)
175

176
    return go
177

178

179
def add_import(model, options, module_name):
180
    def go(model):
181
        if module_name in model.modules:
182
            model.source += '#include "%s.h"\n' % module_name
183
            model.decls.update(model.modules[module_name][1])
184

185
    return go
186

187

188
sys.stdout.write("Finding bug: ")
189
while True:
190
    if generate():
191
        break
192
    sys.stdout.write(".")
193
    sys.stdout.flush()
194

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.