summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2022-07-03 00:23:31 -0700
committerda-woods <dw-git@d-woods.co.uk>2022-07-03 08:32:13 +0100
commit98cebe4dedb52550ce621cf9338283dd7262ea83 (patch)
tree4558e45e1818b20a33214aad3a506f9f1c5de03e /tests
parent5c900c59d03f23f7329d6e68e114e4a277112916 (diff)
downloadcython-98cebe4dedb52550ce621cf9338283dd7262ea83.tar.gz
BUG: Fortify object buffers against included NULLs (#4859)
* BUG: Fortify object buffers against included NULLs While NumPy tends to not actively create object buffers initialized only with NULL (rather than filled with None), at least older versions of NumPy did do that. And NumPy guards against this. This guards against embedded NULLs in object buffers interpreting a NULL as None (and anticipating a NULL value also when setting the buffer for reference count purposes). Closes gh-4858
Diffstat (limited to 'tests')
-rw-r--r--tests/buffers/bufaccess.pyx45
1 files changed, 45 insertions, 0 deletions
diff --git a/tests/buffers/bufaccess.pyx b/tests/buffers/bufaccess.pyx
index 8761e6eb9..2a5e84185 100644
--- a/tests/buffers/bufaccess.pyx
+++ b/tests/buffers/bufaccess.pyx
@@ -1005,6 +1005,51 @@ def assign_to_object(object[object] buf, int idx, obj):
buf[idx] = obj
@testcase
+def check_object_nulled_1d(MockBuffer[object, ndim=1] buf, int idx, obj):
+ """
+ See comments on printbuf_object above.
+
+ >>> a = object()
+ >>> rc1 = get_refcount(a)
+ >>> A = ObjectMockBuffer(None, [a, a])
+ >>> check_object_nulled_1d(A, 0, a)
+ >>> decref(a) # new reference "added" to A
+ >>> check_object_nulled_1d(A, 1, a)
+ >>> decref(a)
+ >>> A = ObjectMockBuffer(None, [a, a, a, a], strides=(2,))
+ >>> check_object_nulled_1d(A, 0, a) # only 0 due to stride
+ >>> decref(a)
+ >>> get_refcount(a) == rc1
+ True
+ """
+ cdef void **data = <void **>buf.buffer
+ data[idx] = NULL
+ res = buf[idx] # takes None
+ buf[idx] = obj
+ return res
+
+@testcase
+def check_object_nulled_2d(MockBuffer[object, ndim=2] buf, int idx1, int idx2, obj):
+ """
+ See comments on printbuf_object above.
+
+ >>> a = object()
+ >>> rc1 = get_refcount(a)
+ >>> A = ObjectMockBuffer(None, [a, a, a, a], shape=(2, 2))
+ >>> check_object_nulled_2d(A, 0, 0, a)
+ >>> decref(a) # new reference "added" to A
+ >>> check_object_nulled_2d(A, 1, 1, a)
+ >>> decref(a)
+ >>> get_refcount(a) == rc1
+ True
+ """
+ cdef void **data = <void **>buf.buffer
+ data[idx1 + 2*idx2] = NULL
+ res = buf[idx1, idx2] # takes None
+ buf[idx1, idx2] = obj
+ return res
+
+@testcase
def assign_temporary_to_object(object[object] buf):
"""
See comments on printbuf_object above.