Skip to content

Commit 25735a9

Browse files
Explicitly invalidate the global parse hash in SpecParser constructor (#409)
Explicitly invalidate the global parse hash in `SpecParser` constructor Python can reuse id of objects after they are garbage-collected, however the global parse hash contains an id of SpecParser instance in order to force parsing on context switches, and when a different instance has the same id, it has no way to detect that. Explicitly invalidate the global parse hash when a SpecParser instance is created to prevent this issue. Fixes packit/packit-service#2461. Reviewed-by: Laura Barcziová
2 parents 3fe7b74 + e5d8d48 commit 25735a9

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

specfile/spec_parser.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def __init__(
5757
self.force_parse = force_parse
5858
self.spec = None
5959
self.tainted = False
60+
# explicitly invalidate the global parse hash, this `SpecParser` instance could have
61+
# been assigned the same id as a previously deleted one and parsing could be
62+
# improperly skipped
63+
SpecParser._last_parse_hash = None
6064

6165
def __eq__(self, other: object) -> bool:
6266
if not isinstance(other, SpecParser):
@@ -71,9 +75,12 @@ def __eq__(self, other: object) -> bool:
7175
def __repr__(self) -> str:
7276
return f"SpecParser({self.sourcedir!r}, {self.macros!r}, {self.force_parse!r})"
7377

78+
def id(self) -> int:
79+
return id(self)
80+
7481
def __deepcopy__(self, memo: Dict[int, Any]) -> "SpecParser":
7582
result = self.__class__.__new__(self.__class__)
76-
memo[id(self)] = result
83+
memo[self.id()] = result
7784
for k, v in self.__dict__.items():
7885
if k in ["spec", "tainted"]:
7986
continue
@@ -359,7 +366,7 @@ def parse(
359366
"""
360367
# calculate hash of all input parameters
361368
payload = (
362-
id(self),
369+
self.id(),
363370
self.sourcedir,
364371
self.macros,
365372
self.force_parse,

tests/integration/test_specfile.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,16 @@ def test_parse_if_necessary(spec_macros):
580580
flexmock(SpecParser).should_call("_do_parse").once()
581581
assert spec1.expanded_name == "test"
582582
assert spec1.expanded_version == "28.1.2~rc2"
583+
flexmock(SpecParser).should_receive("id").and_return(12345)
584+
flexmock(SpecParser).should_call("_do_parse").once()
585+
spec = Specfile(spec_macros)
586+
flexmock(SpecParser).should_call("_do_parse").never()
587+
assert spec.expanded_name == "test"
588+
spec = None
589+
flexmock(SpecParser).should_call("_do_parse").once()
590+
spec = Specfile(spec_macros)
591+
flexmock(SpecParser).should_call("_do_parse").never()
592+
assert spec.expanded_name == "test"
583593

584594

585595
@pytest.mark.skipif(

0 commit comments

Comments
 (0)