def test_merge_memory_object_endness(): for memcls in [UltraPageMemory, ListPageMemory]: state0 = SimState(arch='AMD64', mode='symbolic', plugins={'memory': memcls()}) state0.memory.store(0x20000, claripy.BVS("x", 64), endness="Iend_LE") state1 = SimState(arch="AMD64", mode="symbolic", plugins={'memory': memcls()}) state1.memory.store(0x20000, claripy.BVS("y", 64), endness="Iend_LE") state, _, _ = state0.merge(state1) obj = state.memory.load(0x20000, size=8, endness="Iend_LE") assert isinstance(obj, claripy.ast.Base) # the original endness should be respected, and obj.op should not be Reverse assert obj.op == "If"
def test_state_merge_static(): # With abstract memory # Aligned memory merging a = SimState(arch='AMD64', mode='static') addr = a.se.ValueSet(32, 'global', 0, 8) a.memory.store(addr, a.se.BVV(42, 32)) # Clear a_locs, so further writes will not try to merge with value 42 a.memory.regions['global']._alocs = { } b = a.copy() c = a.copy() a.memory.store(addr, a.se.BVV(50, 32), endness='Iend_LE') b.memory.store(addr, a.se.BVV(60, 32), endness='Iend_LE') c.memory.store(addr, a.se.BVV(70, 32), endness='Iend_LE') merged, _, _ = a.merge(b, c) actual = claripy.backends.vsa.convert(merged.memory.load(addr, 4)) expected = claripy.backends.vsa.convert(a.se.SI(bits=32, stride=10, lower_bound=50, upper_bound=70)) nose.tools.assert_true(actual.identical(expected))
def test_state_merge_3way(): a = SimState(arch='AMD64', mode='symbolic') b = a.copy() c = a.copy() conds = [ a.solver.BoolS('cond_0'), a.solver.BoolS('cond_1') ] a.add_constraints(conds[0]) b.add_constraints(a.solver.Not(conds[0]), conds[1]) c.add_constraints(a.solver.Not(conds[0]), a.solver.Not(conds[1])) a.memory.store(0x400000, a.solver.BVV(8, 32)) b.memory.store(0x400000, b.solver.BVV(9, 32)) c.memory.store(0x400000, c.solver.BVV(10, 32)) m, _, _ = a.merge(b) m, _, _ = m.merge(c) assert m.satisfiable(extra_constraints=(m.memory.load(0x400000, 4) == 8,)) assert m.satisfiable(extra_constraints=(m.memory.load(0x400000, 4) == 9,)) assert m.satisfiable(extra_constraints=(m.memory.load(0x400000, 4) == 10,))
def test_merge_seq(self): state1 = SimState(arch='AMD64', mode='symbolic', plugins={'memory': UltraPageMemory()}) state2 = SimState(arch='AMD64', mode='symbolic', plugins={'memory': UltraPageMemory()}) state1.regs.rsp = 0x80000000 state2.regs.rsp = 0x80000000 state1.memory.store(state1.regs.rsp, 0x11, 1) state1.memory.store(state1.regs.rsp + 1, 0x22, 1) state2.memory.store(state2.regs.rsp, 0xAA, 1) state2.memory.store(state2.regs.rsp + 1, 0xBB, 1) state3, _, __ = state1.merge(state2) vals = (v for v in state3.solver.eval_upto( state3.memory.load(state3.regs.rsp, 2), 10)) assert set([0x1122, 0xaabb]) == set(vals)
def test_state_merge_static(self): # With abstract memory # Aligned memory merging a = SimState(arch="AMD64", mode="static") addr = a.solver.ValueSet(32, "global", 0, 8) a.memory.store(addr, a.solver.BVV(42, 32)) # Clear a_locs, so further writes will not try to merge with value 42 a.memory._regions["global"]._alocs = {} b = a.copy() c = a.copy() a.memory.store(addr, a.solver.BVV(50, 32), endness="Iend_LE") b.memory.store(addr, a.solver.BVV(60, 32), endness="Iend_LE") c.memory.store(addr, a.solver.BVV(70, 32), endness="Iend_LE") merged, _, _ = a.merge(b, c) actual = claripy.backends.vsa.convert( merged.memory.load(addr, 4, endness="Iend_LE")) expected = claripy.backends.vsa.convert( a.solver.SI(bits=32, stride=10, lower_bound=50, upper_bound=70)) assert actual.identical(expected)
def test_state_merge(): a = SimState(arch='AMD64', mode='symbolic') a.memory.store(1, a.se.BVV(42, 8)) b = a.copy() c = b.copy() a.memory.store(2, a.memory.load(1, 1)+1) b.memory.store(2, b.memory.load(1, 1)*2) c.memory.store(2, c.memory.load(1, 1)/2) # make sure the byte at 1 is right nose.tools.assert_equal(a.se.eval(a.memory.load(1, 1)), 42) nose.tools.assert_equal(b.se.eval(b.memory.load(1, 1)), 42) nose.tools.assert_equal(c.se.eval(c.memory.load(1, 1)), 42) # make sure the byte at 2 is right nose.tools.assert_equal(a.se.eval(a.memory.load(2, 1)), 43) nose.tools.assert_equal(b.se.eval(b.memory.load(2, 1)), 84) nose.tools.assert_equal(c.se.eval(c.memory.load(2, 1)), 21) # the byte at 2 should be unique for all before the merge nose.tools.assert_true(a.se.unique(a.memory.load(2, 1))) nose.tools.assert_true(b.se.unique(b.memory.load(2, 1))) nose.tools.assert_true(c.se.unique(c.memory.load(2, 1))) logging.getLogger('angr.state_plugins.symbolic_memory').setLevel(logging.DEBUG) m, merge_conditions, merging_occurred = a.merge(b, c) logging.getLogger('angr.state_plugins.symbolic_memory').setLevel(logging.WARNING) nose.tools.assert_true(merging_occurred) #nose.tools.assert_equals(sorted(m.se.eval_upto(merge_flag, 10)), [ 0,1,2 ]) assert len(merge_conditions) == 3 # the byte at 2 should now *not* be unique for a nose.tools.assert_false(m.se.unique(m.memory.load(2, 1))) nose.tools.assert_true(a.se.unique(a.memory.load(2, 1))) nose.tools.assert_true(b.se.unique(b.memory.load(2, 1))) nose.tools.assert_true(c.se.unique(c.memory.load(2, 1))) # the byte at 2 should have the three values nose.tools.assert_items_equal(m.se.eval_upto(m.memory.load(2, 1), 10), (43, 84, 21)) # we should be able to select them by adding constraints a_a = m.copy() a_a.add_constraints(merge_conditions[0]) nose.tools.assert_true(a_a.se.unique(a_a.memory.load(2, 1))) nose.tools.assert_equal(a_a.se.eval(a_a.memory.load(2, 1)), 43) a_b = m.copy() a_b.add_constraints(merge_conditions[1]) nose.tools.assert_true(a_b.se.unique(a_b.memory.load(2, 1))) nose.tools.assert_equal(a_b.se.eval(a_b.memory.load(2, 1)), 84) a_c = m.copy() a_c.add_constraints(merge_conditions[2]) nose.tools.assert_true(a_c.se.unique(a_c.memory.load(2, 1))) nose.tools.assert_equal(a_c.se.eval(a_c.memory.load(2, 1)), 21) # test different sets of plugins a = SimState(arch='AMD64', mode='symbolic') nose.tools.assert_true(a.has_plugin('memory')) nose.tools.assert_true(a.has_plugin('registers')) nose.tools.assert_false(a.has_plugin('libc')) b = a.copy() a.get_plugin('libc') nose.tools.assert_true(a.has_plugin('libc')) nose.tools.assert_false(b.has_plugin('libc')) c = a.copy().merge(b.copy())[0] d = b.copy().merge(a.copy())[0] nose.tools.assert_true(c.has_plugin('libc')) nose.tools.assert_true(d.has_plugin('libc')) # test merging posix with different open files a = SimState(arch='AMD64', mode='symbolic') b = a.copy() a.posix.get_file(3) nose.tools.assert_equal(len(a.posix.files), 4) nose.tools.assert_equal(len(b.posix.files), 3) c = a.copy().merge(b.copy())[0] d = b.copy().merge(a.copy())[0] nose.tools.assert_equal(len(c.posix.files), 4) nose.tools.assert_equal(len(d.posix.files), 4)
def test_abstract_memory(): initial_memory = {0: 'A', 1: 'B', 2: 'C', 3: 'D'} s = SimState(mode='static', arch="AMD64", memory_backer=initial_memory, add_options={o.ABSTRACT_SOLVER, o.ABSTRACT_MEMORY}) se = s.se def to_vs(region, offset): return s.se.VS(s.arch.bits, region, 0, offset) # Load a single-byte constant from global region expr = s.memory.load(to_vs('global', 2), 1) nose.tools.assert_equal(s.se.any_int(expr), 0x43) nose.tools.assert_equal(s.se.max_int(expr), 0x43) nose.tools.assert_equal(s.se.min_int(expr), 0x43) # Store a single-byte constant to global region s.memory.store(to_vs('global', 1), s.se.BVV(ord('D'), 8), 1) expr = s.memory.load(to_vs('global', 1), 1) nose.tools.assert_equal(s.se.any_int(expr), 0x44) # Store a single-byte StridedInterval to global region si_0 = s.se.BVS('unnamed', 8, 10, 20, 2) s.memory.store(to_vs('global', 4), si_0) # Load the single-byte StridedInterval from global region expr = s.memory.load(to_vs('global', 4), 1) nose.tools.assert_equal(s.se.min_int(expr), 10) nose.tools.assert_equal(s.se.max_int(expr), 20) nose.tools.assert_equal(s.se.any_n_int(expr, 100), [10, 12, 14, 16, 18, 20]) # Store a two-byte StridedInterval object to global region si_1 = s.se.BVS('unnamed', 16, 10, 20, 2) s.memory.store(to_vs('global', 5), si_1) # Load the two-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 5), 2) nose.tools.assert_true(claripy.backends.vsa.identical(expr, si_1)) # Store a four-byte StridedInterval object to global region si_2 = s.se.BVS('unnamed', 32, 8000, 9000, 2) s.memory.store(to_vs('global', 7), si_2) # Load the four-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 7), 4) nose.tools.assert_true( claripy.backends.vsa.identical(expr, s.se.BVS('unnamed', 32, 8000, 9000, 2))) # Test default values s.options.remove(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 100), 4) nose.tools.assert_true( claripy.backends.vsa.identical(expr, s.se.BVS('unnamed', 32, 0, 0, 0))) # Test default values (symbolic) s.options.add(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 104), 4) nose.tools.assert_true( claripy.backends.vsa.identical( expr, s.se.BVS('unnamed', 32, 0, 0xffffffff, 1))) nose.tools.assert_true( claripy.backends.vsa.identical( expr, s.se.BVS('unnamed', 32, -0x80000000, 0x7fffffff, 1))) # # Merging # # Merging two one-byte values s.memory.store(to_vs('function_merge', 0), s.se.BVS('unnamed', 8, 0x10, 0x10, 0)) a = s.copy() a.memory.store(to_vs('function_merge', 0), s.se.BVS('unnamed', 8, 0x20, 0x20, 0)) b = s.merge(a)[0] expr = b.memory.load(to_vs('function_merge', 0), 1) nose.tools.assert_true( claripy.backends.vsa.identical( expr, s.se.BVS('unnamed', 8, 0x10, 0x20, 0x10))) # | MO(value_0) | # | MO(value_1) | # 0x20 0x24 # Merge one byte in value_0/1 means merging the entire MemoryObject a = s.copy() a.memory.store( to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100000, upper_bound=0x100000)) b = s.copy() b.memory.store( to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100001, upper_bound=0x100001)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) nose.tools.assert_true( claripy.backends.vsa.identical( expr, se.SI(bits=32, stride=1, lower_bound=0x100000, upper_bound=0x100001))) c_mem = c.memory.regions['function_merge'].memory.mem object_set = set([c_mem[0x20], c_mem[0x20], c_mem[0x22], c_mem[0x23]]) nose.tools.assert_equal(len(object_set), 1) a = s.copy() a.memory.store( to_vs('function_merge', 0x20), se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x200000)) b = s.copy() b.memory.store( to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x300000, upper_bound=0x300000)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) nose.tools.assert_true( claripy.backends.vsa.identical( expr, se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x300000))) object_set = set([c_mem[0x20], c_mem[0x20], c_mem[0x22], c_mem[0x23]]) nose.tools.assert_equal(len(object_set), 1) # # Widening # a = s.se.SI(bits=32, stride=1, lower_bound=1, upper_bound=2) b = s.se.SI(bits=32, stride=1, lower_bound=1, upper_bound=3) a = a.reversed b = b.reversed
def test_abstract_memory(): initial_memory = {0: b'A', 1: b'B', 2: b'C', 3: b'D'} s = SimState(mode='static', arch="AMD64", memory_backer=initial_memory, add_options={o.ABSTRACT_SOLVER, o.ABSTRACT_MEMORY}) se = s.se def to_vs(region, offset): return s.solver.VS(s.arch.bits, region, 0, offset) # Load a single-byte constant from global region expr = s.memory.load(to_vs('global', 2), 1) nose.tools.assert_equal(s.solver.eval(expr), 0x43) nose.tools.assert_equal(s.solver.max_int(expr), 0x43) nose.tools.assert_equal(s.solver.min_int(expr), 0x43) # Store a single-byte constant to global region s.memory.store(to_vs('global', 1), s.solver.BVV(b'D'), 1) expr = s.memory.load(to_vs('global', 1), 1) nose.tools.assert_equal(s.solver.eval(expr), 0x44) # Store a single-byte StridedInterval to global region si_0 = s.solver.BVS('unnamed', 8, 10, 20, 2) s.memory.store(to_vs('global', 4), si_0) # Load the single-byte StridedInterval from global region expr = s.memory.load(to_vs('global', 4), 1) nose.tools.assert_equal(s.solver.min_int(expr), 10) nose.tools.assert_equal(s.solver.max_int(expr), 20) nose.tools.assert_equal(s.solver.eval_upto(expr, 100), [10, 12, 14, 16, 18, 20]) # Store a two-byte StridedInterval object to global region si_1 = s.solver.BVS('unnamed', 16, 10, 20, 2) s.memory.store(to_vs('global', 5), si_1) # Load the two-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 5), 2) nose.tools.assert_true(claripy.backends.vsa.identical(expr, si_1)) # Store a four-byte StridedInterval object to global region si_2 = s.solver.BVS('unnamed', 32, 8000, 9000, 2) s.memory.store(to_vs('global', 7), si_2) # Load the four-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 7), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 8000, 9000, 2))) # Test default values s.options.remove(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 100), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 0, 0, 0))) # Test default values (symbolic) s.options.add(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 104), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 0, 0xffffffff, 1))) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, -0x80000000, 0x7fffffff, 1))) # # Merging # # Merging two one-byte values s.memory.store(to_vs('function_merge', 0), s.solver.BVS('unnamed', 8, 0x10, 0x10, 0)) a = s.copy() a.memory.store(to_vs('function_merge', 0), s.solver.BVS('unnamed', 8, 0x20, 0x20, 0)) b = s.merge(a)[0] expr = b.memory.load(to_vs('function_merge', 0), 1) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 8, 0x10, 0x20, 0x10))) # | MO(value_0) | # | MO(value_1) | # 0x20 0x24 # Merge one byte in value_0/1 means merging the entire MemoryObject a = s.copy() a.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100000, upper_bound=0x100000)) b = s.copy() b.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100001, upper_bound=0x100001)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, se.SI(bits=32, stride=1, lower_bound=0x100000, upper_bound=0x100001))) c_mem = c.memory.regions['function_merge'].memory.mem object_set = {c_mem[0x20], c_mem[0x20], c_mem[0x22], c_mem[0x23]} nose.tools.assert_equal(len(object_set), 1) a = s.copy() a.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x200000)) b = s.copy() b.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x300000, upper_bound=0x300000)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x300000))) object_set = {c_mem[0x20], c_mem[0x20], c_mem[0x22], c_mem[0x23]} nose.tools.assert_equal(len(object_set), 1) # # Widening # a = s.solver.SI(bits=32, stride=1, lower_bound=1, upper_bound=2) b = s.solver.SI(bits=32, stride=1, lower_bound=1, upper_bound=3) a = a.reversed b = b.reversed
def test_abstract_memory(): initial_memory = {0: b'A', 1: b'B', 2: b'C', 3: b'D'} s = SimState(mode='static', arch="AMD64", dict_memory_backer=initial_memory, add_options={o.ABSTRACT_SOLVER, o.ABSTRACT_MEMORY}) se = s.solver def to_vs(region, offset): return s.solver.VS(s.arch.bits, region, 0, offset) # Load a single-byte constant from global region expr = s.memory.load(to_vs('global', 2), 1) assert s.solver.eval(expr) == 0x43 assert s.solver.max_int(expr) == 0x43 assert s.solver.min_int(expr) == 0x43 # Store a single-byte constant to global region s.memory.store(to_vs('global', 1), s.solver.BVV(b'D'), 1) expr = s.memory.load(to_vs('global', 1), 1) assert s.solver.eval(expr) == 0x44 # Store a single-byte StridedInterval to global region si_0 = s.solver.BVS('unnamed', 8, 10, 20, 2) s.memory.store(to_vs('global', 4), si_0) # Load the single-byte StridedInterval from global region expr = s.memory.load(to_vs('global', 4), 1) assert s.solver.min_int(expr) == 10 assert s.solver.max_int(expr) == 20 assert s.solver.eval_upto(expr, 100) == [10, 12, 14, 16, 18, 20] # Store a two-byte StridedInterval object to global region si_1 = s.solver.BVS('unnamed', 16, 10, 20, 2) s.memory.store(to_vs('global', 5), si_1) # Load the two-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 5), 2) assert claripy.backends.vsa.identical(expr, si_1) # Store a four-byte StridedInterval object to global region si_2 = s.solver.BVS('unnamed', 32, 8000, 9000, 2) s.memory.store(to_vs('global', 7), si_2) # Load the four-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 7), 4) assert claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 8000, 9000, 2)) # Test default values s.options.remove(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 100), 4) assert claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 0, 0, 0)) # Test default values (symbolic) s.options.add(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 104), 4) assert claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 0, 0xffffffff, 1)) assert claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, -0x80000000, 0x7fffffff, 1)) # # Merging # # Merging two one-byte values s.memory.store(to_vs('function_merge', 0), s.solver.BVS('unnamed', 8, 0x10, 0x10, 0)) a = s.copy() a.memory.store(to_vs('function_merge', 0), s.solver.BVS('unnamed', 8, 0x20, 0x20, 0)) b = s.merge(a)[0] expr = b.memory.load(to_vs('function_merge', 0), 1) assert claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 8, 0x10, 0x20, 0x10)) # | MO(value_0) | # | MO(value_1) | # 0x20 0x24 # Merge one byte in value_0/1 means merging the entire MemoryObject a = s.copy() a.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100000, upper_bound=0x100000)) b = s.copy() b.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100001, upper_bound=0x100001)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) assert claripy.backends.vsa.identical(expr, se.SI(bits=32, stride=1, lower_bound=0x100000, upper_bound=0x100001)) c_page = c.memory._regions['function_merge']._pages[0] object_set = {c_page._get_object(0x20, 0), c_page._get_object(0x21, 0), c_page._get_object(0x22, 0), c_page._get_object(0x23, 0), } assert len(object_set) == 1 a = s.copy() a.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x200000)) b = s.copy() b.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x300000, upper_bound=0x300000)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) assert claripy.backends.vsa.identical(expr, se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x300000)) object_set = {c_page._get_object(0x20, 0), c_page._get_object(0x21, 0), c_page._get_object(0x22, 0), c_page._get_object(0x23, 0), } assert len(object_set) == 1 # # Widening # a = s.solver.SI(bits=32, stride=1, lower_bound=1, upper_bound=2) b = s.solver.SI(bits=32, stride=1, lower_bound=1, upper_bound=3) a = a.reversed b = b.reversed
def test_state_merge(self): a = SimState(arch="AMD64", mode="symbolic") a.memory.store(1, a.solver.BVV(42, 8)) b = a.copy() c = b.copy() a.memory.store(2, a.memory.load(1, 1) + 1) b.memory.store(2, b.memory.load(1, 1) * 2) c.memory.store(2, c.memory.load(1, 1) / 2) # make sure the byte at 1 is right assert a.solver.eval(a.memory.load(1, 1)) == 42 assert b.solver.eval(b.memory.load(1, 1)) == 42 assert c.solver.eval(c.memory.load(1, 1)) == 42 # make sure the byte at 2 is right assert a.solver.eval(a.memory.load(2, 1)) == 43 assert b.solver.eval(b.memory.load(2, 1)) == 84 assert c.solver.eval(c.memory.load(2, 1)) == 21 # the byte at 2 should be unique for all before the merge assert a.solver.unique(a.memory.load(2, 1)) assert b.solver.unique(b.memory.load(2, 1)) assert c.solver.unique(c.memory.load(2, 1)) # logging.getLogger('angr.state_plugins.symbolic_memory').setLevel(logging.DEBUG) m, merge_conditions, merging_occurred = a.merge(b, c) # logging.getLogger('angr.state_plugins.symbolic_memory').setLevel(logging.WARNING) assert merging_occurred # assert sorted(m.solver.eval_upto(merge_flag, 10)) == [ 0,1,2 ] assert len(merge_conditions) == 3 # the byte at 2 should now *not* be unique for a assert not m.solver.unique(m.memory.load(2, 1)) assert a.solver.unique(a.memory.load(2, 1)) assert b.solver.unique(b.memory.load(2, 1)) assert c.solver.unique(c.memory.load(2, 1)) # the byte at 2 should have the three values self.assertSequenceEqual( sorted(m.solver.eval_upto(m.memory.load(2, 1), 10)), (21, 43, 84)) # we should be able to select them by adding constraints a_a = m.copy() a_a.add_constraints(merge_conditions[0]) assert a_a.solver.unique(a_a.memory.load(2, 1)) assert a_a.solver.eval(a_a.memory.load(2, 1)) == 43 a_b = m.copy() a_b.add_constraints(merge_conditions[1]) assert a_b.solver.unique(a_b.memory.load(2, 1)) assert a_b.solver.eval(a_b.memory.load(2, 1)) == 84 a_c = m.copy() a_c.add_constraints(merge_conditions[2]) assert a_c.solver.unique(a_c.memory.load(2, 1)) assert a_c.solver.eval(a_c.memory.load(2, 1)) == 21 # test different sets of plugins a = SimState(arch="AMD64", mode="symbolic") assert a.has_plugin("memory") assert a.has_plugin("registers") assert not a.has_plugin("libc") b = a.copy() a.get_plugin("libc") assert a.has_plugin("libc") assert not b.has_plugin("libc") c = a.copy().merge(b.copy())[0] d = b.copy().merge(a.copy())[0] assert c.has_plugin("libc") assert d.has_plugin("libc") # test merging posix with different open files (illegal!) a = SimState(arch="AMD64", mode="symbolic") b = a.copy() a.posix.open(b"/tmp/idk", 1) self.assertRaises(angr.errors.SimMergeError, lambda: a.copy().merge(b.copy()))