Skip to content
This repository was archived by the owner on Nov 26, 2020. It is now read-only.

Commit 941bae1

Browse files
committed
Fix MozillaSecurity#169 by adapting its fixes and review suggestions to master.
1 parent cbff6f5 commit 941bae1

File tree

4 files changed

+80
-64
lines changed

4 files changed

+80
-64
lines changed

src/funfuzz/js/compare_jit.py

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -61,38 +61,40 @@ def ignore_some_stderr(err_inp):
6161
return lines
6262

6363

64-
def compare_jit(jsEngine, # pylint: disable=invalid-name,missing-param-doc,missing-type-doc,too-many-arguments
64+
def compare_jit(js_engine, # pylint: disable=invalid-name,missing-param-doc,missing-type-doc,too-many-arguments
6565
flags, infilename, logPrefix, repo, build_options_str, targetTime, options):
6666
"""For use in loop.py
6767
6868
Returns:
6969
bool: True if any kind of bug is found, otherwise False
7070
"""
7171
# pylint: disable=too-many-locals
72+
js_engine = Path(js_engine)
73+
infilename = Path(infilename)
7274
# If Lithium uses this as an interestingness test, logPrefix is likely not a Path object, so make it one.
7375
logPrefix = Path(logPrefix)
7476
initialdir_name = (logPrefix.parent / (logPrefix.stem + "-initial"))
75-
# pylint: disable=invalid-name
76-
cl = compareLevel(jsEngine, flags, infilename, initialdir_name, options, False, True)
77+
cl = compareLevel(js_engine, # pylint: disable=invalid-name
78+
flags, infilename, initialdir_name, options, False, True)
7779
lev = cl[0]
7880

7981
if lev != js_interesting.JS_FINE:
8082
itest = [__name__, "--flags=" + " ".join(flags),
81-
"--minlevel=" + str(lev), "--timeout=" + str(options.timeout), options.knownPath]
83+
"--minlevel=" + str(lev), "--timeout=" + str(options.timeout)]
8284
(lithResult, _lithDetails, autoBisectLog) = lithium_helpers.pinpoint( # pylint: disable=invalid-name
83-
itest, logPrefix, jsEngine, [], infilename, repo, build_options_str, targetTime, lev)
85+
itest, logPrefix, js_engine, [], infilename, repo, build_options_str, targetTime, lev)
8486
if lithResult == lithium_helpers.LITH_FINISHED:
85-
print("Retesting %s after running Lithium:" % infilename)
87+
print("Retesting %s after running Lithium:" % str(infilename))
8688
finaldir_name = (logPrefix.parent / (logPrefix.stem + "-final"))
87-
retest_cl = compareLevel(jsEngine, flags, infilename, finaldir_name, options, True, False)
89+
retest_cl = compareLevel(js_engine, flags, infilename, finaldir_name, options, True, False)
8890
if retest_cl[0] != js_interesting.JS_FINE:
89-
cl = retest_cl
91+
cl = retest_cl # pylint: disable=invalid-name
9092
quality = 0
9193
else:
9294
quality = 6
9395
else:
9496
quality = 10
95-
print("compare_jit: Uploading %s with quality %s" % (infilename, quality))
97+
print("compare_jit: Uploading %s with quality %s" % (str(infilename), quality))
9698

