mirror of
https://github.com/angr/angr
synced 2026-08-17 12:23:11 -04:00
FunctionParser: convert previous_names protobuf field to a plain list. (#6584)
This commit is contained in:
parent
18d7fff834
commit
79ec25dc24
2 changed files with 66 additions and 1 deletions
|
|
@ -216,7 +216,7 @@ class FunctionParser:
|
|||
obj.info = json.loads(cmsg.info.decode("utf-8")) if cmsg.info else {}
|
||||
obj.is_default_name = cmsg.is_default_name
|
||||
obj.ran_cca = cmsg.ran_cca
|
||||
obj.previous_names = cmsg.previous_names
|
||||
obj.previous_names = list(cmsg.previous_names)
|
||||
|
||||
# signature matched?
|
||||
if cmsg.matched_from == function_pb2.Function.UNMATCHED:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env python3
|
||||
# pylint: disable=missing-class-docstring
|
||||
"""Regression test: parse_from_cmsg assigned the protobuf RepeatedScalarContainer
|
||||
directly to Function.previous_names instead of converting it to a plain list.
|
||||
This breaks pickling of Function objects.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pickle
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import angr
|
||||
from angr.codenode import BlockNode
|
||||
from angr.knowledge_plugins.functions.function import Function
|
||||
|
||||
|
||||
class TestFunctionParserPreviousNames(unittest.TestCase):
|
||||
def test_parsed_previous_names_is_plain_list_and_picklable(self):
|
||||
blob = bytes.fromhex("c3") # ret
|
||||
addr = 0x400000
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f:
|
||||
f.write(blob)
|
||||
blob_path = f.name
|
||||
|
||||
proj = angr.Project(
|
||||
blob_path,
|
||||
main_opts={
|
||||
"backend": "blob",
|
||||
"base_addr": addr,
|
||||
"arch": "AMD64",
|
||||
"entry_point": addr,
|
||||
},
|
||||
auto_load_libs=False,
|
||||
)
|
||||
|
||||
fm = proj.kb.functions
|
||||
func = fm.function(addr=addr, create=True)
|
||||
assert func is not None
|
||||
func._register_node(True, BlockNode(addr, 1, bytestr=blob))
|
||||
func.name = "original_name"
|
||||
func.name = "renamed" # records "original_name" in previous_names
|
||||
self.assertIn("original_name", func.previous_names)
|
||||
expected = list(func.previous_names)
|
||||
|
||||
cmsg = func.serialize_to_cmessage()
|
||||
loaded = Function.parse_from_cmessage(cmsg, function_manager=fm, project=proj)
|
||||
|
||||
# previous_names must be a plain list, not a live protobuf container
|
||||
self.assertIs(type(loaded.previous_names), list)
|
||||
self.assertEqual(loaded.previous_names, expected)
|
||||
|
||||
# mutating the parsed function must not alias back into the cmsg
|
||||
loaded.previous_names.append("another_name")
|
||||
self.assertEqual(list(cmsg.previous_names), expected)
|
||||
|
||||
# the parsed function must round-trip through pickle
|
||||
unpickled = pickle.loads(pickle.dumps(loaded))
|
||||
self.assertEqual(unpickled.previous_names, [*expected, "another_name"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue