Skip to content

Commit 7213fcc

Browse files
committed
Issue python#23370: Fix off-by-one error for non-contiguous buffers.
1 parent f046dfe commit 7213fcc

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

Modules/_testcapimodule.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,56 @@ make_memoryview_from_NULL_pointer(PyObject *self)
24672467
return NULL;
24682468
return PyMemoryView_FromBuffer(&info);
24692469
}
2470+
2471+
static PyObject *
2472+
test_from_contiguous(PyObject* self, PyObject *noargs)
2473+
{
2474+
int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
2475+
int init[5] = {0, 1, 2, 3, 4};
2476+
Py_ssize_t itemsize = sizeof(int);
2477+
Py_ssize_t shape = 5;
2478+
Py_ssize_t strides = 2 * itemsize;
2479+
Py_buffer view = {
2480+
data,
2481+
NULL,
2482+
5 * itemsize,
2483+
itemsize,
2484+
1,
2485+
1,
2486+
NULL,
2487+
&shape,
2488+
&strides,
2489+
NULL,
2490+
NULL
2491+
};
2492+
int *ptr;
2493+
int i;
2494+
2495+
PyBuffer_FromContiguous(&view, init, view.len, 'C');
2496+
ptr = view.buf;
2497+
for (i = 0; i < 5; i++) {
2498+
if (ptr[2*i] != i) {
2499+
PyErr_SetString(TestError,
2500+
"test_from_contiguous: incorrect result");
2501+
return NULL;
2502+
}
2503+
}
2504+
2505+
view.buf = &data[8];
2506+
view.strides[0] = -2 * itemsize;
2507+
2508+
PyBuffer_FromContiguous(&view, init, view.len, 'C');
2509+
ptr = view.buf;
2510+
for (i = 0; i < 5; i++) {
2511+
if (*(ptr-2*i) != i) {
2512+
PyErr_SetString(TestError,
2513+
"test_from_contiguous: incorrect result");
2514+
return NULL;
2515+
}
2516+
}
2517+
2518+
Py_RETURN_NONE;
2519+
}
24702520

24712521
/* Test that the fatal error from not having a current thread doesn't
24722522
cause an infinite loop. Run via Lib/test/test_capi.py */
@@ -3031,6 +3081,7 @@ static PyMethodDef TestMethods[] = {
30313081
{"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS},
30323082
{"test_unicode_compare_with_ascii", (PyCFunction)test_unicode_compare_with_ascii, METH_NOARGS},
30333083
{"test_capsule", (PyCFunction)test_capsule, METH_NOARGS},
3084+
{"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS},
30343085
{"getargs_tuple", getargs_tuple, METH_VARARGS},
30353086
{"getargs_keywords", (PyCFunction)getargs_keywords,
30363087
METH_VARARGS|METH_KEYWORDS},

Objects/abstract.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)
488488

489489
/* Otherwise a more elaborate scheme is needed */
490490

491-
/* XXX(nnorwitz): need to check for overflow! */
491+
/* view->ndim <= 64 */
492492
indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim));
493493
if (indices == NULL) {
494494
PyErr_NoMemory();
@@ -510,10 +510,10 @@ PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)
510510
*/
511511
elements = len / view->itemsize;
512512
while (elements--) {
513-
addone(view->ndim, indices, view->shape);
514513
ptr = PyBuffer_GetPointer(view, indices);
515514
memcpy(ptr, src, view->itemsize);
516515
src += view->itemsize;
516+
addone(view->ndim, indices, view->shape);
517517
}
518518

519519
PyMem_Free(indices);

0 commit comments

Comments
 (0)