9799
metadata = {}
98100
if autoBisectLog:
@@ -103,17 +105,19 @@ def compare_jit(jsEngine, # pylint: disable=invalid-name,missing-param-doc,miss
103105
return False
104106

105107

106-
def compareLevel(jsEngine, flags, infilename, logPrefix, options, showDetailedDiffs, quickMode):
107-
# pylint: disable=invalid-name,missing-docstring,missing-return-doc,missing-return-type-doc,too-complex
108-
# pylint: disable=too-many-branches,too-many-arguments,too-many-locals
108+
def compareLevel(js_engine, # pylint: disable=invalid-name,missing-docstring,missing-return-doc,missing-return-type-doc
109+
flags, infilename, logPrefix, options, showDetailedDiffs, quickMode):
110+
# pylint: disable=too-complex,too-many-branches,too-many-arguments,too-many-locals
109111

110112
# options dict must be one we can pass to js_interesting.ShellResult
111-
# we also use it directly for knownPath, timeout, and collector
113+
# we also use it directly for timeout, and collector
112114
# Return: (lev, crashInfo) or (js_interesting.JS_FINE, None)
113115

114-
assert isinstance(infilename, Path)
116+
js_engine = Path(js_engine)
117+
infilename = Path(infilename)
118+
logPrefix = Path(logPrefix)
115119

116-
combos = shell_flags.basic_flag_sets(jsEngine)
120+
combos = shell_flags.basic_flag_sets(str(js_engine))
117121

118122
if quickMode:
119123
# Only used during initial fuzzing. Allowed to have false negatives.
@@ -122,7 +126,7 @@ def compareLevel(jsEngine, flags, infilename, logPrefix, options, showDetailedDi
122126
if flags:
123127
combos.insert(0, flags)
124128

125-
commands = [[jsEngine] + combo + [str(infilename)] for combo in combos]
129+
commands = [[str(js_engine)] + combo + [str(infilename)] for combo in combos]
126130

127131
for i, command in enumerate(commands):
128132
prefix = (logPrefix.parent / ("%s-r%s" % (logPrefix.stem, str(i))))
@@ -192,8 +196,7 @@ def optionDisabledAsmOnOneSide(): # pylint: disable=invalid-name,missing-docstr
192196
rerunCommand = " ".join(quote(str(x)) for x in ["python -m funfuzz.js.compare_jit",
193197
"--flags=" + " ".join(flags),
194198
"--timeout=" + str(options.timeout),
195-
str(options.knownPath),
196-
str(jsEngine),
199+
str(js_engine),
197200
str(infilename.name)])
198201
(summary, issues) = summarizeMismatch(mismatchErr, mismatchOut, prefix0, prefix)
199202
summary = (" " + " ".join(quote(str(x)) for x in commands[0]) + "\n " +
@@ -209,7 +212,7 @@ def optionDisabledAsmOnOneSide(): # pylint: disable=invalid-name,missing-docstr
209212
print(summary)
210213
print()
211214
# Create a crashInfo object with empty stdout, and stderr showing diffs
212-
pc = ProgramConfiguration.fromBinary(str(jsEngine)) # pylint: disable=invalid-name
215+
pc = ProgramConfiguration.fromBinary(str(js_engine)) # pylint: disable=invalid-name
213216
pc.addProgramArguments(flags)
214217
crashInfo = CrashInfo.CrashInfo.fromRawCrashData([], summary, pc) # pylint: disable=invalid-name
215218
return (js_interesting.JS_OVERALL_MISMATCH, crashInfo)
@@ -281,11 +284,10 @@ def parseOptions(args): # pylint: disable=invalid-name
281284
default="",
282285
help="space-separated list of one set of flags")
283286
options, args = parser.parse_args(args)
284-
if len(args) != 3:
285-
raise Exception("Wrong number of positional arguments. Need 3 (knownPath, jsengine, infilename).")
286-
options.knownPath = Path(args[0]).expanduser().resolve()
287-
options.jsengine = Path(args[1]).expanduser().resolve()
288-
options.infilename = Path(args[2]).expanduser().resolve()
287+
if len(args) != 2:
288+
raise Exception("Wrong number of positional arguments. Need 2 (jsengine, infilename).")
289+
options.jsengine = Path(args[0]).expanduser().resolve()
290+
options.infilename = Path(args[1]).expanduser().resolve()
289291
options.flags = options.flagsSpaceSep.split(" ") if options.flagsSpaceSep else []
290292
if not options.jsengine.is_file():
291293
raise OSError("js shell does not exist: %s" % options.jsengine)
@@ -298,24 +300,37 @@ def parseOptions(args): # pylint: disable=invalid-name
298300
return options
299301

300302

301-
# For use by Lithium and autobisectjs. (autobisectjs calls init multiple times because it changes the js engine name)
302-
def init(args):
303-
global gOptions # pylint: disable=invalid-name,global-statement
304-
gOptions = parseOptions(args)
303+
class Interesting(object):
304+
305+
def __init__(self, interestingness_script=False):
306+
if interestingness_script:
307+
global init, interesting # pylint: disable=global-variable-undefined
308+
init = self.init
309+
interesting = self.interesting
310+
311+
self.args = None
312+
self.real_level = None
313+
314+
# For use by Lithium and autobisectjs.
315+
# (autobisectjs calls init multiple times because it changes the js engine name)
316+
def init(self, args):
317+
self.args = parseOptions(args)
318+
319+
def interesting(self, _args, cwd_prefix): # pylint: disable=missing-docstring,missing-return-doc
320+
# pylint: disable=missing-return-type-doc
321+
self.real_level = compareLevel(
322+
Path(self.args.jsengine), self.args.flags, Path(self.args.infilename),
323+
Path(cwd_prefix), self.args, False, False)[0]
324+
return self.real_level >= self.args.minimumInterestingLevel
305325

306326

307-
# FIXME: _args is unused here, we should check if it can be removed? # pylint: disable=fixme
308-
def interesting(_args, cwd_prefix):
309-
cwd_prefix = Path(cwd_prefix) # Lithium uses this function and cwd_prefix from Lithium is not a Path
310-
actualLevel = compareLevel( # pylint: disable=invalid-name
311-
gOptions.jsengine, gOptions.flags, gOptions.infilename, cwd_prefix, gOptions, False, False)[0]
312-
return actualLevel >= gOptions.minimumInterestingLevel
327+
Interesting(interestingness_script=True)
313328

314329

315330
def main():
316331
options = parseOptions(sys.argv[1:])
317332
print(compareLevel(
318-
options.jsengine, options.flags, options.infilename, # pylint: disable=no-member
333+
Path(options.jsengine), options.flags, Path(options.infilename), # pylint: disable=no-member
319334
Path(tempfile.mkdtemp("compare_jitmain")), options, True, False)[0])
320335

321336

src/funfuzz/js/js_interesting.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666

6767
class ShellResult(object): # pylint: disable=missing-docstring,too-many-instance-attributes,too-few-public-methods
6868

69-
# options dict should include: timeout, knownPath, collector, valgrind, shellIsDeterministic
69+
# options dict should include: timeout, collector, valgrind, shellIsDeterministic
7070
def __init__(self, options, runthis, logPrefix, in_compare_jit, env=None): # pylint: disable=too-complex
7171
# pylint: disable=too-many-arguments,too-many-branches,too-many-locals,too-many-statements
7272

@@ -328,8 +328,7 @@ def parseOptions(args): # pylint: disable=invalid-name,missing-docstring,missin
328328
options, args = parser.parse_args(args)
329329
if len(args) < 2:
330330
raise Exception("Not enough positional arguments")
331-
options.knownPath = args[0]
332-
options.jsengineWithArgs = [Path(args[1]).resolve()] + args[2:-1] + [Path(args[-1]).resolve()]
331+
options.jsengineWithArgs = [Path(args[0]).resolve()] + args[1:-1] + [Path(args[-1]).resolve()]
333332
assert options.jsengineWithArgs[0].is_file() # js shell
334333
assert options.jsengineWithArgs[-1].is_file() # testcase
335334
options.collector = create_collector.make_collector()
@@ -342,24 +341,30 @@ def parseOptions(args): # pylint: disable=invalid-name,missing-docstring,missin
342341
# loop uses parseOptions and ShellResult [with in_compare_jit = False]
343342
# compare_jit uses ShellResult [with in_compare_jit = True]
344343

345-
# For use by Lithium and autobisectjs. (autobisectjs calls init multiple times because it changes the js engine name)
346-
def init(args): # pylint: disable=missing-docstring
347-
global gOptions # pylint: disable=global-statement,invalid-name
348-
gOptions = parseOptions(args)
344+
class Interesting(object): # pylint: disable=missing-docstring
349345

346+
def __init__(self, interestingness_script=False):
347+
if interestingness_script:
348+
global init, interesting # pylint: disable=global-variable-undefined,invalid-name
349+
init = self.init
350+
interesting = self.interesting
350351

351-
# FIXME: _args is unused here, we should check if it can be removed? # pylint: disable=fixme
352-
def interesting(_args, cwd_prefix): # pylint: disable=missing-docstring,missing-return-doc
353-
# pylint: disable=missing-return-type-doc
354-
cwd_prefix = Path(cwd_prefix) # Lithium uses this function and cwd_prefix from Lithium is not a Path
355-
options = gOptions
356-
# options, runthis, logPrefix, in_compare_jit
357-
res = ShellResult(options, options.jsengineWithArgs, cwd_prefix, False)
358-
out_log = (cwd_prefix.parent / (cwd_prefix.stem + "-out")).with_suffix(".txt")
359-
err_log = (cwd_prefix.parent / (cwd_prefix.stem + "-err")).with_suffix(".txt")
360-
truncateFile(out_log, 1000000)
361-
truncateFile(err_log, 1000000)
362-
return res.lev >= gOptions.minimumInterestingLevel
352+
self.args = None
353+
354+
def init(self, args): # pylint: disable=missing-docstring
355+
self.args = parseOptions(args)
356+
357+
def interesting(self, _args, cwd_prefix): # pylint: disable=missing-docstring,missing-return-doc
358+
# pylint: disable=missing-return-type-doc
359+
cwd_prefix = Path(cwd_prefix) # Lithium uses this function, and cwd_prefix from Lithium is not a Path
360+
# options, runthis, logPrefix, in_compare_jit
361+
res = ShellResult(self.args, self.args.jsengineWithArgs, cwd_prefix, False)
362+
truncateFile((cwd_prefix.parent / (cwd_prefix.stem + "-out")).with_suffix(".txt"), 1000000)
363+
truncateFile((cwd_prefix.parent / (cwd_prefix.stem + "-err")).with_suffix(".txt"), 1000000)
364+
return res.lev >= self.args.minimumInterestingLevel
365+
366+
367+
Interesting(interestingness_script=True)
363368

364369

365370
# For direct, manual use

src/funfuzz/js/loop.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,8 @@ def parseOpts(args): # pylint: disable=invalid-name,missing-docstring,missing-r
7575
# lower = less time wasted in timeouts and in compare_jit testcases that are thrown away due to OOMs.
7676
options.timeout = int(args[0])
7777

78-
# FIXME: We can probably remove args[1] # pylint: disable=fixme
79-
options.knownPath = "mozilla-central"
80-
options.jsEngine = Path(args[2])
81-
options.engineFlags = args[3:]
78+
options.js_engine = Path(args[1])
79+
options.engineFlags = args[2:]
8280

8381
return options
8482

@@ -154,7 +152,6 @@ def many_timed_runs(targetTime, wtmpDir, args, collector, ccoverage): # pylint:
154152
js_interesting_args.append("--timeout=" + str(options.timeout))
155153
if options.valgrind:
156154
js_interesting_args.append("--valgrind")
157-
js_interesting_args.append(str(options.knownPath))
158155
js_interesting_args.append(str(options.jsEngine))
159156
if options.randomFlags:
160157
engineFlags = shell_flags.random_flag_set(options.jsEngine) # pylint: disable=invalid-name
@@ -204,7 +201,6 @@ def many_timed_runs(targetTime, wtmpDir, args, collector, ccoverage): # pylint:
204201
itest.append("--valgrind")
205202
itest.append("--minlevel=" + str(res.lev))
206203
itest.append("--timeout=" + str(options.timeout))
207-
itest.append(options.knownPath)
208204
(lithResult, _lithDetails, autoBisectLog) = lithium_helpers.pinpoint( # pylint: disable=invalid-name
209205
itest, logPrefix, options.jsEngine, engineFlags, reduced_log, options.repo,
210206
options.build_options_str, targetTime, res.lev)

src/funfuzz/util/lithium_helpers.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,16 @@
4040
LITH_FINISHED, LITH_RETESTED_STILL_INTERESTING, LITH_PLEASE_CONTINUE, LITH_BUSTED) = range(8)
4141

4242

43-
def pinpoint(itest, logPrefix, jsEngine, engineFlags, infilename, # pylint: disable=invalid-name,missing-param-doc
43+
def pinpoint(itest, logPrefix, js_engine, engineFlags, infilename, # pylint: disable=invalid-name,missing-param-doc
4444
bisectRepo, build_options_str, targetTime, suspiciousLevel):
4545
# pylint: disable=missing-return-doc,missing-return-type-doc,missing-type-doc,too-many-arguments,too-many-locals
4646
"""Run Lithium and autobisectjs.
4747
4848
itest must be an array of the form [module, ...] where module is an interestingness module.
49-
The module's "interesting" function must accept [...] + [jsEngine] + engineFlags + infilename
49+
The module's "interesting" function must accept [...] + [js_engine] + engineFlags + infilename
5050
(If it's not prepared to accept engineFlags, engineFlags must be empty.)
5151
"""
52-
lithArgs = itest + [str(jsEngine)] + engineFlags + [str(infilename)] # pylint: disable=invalid-name
52+
lithArgs = itest + [str(js_engine)] + engineFlags + [str(infilename)] # pylint: disable=invalid-name
5353

5454
(lithResult, lithDetails) = reduction_strat( # pylint: disable=invalid-name
5555
logPrefix, infilename, lithArgs, targetTime, suspiciousLevel)
@@ -61,7 +61,7 @@ def pinpoint(itest, logPrefix, jsEngine, engineFlags, infilename, # pylint: dis
6161

6262
# pylint: disable=literal-comparison
6363
if (bisectRepo is not "none" and targetTime >= 3 * 60 * 60 and
64-
build_options_str is not None and testJsShellOrXpcshell(jsEngine) != "xpcshell"):
64+
build_options_str is not None and testJsShellOrXpcshell(js_engine) != "xpcshell"):
6565
autobisectCmd = ( # pylint: disable=invalid-name
6666
[sys.executable, "-u", "-m", "funfuzz.autobisectjs"] +
6767
["-b", build_options_str] +

0 commit comments

Comments
 (0)