From 30e06b367932f6c39eb054312e7c978227950b4a Mon Sep 17 00:00:00 2001 From: ianshefferman Date: Tue, 13 Oct 2015 10:48:43 -0400 Subject: [PATCH 1/2] Wrap JSContext() with JSLocker() lock Make PyV8.JSContext thread safe by wrapping it in a lock. Multithreaded programs that call peepdf may cause peepdf analyses to mysteriously segfault without this. This is an issue with PyV8 in general. Examples of other people having similar issues with PyV8 in multithreaded applications: http://inarticulateloquence.com/django-pyv8/ http://www.pythoneye.com/440_11816513/ Copied from my earlier defunct PR at https://github.com/viper-framework/viper/pull/130. --- JSAnalysis.py | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/JSAnalysis.py b/JSAnalysis.py index 53c8fab..2830b5c 100644 --- a/JSAnalysis.py +++ b/JSAnalysis.py @@ -76,28 +76,29 @@ def analyseJS(code, context = None, manualAnalysis = False): JSCode.append(code) if code != None and JS_MODULE and not manualAnalysis: - if context == None: - context = PyV8.JSContext(Global()) - context.enter() - # Hooking the eval function - context.eval('eval=evalOverride') - #context.eval(preDefinedCode) - while True: - originalCode = code - try: - context.eval(code) - evalCode = context.eval('evalCode') - evalCode = jsbeautifier.beautify(evalCode) - if evalCode != '' and evalCode != code: - code = evalCode - JSCode.append(code) - else: + with PyV8.JSLocker(): + if context == None: + context = PyV8.JSContext(Global()) + context.enter() + # Hooking the eval function + context.eval('eval=evalOverride') + #context.eval(preDefinedCode) + while True: + originalCode = code + try: + context.eval(code) + evalCode = context.eval('evalCode') + evalCode = jsbeautifier.beautify(evalCode) + if evalCode != '' and evalCode != code: + code = evalCode + JSCode.append(code) + else: + break + except: + error = str(sys.exc_info()[1]) + open('jserror.log','ab').write(error + newLine) + errors.append(error) break - except: - error = str(sys.exc_info()[1]) - open('jserror.log','ab').write(error + newLine) - errors.append(error) - break if code != '': escapedVars = re.findall('(\w*?)\s*?=\s*?(unescape\((.*?)\))', code, re.DOTALL) @@ -259,4 +260,4 @@ def unescape(escapedBytes, unicode = True): unescapedBytes = escapedBytes except: return (-1,'Error while unescaping the bytes') - return (0,unescapedBytes) \ No newline at end of file + return (0,unescapedBytes) From 25b2c423d8810661d2b7d88724cb35e42afd0fea Mon Sep 17 00:00:00 2001 From: ianshefferman Date: Mon, 2 Nov 2015 15:27:56 -0500 Subject: [PATCH 2/2] Exit context before releasing lock --- JSAnalysis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/JSAnalysis.py b/JSAnalysis.py index 2830b5c..98ead3c 100644 --- a/JSAnalysis.py +++ b/JSAnalysis.py @@ -99,6 +99,7 @@ def analyseJS(code, context = None, manualAnalysis = False): open('jserror.log','ab').write(error + newLine) errors.append(error) break + context.leave() if code != '': escapedVars = re.findall('(\w*?)\s*?=\s*?(unescape\((.*?)\))', code, re.DOTALL)