0

android: fix deobfuscator closing + add infinite loop test case.

Bug: 876539
Change-Id: Ib28bf55e7213789186b8180904f7317cb5c0d8ce
Reviewed-on: https://chromium-review.googlesource.com/1186542
Commit-Queue: John Budorick <jbudorick@chromium.org>
Reviewed-by: agrieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585843}
This commit is contained in:
John Budorick
2018-08-24 15:18:57 +00:00
committed by Commit Bot
parent 3ac3c0d87b
commit 32813a502d
2 changed files with 75 additions and 35 deletions
build/android

@ -25,6 +25,8 @@ class Deobfuscator(object):
cmd = [script_path, mapping_path]
# Allow only one thread to call TransformLines() at a time.
self._lock = threading.Lock()
# Ensure that only one thread attempts to kill self._proc in Close().
self._close_lock = threading.Lock()
self._closed_called = False
# Assign to None so that attribute exists if Popen() throws.
self._proc = None
@ -114,8 +116,11 @@ class Deobfuscator(object):
return lines
def Close(self):
self._closed_called = True
if not self.IsClosed():
with self._close_lock:
needs_closing = not self.IsClosed()
self._closed_called = True
if needs_closing:
self._proc.stdin.close()
self._proc.kill()
self._proc.wait()

@ -6,10 +6,14 @@
"""Tests for java_deobfuscate."""
import argparse
import os
import subprocess
import sys
import tempfile
import unittest
# Set by command-line argument.
_JAVA_DEOBFUSCATE_PATH = None
LINE_PREFIXES = [
'',
@ -59,44 +63,75 @@ this.was.Deobfuscated: Error message
""".splitlines(True)
def _RunTest(bin_path, map_file, prefix):
cmd = [bin_path, map_file]
payload = TEST_DATA
expected_output = EXPECTED_OUTPUT
class JavaDeobfuscateTest(unittest.TestCase):
payload = [prefix + x for x in payload]
expected_output = [prefix + x for x in expected_output]
def __init__(self, *args, **kwargs):
super(JavaDeobfuscateTest, self).__init__(*args, **kwargs)
self._map_file = None
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
actual_output = proc.communicate(''.join(payload))[0].splitlines(True)
any_unexpected_failures = False
for actual, expected in zip(actual_output, expected_output):
if actual == expected:
sys.stdout.write('Good: ' + actual)
elif actual.replace('bar', 'someMethod') == expected:
# TODO(agrieve): Fix ReTrace's ability to deobfuscated methods.
sys.stdout.write('Fine: ' + actual)
else:
sys.stdout.write('BAD: ' + actual)
any_unexpected_failures = True
return not any_unexpected_failures
def setUp(self):
self._map_file = tempfile.NamedTemporaryFile()
self._map_file.write(TEST_MAP)
self._map_file.flush()
def tearDown(self):
if self._map_file:
self._map_file.close()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('path_to_java_deobfuscate')
args = parser.parse_args()
def _testImpl(self, input_lines=None, expected_output_lines=None,
prefix=''):
self.assertTrue(bool(input_lines) == bool(expected_output_lines))
with tempfile.NamedTemporaryFile() as map_file:
map_file.write(TEST_MAP)
map_file.flush()
passed = True
for prefix in LINE_PREFIXES:
if not _RunTest(args.path_to_java_deobfuscate, map_file.name, prefix):
passed = False
print 'Result:', 'PASS' if passed else 'FAIL'
sys.exit(int(not passed))
if not input_lines:
input_lines = [prefix + x for x in TEST_DATA]
if not expected_output_lines:
expected_output_lines = [prefix + x for x in EXPECTED_OUTPUT]
cmd = [_JAVA_DEOBFUSCATE_PATH, self._map_file.name]
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
proc_output, _ = proc.communicate(''.join(input_lines))
actual_output_lines = proc_output.splitlines(True)
for actual, expected in zip(actual_output_lines, expected_output_lines):
self.assertTrue(
actual == expected or actual.replace('bar', 'someMethod') == expected,
msg=''.join([
'Deobfuscation failed.\n',
' actual: %s' % actual,
' expected: %s' % expected]))
def testNoPrefix(self):
self._testImpl(prefix='')
def testThreadtimePrefix(self):
self._testImpl(prefix='09-08 14:38:35.535 18029 18084 E qcom_sensors_hal: ')
def testStandardPrefix(self):
self._testImpl(prefix='W/GCM (15158): ')
def testStandardPrefixWithPadding(self):
self._testImpl(prefix='W/GCM ( 158): ')
@unittest.skip('causes java_deobfuscate to hang, see crbug.com/876539')
def testIndefiniteHang(self):
# Test for crbug.com/876539.
self._testImpl(
input_lines=[
'VFY: unable to resolve virtual method 2: LFOO;'
+ '.onDescendantInvalidated '
+ '(Landroid/view/View;Landroid/view/View;)V',
],
expected_output_lines=[
'VFY: unable to resolve virtual method 2: Lthis.was.Deobfuscated;'
+ '.onDescendantInvalidated '
+ '(Landroid/view/View;Landroid/view/View;)V',
])
if __name__ == '__main__':
main()
parser = argparse.ArgumentParser()
parser.add_argument('--java-deobfuscate-path', type=os.path.realpath,
required=True)
known_args, unittest_args = parser.parse_known_args()
_JAVA_DEOBFUSCATE_PATH = known_args.java_deobfuscate_path
unittest_args = [sys.argv[0]] + unittest_args
unittest.main(argv=unittest_args)