8000 Unexpected behavior of z3 in parallel mode · Issue #7596 · Z3Prover/z3 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Unexpected behavior of z3 in parallel mode #7596

New issue

Have a question about this project? Sign up for a free GitHub 8000 account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
rstular opened this issue Mar 26, 2025 · 2 comments
Open

Unexpected behavior of z3 in parallel mode #7596

rstular opened this issue Mar 26, 2025 · 2 comments

Comments

@rstular
Copy link
rstular commented Mar 26, 2025

Running the example below produces incorrect/unexpected results. All flag characters are constrained to be within the [a-fA-F0-9] range. However, the generated solution clearly violates that constraint. Switching the parallel mode off fixes the problem.

Python reproduction
from z3 import *

FLAG = [BitVec(f"flag_{i:x}", 32) for i in range(16)]

set_option("parallel.enable", True)

s = Solver()

# All characters must be between a-f or 0-9
for flag_char in FLAG:
    s.add(Or(And(flag_char >= ord('a'), flag_char <= ord('f')), And(flag_char >= ord('0'), flag_char <= ord('9'))))

HASH = BitVecVal(0x811C9DC5, 32)
for i in range(16):
    HASH *= 0x1000193
    HASH ^= FLAG[i]
s.add(HASH == 0x7586CBD1)

MEM_0x10 = BitVecVal(0x811C9DC5, 32)
for i in range(3):
    MEM_0x10 *= 0x1000193
    MEM_0x10 ^= FLAG[i + 5]
MEM_0x10 &= 0xFF
s.add(MEM_0x10 == 0x51)

MEM_0x11 = BitVecVal(0x811C9DC5, 32)
for i in range(3):
    MEM_0x11 *= 0x1000193
    MEM_0x11 ^= FLAG[(i * 2) + 0xA]
MEM_0x11 &= 0xFF
s.add(MEM_0x11 == 0x53)

s.add(FLAG[4] == 0x30)  # 0x12

MEM_0x13 = BitVecVal(0, 32)
for i in range(4):
    MEM_0x13 += FLAG[i] * (0xD3**i)
MEM_0x13 -= 0x74D
MEM_0x13 &= 0xFF
MEM_0x13 ^= 0xC0
s.add(MEM_0x13 == 0xD1)

R0 = BitVecVal(0, 32)
R0 += FLAG[0xB]
R0 = R0 >> 13 | ((R0 & 0xFFFF) << (32 - 13))
R0 += FLAG[0xD]
R0 = R0 >> 13 | ((R0 & 0xFFFF) << (32 - 13))
R0 += FLAG[0xF]
R0 = R0 >> 13 | ((R0 & 0xFFFF) << (32 - 13))
R0 &= 0xFF
s.add(R0 == 0x40)

s.add(FLAG[9] == 0x61)
s.add(FLAG[8] == 0x32)

print(s.check())
m = s.model()

vals = [(x, m[x]) for x in m]
sm = sorted(vals, key=lambda x: str(x[0]))

for x in sm:
    print(x[0], hex(x[1].as_long()), chr(x[1].as_long()) if x[1].as_long() < 1000 else '???')
Output
sat
flag_0 0x61 a
flag_1 0xf00039 ???
flag_2 0x30 0
flag_3 0x36 6
flag_4 0x30 0
flag_5 0x62 b
flag_6 0x36 6
flag_7 0x32 2
flag_8 0x32 2
flag_9 0x61 a
flag_a 0x36 6
flag_b 0x6c l
flag_c 0x39 9
flag_d 0x3d =
flag_e 0x65 e
flag_f 0x43040432 ???

In case this is intended behaviour, and I'm using z3 incorrectly, a warning message or even a crash would be appreciated since presenting an incorrect result is quite unintuitive.

@martinmladenov
Copy link

Here is a smaller example producing a solution violating the defined constraints:

from z3 import *

n = 7

expected_result = 0
for _ in range(n):
    expected_result *= 0x1000123
    expected_result += ord('a')
expected_result &= 0xffffffff

set_option("parallel.enable", True)

chars = [BitVec(f"c_{i}", 32) for i in range(n)]

s = Solver()

# All characters must be between a-f or 0-9
for c in chars:
    s.add(Or(And(c >= ord('a'), c <= ord('f')), And(c >= ord('0'
8000
), c <= ord('9'))))

h = BitVecVal(0, 32)
for i in range(len(chars)):
    h *= 0x1000123
    h += chars[i]
s.add(h == expected_result)

print(s.check())
m = s.model()

vals = [(x, m[x]) for x in m]
sm = sorted(vals, key=lambda x: str(x[0]))

for name, r in sm:
    val = r.as_long()
    print(name, hex(val), chr(val) if val < 128 else 'invalid')

Output:

sat
c_0 0x61 a
c_1 0x80000061 invalid
c_2 0x61 a
c_3 0x61 a
c_4 0x61 a
c_5 0x80000061 invalid
c_6 0x61 a

@NikolajBjorner
Copy link
Contributor

it's a tricky one

NikolajBjorner added a commit that referenced this issue Apr 28, 2025
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
0