From d5ea3208ea40caaf41f5c31020419d961fe479c2 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 14:53:28 -0500 Subject: [PATCH 01/12] Rename a duplicately-named test --- tests/other/utils/test_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/other/utils/test_config.py b/tests/other/utils/test_config.py index 2412d3654..80f0269ee 100644 --- a/tests/other/utils/test_config.py +++ b/tests/other/utils/test_config.py @@ -127,7 +127,7 @@ def test_parse(self): self.assertEqual(g.var3, [1, 2, 3]) self.assertEqual(g.var4, []) - def test_parse(self): + def test_parse_badconfig(self): conf = "bad config" f = io.StringIO(conf) # this shouldn't raise From 5f7f75b735088faef610cffec8f37a71fde8dd85 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 14:54:03 -0500 Subject: [PATCH 02/12] Delete a copy-and-pasted doubled test case --- tests/native/test_state.py | 53 -------------------------------------- 1 file changed, 53 deletions(-) diff --git a/tests/native/test_state.py b/tests/native/test_state.py index 42a7b31c9..ac7df6e09 100644 --- a/tests/native/test_state.py +++ b/tests/native/test_state.py @@ -210,59 +210,6 @@ def testContextSerialization(self): new_new_state = pickle.loads(new_new_file) self.assertEqual(new_new_state.context["step"], 30) - def testContextSerialization(self): - import pickle as pickle - - initial_file = "" - new_file = "" - new_new_file = "" - constraints = ConstraintSet() - initial_state = State(constraints, FakePlatform()) - initial_state.context["step"] = 10 - initial_file = pickle_dumps(initial_state) - with initial_state as new_state: - self.assertEqual(initial_state.context["step"], 10) - self.assertEqual(new_state.context["step"], 10) - - new_state.context["step"] = 20 - - self.assertEqual(initial_state.context["step"], 10) - self.assertEqual(new_state.context["step"], 20) - new_file = pickle_dumps(new_state) - - with new_state as new_new_state: - self.assertEqual(initial_state.context["step"], 10) - self.assertEqual(new_state.context["step"], 20) - self.assertEqual(new_new_state.context["step"], 20) - - new_new_state.context["step"] += 10 - - self.assertEqual(initial_state.context["step"], 10) - self.assertEqual(new_state.context["step"], 20) - self.assertEqual(new_new_state.context["step"], 30) - - new_new_file = pickle_dumps(new_new_state) - - self.assertEqual(initial_state.context["step"], 10) - self.assertEqual(new_state.context["step"], 20) - self.assertEqual(new_new_state.context["step"], 30) - - self.assertEqual(initial_state.context["step"], 10) - self.assertEqual(new_state.context["step"], 20) - - self.assertEqual(initial_state.context["step"], 10) - - del initial_state - del new_state - del new_new_state - - initial_state = pickle.loads(initial_file) - self.assertEqual(initial_state.context["step"], 10) - new_state = pickle.loads(new_file) - self.assertEqual(new_state.context["step"], 20) - new_new_state = pickle.loads(new_new_file) - self.assertEqual(new_new_state.context["step"], 30) - class StateMergeTest(unittest.TestCase): From 7c41a8fc3c0d8cdcab3b45c221c32949df4c0d13 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 15:01:00 -0500 Subject: [PATCH 03/12] Add type annotation that mypy was asking for --- manticore/utils/log.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/manticore/utils/log.py b/manticore/utils/log.py index 5a9240f15..e1d9e9b56 100644 --- a/manticore/utils/log.py +++ b/manticore/utils/log.py @@ -1,9 +1,11 @@ import logging import sys +from typing import Set + manticore_verbosity = 0 DEFAULT_LOG_LEVEL = logging.WARNING -all_loggers = set() +all_loggers: Set[str] = set() default_factory = logging.getLogRecordFactory() logfmt = "%(asctime)s: [%(process)d] %(name)s:%(levelname)s %(message)s" handler = logging.StreamHandler(sys.stdout) From 67072da42ddbdfa983b66ddfb0a3a1b94f11e640 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 15:02:46 -0500 Subject: [PATCH 04/12] Add some type annotations to manticore.utils.log --- manticore/utils/log.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/manticore/utils/log.py b/manticore/utils/log.py index e1d9e9b56..d1e41f451 100644 --- a/manticore/utils/log.py +++ b/manticore/utils/log.py @@ -1,7 +1,7 @@ import logging import sys -from typing import Set +from typing import List, Set, Tuple manticore_verbosity = 0 DEFAULT_LOG_LEVEL = logging.WARNING @@ -18,7 +18,7 @@ class ContextFilter(logging.Filter): This is a filter which injects contextual information into the log. """ - def summarized_name(self, name): + def summarized_name(self, name: str) -> str: """ Produce a summarized record name i.e. manticore.core.executor -> m.c.executor @@ -44,7 +44,7 @@ def summarized_name(self, name): colored_levelname_format = "\x1b[{}m{}:\x1b[0m" plain_levelname_format = "{}:" - def colored_level_name(self, levelname): + def colored_level_name(self, levelname: str) -> str: """ Colors the logging level in the logging record """ @@ -53,7 +53,7 @@ def colored_level_name(self, levelname): else: return self.colored_levelname_format.format(self.color_map[levelname], levelname) - def filter(self, record): + def filter(self, record) -> bool: record.name = self.summarized_name(record.name) record.levelname = self.colored_level_name(record.levelname) return True @@ -67,7 +67,7 @@ class CustomLogger(logging.Logger): Custom Logger class that can grab the correct verbosity level from this module """ - def __init__(self, name, level=DEFAULT_LOG_LEVEL, *args): + def __init__(self, name: str, level=DEFAULT_LOG_LEVEL, *args) -> None: super().__init__(name, min(get_verbosity(name), level), *args) all_loggers.add(name) self.initialized = False @@ -81,11 +81,11 @@ def __init__(self, name, level=DEFAULT_LOG_LEVEL, *args): logging.setLoggerClass(CustomLogger) -def disable_colors(): +def disable_colors() -> None: ContextFilter.colors_disabled = True -def get_levels(): +def get_levels() -> List[List[Tuple[str, int]]]: return [ # 0 [(x, DEFAULT_LOG_LEVEL) for x in all_loggers], @@ -125,8 +125,8 @@ def get_levels(): ] -def get_verbosity(logger_name): - def match(name, pattern): +def get_verbosity(logger_name: str) -> int: + def match(name: str, pattern: str): """ Pseudo globbing that only supports full fields. 'a.*.d' matches 'a.b.d' but not 'a.b.c.d'. @@ -148,7 +148,7 @@ def match(name, pattern): return DEFAULT_LOG_LEVEL -def set_verbosity(setting): +def set_verbosity(setting: int) -> None: global manticore_verbosity manticore_verbosity = min(max(setting, 0), len(get_levels()) - 1) for logger_name in all_loggers: From 724007ec344aa75d9fdfda9fde68ef09f51ae293 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 15:13:31 -0500 Subject: [PATCH 05/12] Sort manticore.ethereum imports --- tests/ethereum/test_detectors.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ethereum/test_detectors.py b/tests/ethereum/test_detectors.py index 9e0f60b70..8f8b2c843 100644 --- a/tests/ethereum/test_detectors.py +++ b/tests/ethereum/test_detectors.py @@ -11,15 +11,15 @@ from manticore.core.smtlib import operators, ConstraintSet from manticore.ethereum import ( - ManticoreEVM, - DetectIntegerOverflow, - DetectUnusedRetVal, - DetectSuicidal, DetectDelegatecall, - DetectExternalCallAndLeak, DetectEnvInstruction, - DetectRaceCondition, + DetectExternalCallAndLeak, + DetectIntegerOverflow, DetectManipulableBalance, + DetectRaceCondition, + DetectSuicidal, + DetectUnusedRetVal, + ManticoreEVM, State, ) from manticore.ethereum.plugins import LoopDepthLimiter, KeepOnlyIfStorageChanges From 12cdb66a0a20eac4a068a2acde14b1078d4bcfe9 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 15:16:03 -0500 Subject: [PATCH 06/12] Rewrite a couple shadowed imports to appease mypy --- tests/native/test_cpu_automatic.py | 4 ++-- tests/native/test_cpu_manual.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/native/test_cpu_automatic.py b/tests/native/test_cpu_automatic.py index 804a9867e..2ac594fe1 100644 --- a/tests/native/test_cpu_automatic.py +++ b/tests/native/test_cpu_automatic.py @@ -1,9 +1,9 @@ import unittest from manticore.native.cpu.x86 import * -from manticore.core.smtlib import * +import manticore.core.smtlib from manticore.native.memory import * -solver = solver.Z3Solver.instance() +solver = manticore.core.smtlib.solver.Z3Solver.instance() class CPUTest(unittest.TestCase): diff --git a/tests/native/test_cpu_manual.py b/tests/native/test_cpu_manual.py index 0f2ac92ac..381b3660f 100644 --- a/tests/native/test_cpu_manual.py +++ b/tests/native/test_cpu_manual.py @@ -8,7 +8,7 @@ from manticore.native.memory import * from manticore.core.smtlib import BitVecOr, operator, Bool from manticore.core.smtlib.solver import Z3Solver -from .mockmem import Memory +from .mockmem import Memory as MockMemory from functools import reduce solver = Z3Solver.instance() @@ -186,7 +186,7 @@ def write(self, value): return self.value def setUp(self): - mem = Memory() + mem = MockMemory() self.cpu = I386Cpu(mem) # TODO reset cpu in between tests... # TODO mock getchar/putchar in case the instruction accesses memory directly From 0cbb230867a2f1ae11ae6ef700ed6dad03767f57 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 15:22:18 -0500 Subject: [PATCH 07/12] Fix a misspelled format string --- tests/native/test_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/native/test_memory.py b/tests/native/test_memory.py index ac1f6d3ea..c74254b83 100644 --- a/tests/native/test_memory.py +++ b/tests/native/test_memory.py @@ -1428,7 +1428,7 @@ def testmprotectFailSymbReading(self): # No Access Reading <4160741376> # self.assertRaisesRegexp(MemoryException, r"No access reading.*", mem.__getitem__, x) with self.assertRaisesRegex( - InvalidSymbolicMemoryAccess, "Invalid symbolic memory access.*".format(addr) + InvalidSymbolicMemoryAccess, f"Invalid symbolic memory access.*<{addr:x}>" ): _ = mem[x] # mem[addr] = 'a' From 57511deb08b9e1d5e781d6dc3a963d91f3f3e485 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 15:26:28 -0500 Subject: [PATCH 08/12] Delete copy-and-pasted unused variables --- tests/ethereum/test_sha3.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/ethereum/test_sha3.py b/tests/ethereum/test_sha3.py index 292f5317f..115834753 100644 --- a/tests/ethereum/test_sha3.py +++ b/tests/ethereum/test_sha3.py @@ -20,12 +20,6 @@ class EthSha3TestSymbolicate(unittest.TestCase): - """ - Subclasses must assign this class variable to the class for the detector - """ - - DETECTOR_CLASS = None - def setUp(self): evm_consts = config.get_group("evm") evm_consts.sha3 = evm_consts.sha3.symbolicate @@ -426,12 +420,6 @@ def test_essence3(self): class EthSha3TestConcrete(unittest.TestCase): - """ - Subclasses must assign this class variable to the class for the detector - """ - - DETECTOR_CLASS = None - def setUp(self): evm_consts = config.get_group("evm") evm_consts.sha3 = evm_consts.sha3.concretize From 50b9f6375b93293d86f09f1339fbb33f2cbaed0d Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 15:14:09 -0500 Subject: [PATCH 09/12] Add a type annotation to make mypy happy --- tests/ethereum/test_detectors.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ethereum/test_detectors.py b/tests/ethereum/test_detectors.py index 8f8b2c843..54c3d6771 100644 --- a/tests/ethereum/test_detectors.py +++ b/tests/ethereum/test_detectors.py @@ -16,6 +16,7 @@ DetectExternalCallAndLeak, DetectIntegerOverflow, DetectManipulableBalance, + Detector, DetectRaceCondition, DetectSuicidal, DetectUnusedRetVal, @@ -26,6 +27,8 @@ from manticore.utils import config, log +from typing import Type + consts = config.get_group("core") consts.mprocessing = consts.mprocessing.single @@ -39,11 +42,8 @@ def make_mock_evm_state(): class EthDetectorTest(unittest.TestCase): - """ - Subclasses must assign this class variable to the class for the detector - """ - - DETECTOR_CLASS = None + # Subclasses must assign this class variable to the class for the detector + DETECTOR_CLASS: Type[Detector] def setUp(self): self.mevm = ManticoreEVM() From 55bf7130c02033e115badda1d69fb3afb415120f Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 14:52:38 -0500 Subject: [PATCH 10/12] mypy: run on the `tests` directory by default --- mypy.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy.ini b/mypy.ini index f4c2c4bc7..0c3fa549b 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,6 +1,6 @@ [mypy] python_version = 3.6 -files = manticore +files = manticore, tests # Generated file [mypy-manticore.ethereum.parsetab] From dd9678e7ac22fe066886f40be4f9bf8adb698644 Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 16:39:40 -0500 Subject: [PATCH 11/12] Rewrite a bungled test assertion --- tests/native/test_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/native/test_memory.py b/tests/native/test_memory.py index c74254b83..d2fc54c2c 100644 --- a/tests/native/test_memory.py +++ b/tests/native/test_memory.py @@ -1428,7 +1428,7 @@ def testmprotectFailSymbReading(self): # No Access Reading <4160741376> # self.assertRaisesRegexp(MemoryException, r"No access reading.*", mem.__getitem__, x) with self.assertRaisesRegex( - InvalidSymbolicMemoryAccess, f"Invalid symbolic memory access.*<{addr:x}>" + InvalidSymbolicMemoryAccess, "Invalid symbolic memory access \(mode:r\)" ): _ = mem[x] # mem[addr] = 'a' From 9038c25160bcc40b0df4020fe061ecbfc3a936bc Mon Sep 17 00:00:00 2001 From: Brad Larsen Date: Tue, 4 Feb 2020 16:43:18 -0500 Subject: [PATCH 12/12] Fix warnings in test_memory.py about deprecated "\(" escapes --- tests/native/test_memory.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/native/test_memory.py b/tests/native/test_memory.py index d2fc54c2c..e6f03ea70 100644 --- a/tests/native/test_memory.py +++ b/tests/native/test_memory.py @@ -1373,7 +1373,7 @@ def testmprotectFailReading(self): mem.mprotect(addr, size, "w") with self.assertRaisesRegex( - InvalidMemoryAccess, f"Invalid memory access \(mode:.\) <{addr:x}>" + InvalidMemoryAccess, fr"Invalid memory access \(mode:.\) <{addr:x}>" ): _ = mem[addr] @@ -1428,7 +1428,7 @@ def testmprotectFailSymbReading(self): # No Access Reading <4160741376> # self.assertRaisesRegexp(MemoryException, r"No access reading.*", mem.__getitem__, x) with self.assertRaisesRegex( - InvalidSymbolicMemoryAccess, "Invalid symbolic memory access \(mode:r\)" + InvalidSymbolicMemoryAccess, r"Invalid symbolic memory access \(mode:r\)" ): _ = mem[x] # mem[addr] = 'a' @@ -1445,7 +1445,7 @@ def testmprotectFailWriting(self): mem[addr] = "a" mem.mprotect(addr, size, "r") with self.assertRaisesRegex( - InvalidMemoryAccess, f"Invalid memory access \(mode:w\) <{addr:x}>" + InvalidMemoryAccess, fr"Invalid memory access \(mode:w\) <{addr:x}>" ): mem[addr] = "a" @@ -1461,7 +1461,7 @@ def testmprotecNoReadthenOkRead(self): mem[addr] = "a" with self.assertRaisesRegex( - InvalidMemoryAccess, f"Invalid memory access \(mode:r\) <{addr:x}>" + InvalidMemoryAccess, fr"Invalid memory access \(mode:r\) <{addr:x}>" ): _ = mem[addr]