Home | History | Annotate | Download | only in fuzzing
      1 #!/usr/bin/env python
      2 
      3 from __future__ import print_function, division, absolute_import
      4 
      5 import sys, os, subprocess, tempfile, threading
      6 
      7 
      8 def which(program):
      9 	# https://stackoverflow.com/a/377028
     10 	def is_exe(fpath):
     11 		return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
     12 
     13 	fpath, _ = os.path.split(program)
     14 	if fpath:
     15 		if is_exe(program):
     16 			return program
     17 	else:
     18 		for path in os.environ["PATH"].split(os.pathsep):
     19 			exe_file = os.path.join(path, program)
     20 			if is_exe(exe_file):
     21 				return exe_file
     22 
     23 	return None
     24 
     25 
     26 def cmd(command):
     27 	# https://stackoverflow.com/a/4408409
     28 	# https://stackoverflow.com/a/10012262
     29 	with tempfile.TemporaryFile() as tempf:
     30 		p = subprocess.Popen (command, stderr=tempf)
     31 		is_killed = {'value': False}
     32 
     33 		def timeout(p, is_killed):
     34 			is_killed['value'] = True
     35 			p.kill()
     36 		timer = threading.Timer (2, timeout, [p, is_killed])
     37 
     38 		try:
     39 			timer.start()
     40 			p.wait ()
     41 			tempf.seek (0)
     42 			text = tempf.read().decode ("utf-8").strip ()
     43 			returncode = p.returncode
     44 		finally:
     45 			timer.cancel()
     46 
     47 		if is_killed['value']:
     48 			text = 'error: timeout, ' + text
     49 			returncode = 1
     50 
     51 		return text, returncode
     52 
     53 
     54 srcdir = os.environ.get ("srcdir", ".")
     55 EXEEXT = os.environ.get ("EXEEXT", "")
     56 top_builddir = os.environ.get ("top_builddir", ".")
     57 hb_shape_fuzzer = os.path.join (top_builddir, "hb-shape-fuzzer" + EXEEXT)
     58 
     59 if not os.path.exists (hb_shape_fuzzer):
     60 	if len (sys.argv) == 1 or not os.path.exists (sys.argv[1]):
     61 		print ("""Failed to find hb-shape-fuzzer binary automatically,
     62 please provide it as the first argument to the tool""")
     63 		sys.exit (1)
     64 
     65 	hb_shape_fuzzer = sys.argv[1]
     66 
     67 print ('hb_shape_fuzzer:', hb_shape_fuzzer)
     68 fails = 0
     69 
     70 valgrind = None
     71 if os.environ.get('RUN_VALGRIND', ''):
     72 	valgrind = which ('valgrind')
     73 
     74 parent_path = os.path.join (srcdir, "fonts")
     75 for file in os.listdir (parent_path):
     76 	path = os.path.join(parent_path, file)
     77 
     78 	text, returncode = cmd ([hb_shape_fuzzer, path])
     79 	if text.strip ():
     80 		print (text)
     81 
     82 	failed = False
     83 	if returncode != 0 or 'error' in text:
     84 		print ('failure on %s' % file)
     85 		failed = True
     86 
     87 	if valgrind:
     88 		text, returncode = cmd ([valgrind, '--error-exitcode=1', hb_shape_fuzzer, path])
     89 		if returncode:
     90 			print (text)
     91 			print ('failure on %s' % file)
     92 			failed = True
     93 
     94 	if failed:
     95 		fails = fails + 1
     96 
     97 if fails:
     98 	print ("%i shape fuzzer related tests failed." % fails)
     99 	sys.exit (1)
    100