angr/tests/angrdb/test_angrdb_load_missing_binary.py
Kevin Phoenix f939c5b88c
Enable ruff isort rule (#6452)
* Enable ruff isort rule

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-06-02 14:48:07 -07:00

88 lines
3.4 KiB
Python

#!/usr/bin/env python3
# pylint:disable=missing-class-docstring,no-self-use
from __future__ import annotations
__package__ = __package__ or "tests.angrdb" # pylint:disable=redefined-builtin
import os
import shutil
import tempfile
import unittest
import angr
from angr.angrdb import AngrDB
from tests.common import bin_location
test_location = os.path.join(bin_location, "tests")
class TestAngrDBLoadMissingBinary(unittest.TestCase):
def test_load_after_original_binary_deleted(self):
"""AngrDB.load() must work even when the original binary no longer exists on disk.
Regression test for https://github.com/angr/angr/issues/6367:
previously the loader extracted binaries to a TemporaryDirectory,
which caused a PermissionError on Windows when CLE memory-mapped
the temp files and the context manager tried to delete them.
The fix uses BytesIO so no temporary files are created at all.
"""
src_bin = os.path.join(test_location, "x86_64", "fauxware")
with tempfile.TemporaryDirectory() as td:
# Copy the binary into a temporary location
tmp_bin = os.path.join(td, "fauxware")
shutil.copy2(src_bin, tmp_bin)
# Create a project from the temporary copy and dump it
proj = angr.Project(tmp_bin, auto_load_libs=False)
db_file = os.path.join(td, "test.adb")
AngrDB(proj, nullpool=True).dump(db_file)
# Delete the original binary
os.unlink(tmp_bin)
assert not os.path.exists(tmp_bin)
# Load should succeed without PermissionError
proj2 = AngrDB(nullpool=True).load(db_file)
# Verify the reloaded project is functional
assert proj2.arch.name == proj.arch.name
assert proj2.entry == proj.entry
def test_load_ignores_different_binary_at_original_path(self):
"""AngrDB.load() must always use the stored binary content, even when
a (potentially different) file exists at the original path.
"""
fauxware = os.path.join(test_location, "x86_64", "fauxware")
with tempfile.TemporaryDirectory() as td:
tmp_bin = os.path.join(td, "target_binary")
shutil.copy2(fauxware, tmp_bin)
proj = angr.Project(tmp_bin, auto_load_libs=False)
db_file = os.path.join(td, "test.adb")
AngrDB(proj, nullpool=True).dump(db_file)
original_entry = proj.entry
original_arch = proj.arch.name
# Overwrite the file at the original path with a completely
# different binary. If the loader were to read from disk
# instead of the DB content, it would get the wrong binary.
different_bin = os.path.join(test_location, "i386", "fauxware")
shutil.copy2(different_bin, tmp_bin)
# Sanity-check: the replacement really is different
replacement_proj = angr.Project(tmp_bin, auto_load_libs=False)
assert replacement_proj.arch.name != original_arch or replacement_proj.entry != original_entry
# Load from DB — should get the *original* binary, not the
# replacement sitting at the same path
proj2 = AngrDB(nullpool=True).load(db_file)
assert proj2.arch.name == original_arch
assert proj2.entry == original_entry
if __name__ == "__main__":
unittest.main()