From 24fdbb9aca552f000486185136b8372a00be457f Mon Sep 17 00:00:00 2001 From: xmarre Date: Sun, 15 Mar 2026 07:30:18 +0100 Subject: [PATCH] Replace sanitize hash two pass --- comfy_execution/caching.py | 14 +++++++------- tests-unit/execution_test/caching_test.py | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/comfy_execution/caching.py b/comfy_execution/caching.py index caa5d4a48..130b0dd5e 100644 --- a/comfy_execution/caching.py +++ b/comfy_execution/caching.py @@ -170,17 +170,17 @@ def _signature_to_hashable_impl(obj, depth=0, max_depth=_MAX_SIGNATURE_DEPTH, ac return _FAILED_SIGNATURE key_value, key_sort = key_result value_value, value_sort = value_result - ordered_items.append((((key_sort, value_sort)), (key_value, value_value))) + ordered_items.append((key_sort, value_sort, key_value, value_value)) - ordered_items.sort(key=lambda item: item[0]) + ordered_items.sort(key=lambda item: (item[0], item[1])) for index in range(1, len(ordered_items)): - previous_sort_key, previous_item = ordered_items[index - 1] - current_sort_key, current_item = ordered_items[index] - if previous_sort_key == current_sort_key and previous_item != current_item: + previous_key_sort = ordered_items[index - 1][0] + current_key_sort = ordered_items[index][0] + if previous_key_sort == current_key_sort: return _FAILED_SIGNATURE - value = ("dict", tuple(item for _, item in ordered_items)) - sort_key = ("dict", tuple(sort_key for sort_key, _ in ordered_items)) + value = ("dict", tuple((key_value, value_value) for _, _, key_value, value_value in ordered_items)) + sort_key = ("dict", tuple((key_sort, value_sort) for key_sort, value_sort, _, _ in ordered_items)) elif obj_type is list or obj_type is tuple: try: items = list(obj) diff --git a/tests-unit/execution_test/caching_test.py b/tests-unit/execution_test/caching_test.py index a7dffcee0..9e813eec7 100644 --- a/tests-unit/execution_test/caching_test.py +++ b/tests-unit/execution_test/caching_test.py @@ -240,6 +240,28 @@ def test_signature_to_hashable_fails_closed_for_ambiguous_dict_ordering(caching_ assert isinstance(sanitized, caching.Unhashable) +def test_signature_to_hashable_fails_closed_on_dict_key_sort_collisions_even_with_distinct_values(caching_module, monkeypatch): + """Different values must not mask dict key-sort collisions during canonicalization.""" + caching, _ = caching_module + original = caching._signature_to_hashable_impl + key_a = object() + key_b = object() + + def colliding_key_canonicalize(obj, *args, **kwargs): + """Force two distinct raw keys to share the same canonical sort key.""" + if obj is key_a: + return ("key-a", ("COLLIDE",)) + if obj is key_b: + return ("key-b", ("COLLIDE",)) + return original(obj, *args, **kwargs) + + monkeypatch.setattr(caching, "_signature_to_hashable_impl", colliding_key_canonicalize) + + sanitized = caching._signature_to_hashable({key_a: 1, key_b: 2}) + + assert isinstance(sanitized, caching.Unhashable) + + @pytest.mark.parametrize( "container_factory", [