From dd58130ec147e10f1e4809b31443328b07f8677e Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 23 Oct 2026 17:03:59 +0200 Subject: [PATCH] Fix autopatch_capi not replacing ob_refcnt set --- .../src/tests/test_autopatch_capi.py | 27 +++++++++++++++++++ .../lib-graalpython/modules/autopatch_capi.py | 8 +++--- .../lib-graalpython/patches/numpy-2.4.4.patch | 13 --------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_autopatch_capi.py b/graalpython/com.oracle.graal.python.test/src/tests/test_autopatch_capi.py index cd54956ec2..53ecacf515 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_autopatch_capi.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_autopatch_capi.py @@ -137,3 +137,30 @@ def test_replace_field_access(): PySequence_Fast_ITEMS((PyObject*)L)[len] = x; ''', ) + + + def test_replace_refcnt_assignment(): + check_autopatched( + 'obj->ob_refcnt = 1;', + 'Py_SET_REFCNT(obj, 1);', + ) + check_autopatched( + ''' + #else + op->ob_refcnt = _Py_IMMORTAL_REFCNT; + #endif + ''', + ''' + #else + Py_SET_REFCNT(op, _Py_IMMORTAL_REFCNT); + #endif + ''', + ) + check_autopatched( + '((PyObject*)obj)->ob_refcnt = compute_refcnt(obj, 1);', + 'Py_SET_REFCNT(((PyObject*)obj), compute_refcnt(obj, 1));', + ) + check_autopatched( + 'if (obj->ob_refcnt == 1) return obj->ob_refcnt;', + 'if (Py_REFCNT(obj) == 1) return Py_REFCNT(obj);', + ) diff --git a/graalpython/lib-graalpython/modules/autopatch_capi.py b/graalpython/lib-graalpython/modules/autopatch_capi.py index 49382c5fc6..6117e258cd 100644 --- a/graalpython/lib-graalpython/modules/autopatch_capi.py +++ b/graalpython/lib-graalpython/modules/autopatch_capi.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -138,7 +138,7 @@ def consume_identifier_backwards(idx): break idx = consume_whitespace_backwards(idx) - receiver_start = consume_whitespace_forward(idx) + receiver_start = consume_whitespace_forward(max(idx, 0)) receiver_string = contents[receiver_start: start - 1] if assignment is not None: @@ -149,7 +149,7 @@ def consume_identifier_backwards(idx): # this looks like an assignment, determine the value idx = consume_whitespace_forward(idx + 1) value_start = idx - while idx < len(contents) - 2: + while idx < len(contents): c = contents[idx] c2 = contents[idx: idx + 2] if c == '(' or c == '[' or (c == '<' and c2 != '<=' and c2 != '<<'): @@ -179,7 +179,7 @@ def consume_identifier_backwards(idx): r'\+\+([\d\w_]+)->ob_refcnt': (replace_pre, '(Py_SET_REFCNT(%receiver, Py_REFCNT(%receiver) + 1), Py_REFCNT(%receiver))'), # avoid direct access: r'\W(ob_type)\W': (replace_field_access, 'Py_TYPE(%receiver)'), - r'\W(ob_refcnt)\W': (replace_field_access, 'Py_REFCNT(%receiver)'), + r'\W(ob_refcnt)\W': (replace_field_access, 'Py_REFCNT(%receiver)', 'Py_SET_REFCNT(%receiver, %value)'), r'\W(ob_item)\W': (replace_field_access, 'PySequence_Fast_ITEMS((PyObject*)%receiver)'), r'^\s*()(std::)?free\((const_cast)?\(?\w+->m_ml->ml_doc\)?\);': (simple_replace, '//'), r'\W(m_ml\s*->\s*ml_doc)\W': (replace_field_access, 'GraalPyCFunction_GetDoc((PyObject*)(%receiver))', 'GraalPyCFunction_SetDoc((PyObject*)(%receiver), %value)'), diff --git a/graalpython/lib-graalpython/patches/numpy-2.4.4.patch b/graalpython/lib-graalpython/patches/numpy-2.4.4.patch index e1331821a1..8a18791753 100644 --- a/graalpython/lib-graalpython/patches/numpy-2.4.4.patch +++ b/graalpython/lib-graalpython/patches/numpy-2.4.4.patch @@ -34,19 +34,6 @@ index 3a0b52c..1819ec6 100644 include_directories: [ 'include', 'src/common', -diff --git a/numpy/_core/src/common/pythoncapi-compat/pythoncapi_compat.h b/numpy/_core/src/common/pythoncapi-compat/pythoncapi_compat.h -index 10b7bf7..fc61d66 100644 ---- a/numpy/_core/src/common/pythoncapi-compat/pythoncapi_compat.h -+++ b/numpy/_core/src/common/pythoncapi-compat/pythoncapi_compat.h -@@ -2684,7 +2684,7 @@ PyUnstable_SetImmortal(PyObject *op) - op->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL; - op->ob_ref_shared = 0; - #else -- Py_REFCNT(op) = _Py_IMMORTAL_REFCNT; -+ Py_SET_REFCNT(op, _Py_IMMORTAL_REFCNT); - #endif - #endif - return 1; diff --git a/numpy/_core/src/multiarray/compiled_base.c b/numpy/_core/src/multiarray/compiled_base.c index 6e37968..010bd03 100644 --- a/numpy/_core/src/multiarray/compiled_base.c