gh-120674: Protect multi-line macros in _testbuffer.c and _testcapimodule.c (#120675)

Add do { ... } while (0) pattern.
This commit is contained in:
Bénédikt Tran 2024-06-18 14:04:52 +02:00 committed by GitHub
parent 4bc27abdbe
commit 7c5da94b5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 86 additions and 60 deletions

View File

@ -24,11 +24,13 @@ static PyTypeObject NDArray_Type;
#define NDArray_Check(v) Py_IS_TYPE(v, &NDArray_Type) #define NDArray_Check(v) Py_IS_TYPE(v, &NDArray_Type)
#define CHECK_LIST_OR_TUPLE(v) \ #define CHECK_LIST_OR_TUPLE(v) \
if (!PyList_Check(v) && !PyTuple_Check(v)) { \ do { \
PyErr_SetString(PyExc_TypeError, \ if (!PyList_Check(v) && !PyTuple_Check(v)) { \
#v " must be a list or a tuple"); \ PyErr_SetString(PyExc_TypeError, \
return NULL; \ #v " must be a list or a tuple"); \
} \ return NULL; \
} \
} while (0)
#define PyMem_XFree(v) \ #define PyMem_XFree(v) \
do { if (v) PyMem_Free(v); } while (0) do { if (v) PyMem_Free(v); } while (0)
@ -1180,7 +1182,7 @@ init_ndbuf(PyObject *items, PyObject *shape, PyObject *strides,
Py_ssize_t itemsize; Py_ssize_t itemsize;
/* ndim = len(shape) */ /* ndim = len(shape) */
CHECK_LIST_OR_TUPLE(shape) CHECK_LIST_OR_TUPLE(shape);
ndim = PySequence_Fast_GET_SIZE(shape); ndim = PySequence_Fast_GET_SIZE(shape);
if (ndim > ND_MAX_NDIM) { if (ndim > ND_MAX_NDIM) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
@ -1190,7 +1192,7 @@ init_ndbuf(PyObject *items, PyObject *shape, PyObject *strides,
/* len(strides) = len(shape) */ /* len(strides) = len(shape) */
if (strides) { if (strides) {
CHECK_LIST_OR_TUPLE(strides) CHECK_LIST_OR_TUPLE(strides);
if (PySequence_Fast_GET_SIZE(strides) == 0) if (PySequence_Fast_GET_SIZE(strides) == 0)
strides = NULL; strides = NULL;
else if (flags & ND_FORTRAN) { else if (flags & ND_FORTRAN) {
@ -1222,7 +1224,7 @@ init_ndbuf(PyObject *items, PyObject *shape, PyObject *strides,
return NULL; return NULL;
} }
else { else {
CHECK_LIST_OR_TUPLE(items) CHECK_LIST_OR_TUPLE(items);
Py_INCREF(items); Py_INCREF(items);
} }

View File

@ -81,8 +81,11 @@ static PyObject*
test_config(PyObject *self, PyObject *Py_UNUSED(ignored)) test_config(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
#define CHECK_SIZEOF(FATNAME, TYPE) \ #define CHECK_SIZEOF(FATNAME, TYPE) \
if (FATNAME != sizeof(TYPE)) \ do { \
return sizeof_error(self, #FATNAME, #TYPE, FATNAME, sizeof(TYPE)) if (FATNAME != sizeof(TYPE)) { \
return sizeof_error(self, #FATNAME, #TYPE, FATNAME, sizeof(TYPE)); \
} \
} while (0)
CHECK_SIZEOF(SIZEOF_SHORT, short); CHECK_SIZEOF(SIZEOF_SHORT, short);
CHECK_SIZEOF(SIZEOF_INT, int); CHECK_SIZEOF(SIZEOF_INT, int);
@ -103,21 +106,25 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored))
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits" #pragma GCC diagnostic ignored "-Wtype-limits"
#endif #endif
#define CHECK_SIZEOF(TYPE, EXPECTED) \ #define CHECK_SIZEOF(TYPE, EXPECTED) \
if (EXPECTED != sizeof(TYPE)) { \ do { \
PyErr_Format(get_testerror(self), \ if (EXPECTED != sizeof(TYPE)) { \
"sizeof(%s) = %u instead of %u", \ PyErr_Format(get_testerror(self), \
#TYPE, sizeof(TYPE), EXPECTED); \ "sizeof(%s) = %u instead of %u", \
return (PyObject*)NULL; \ #TYPE, sizeof(TYPE), EXPECTED); \
} return (PyObject*)NULL; \
} \
} while (0)
#define IS_SIGNED(TYPE) (((TYPE)-1) < (TYPE)0) #define IS_SIGNED(TYPE) (((TYPE)-1) < (TYPE)0)
#define CHECK_SIGNNESS(TYPE, SIGNED) \ #define CHECK_SIGNNESS(TYPE, SIGNED) \
if (IS_SIGNED(TYPE) != SIGNED) { \ do { \
PyErr_Format(get_testerror(self), \ if (IS_SIGNED(TYPE) != SIGNED) { \
"%s signness is %i, instead of %i", \ PyErr_Format(get_testerror(self), \
#TYPE, IS_SIGNED(TYPE), SIGNED); \ "%s signness is %i, instead of %i", \
return (PyObject*)NULL; \ #TYPE, IS_SIGNED(TYPE), SIGNED); \
} return (PyObject*)NULL; \
} \
} while (0)
/* integer types */ /* integer types */
CHECK_SIZEOF(Py_UCS1, 1); CHECK_SIZEOF(Py_UCS1, 1);
@ -884,27 +891,34 @@ test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) {
double result; double result;
const char *msg; const char *msg;
#define CHECK_STRING(STR, expected) \ #define CHECK_STRING(STR, expected) \
result = PyOS_string_to_double(STR, NULL, NULL); \ do { \
if (result == -1.0 && PyErr_Occurred()) \ result = PyOS_string_to_double(STR, NULL, NULL); \
return NULL; \ if (result == -1.0 && PyErr_Occurred()) { \
if (result != (double)expected) { \ return NULL; \
msg = "conversion of " STR " to float failed"; \ } \
goto fail; \ if (result != (double)expected) { \
} msg = "conversion of " STR " to float failed"; \
goto fail; \
} \
} while (0)
#define CHECK_INVALID(STR) \ #define CHECK_INVALID(STR) \
result = PyOS_string_to_double(STR, NULL, NULL); \ do { \
if (result == -1.0 && PyErr_Occurred()) { \ result = PyOS_string_to_double(STR, NULL, NULL); \
if (PyErr_ExceptionMatches(PyExc_ValueError)) \ if (result == -1.0 && PyErr_Occurred()) { \
PyErr_Clear(); \ if (PyErr_ExceptionMatches(PyExc_ValueError)) { \
else \ PyErr_Clear(); \
return NULL; \ } \
} \ else { \
else { \ return NULL; \
msg = "conversion of " STR " didn't raise ValueError"; \ } \
goto fail; \ } \
} else { \
msg = "conversion of " STR " didn't raise ValueError"; \
goto fail; \
} \
} while (0)
CHECK_STRING("0.1", 0.1); CHECK_STRING("0.1", 0.1);
CHECK_STRING("1.234", 1.234); CHECK_STRING("1.234", 1.234);
@ -971,16 +985,22 @@ test_capsule(PyObject *self, PyObject *Py_UNUSED(ignored))
}; };
known_capsule *known = &known_capsules[0]; known_capsule *known = &known_capsules[0];
#define FAIL(x) { error = (x); goto exit; } #define FAIL(x) \
do { \
error = (x); \
goto exit; \
} while (0)
#define CHECK_DESTRUCTOR \ #define CHECK_DESTRUCTOR \
if (capsule_error) { \ do { \
FAIL(capsule_error); \ if (capsule_error) { \
} \ FAIL(capsule_error); \
else if (!capsule_destructor_call_count) { \ } \
FAIL("destructor not called!"); \ else if (!capsule_destructor_call_count) { \
} \ FAIL("destructor not called!"); \
capsule_destructor_call_count = 0; \ } \
capsule_destructor_call_count = 0; \
} while (0)
object = PyCapsule_New(capsule_pointer, capsule_name, capsule_destructor); object = PyCapsule_New(capsule_pointer, capsule_name, capsule_destructor);
PyCapsule_SetContext(object, capsule_context); PyCapsule_SetContext(object, capsule_context);
@ -1024,12 +1044,12 @@ test_capsule(PyObject *self, PyObject *Py_UNUSED(ignored))
static char buffer[256]; static char buffer[256];
#undef FAIL #undef FAIL
#define FAIL(x) \ #define FAIL(x) \
{ \ do { \
sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \ sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \
x, known->module, known->attribute); \ x, known->module, known->attribute); \
error = buffer; \ error = buffer; \
goto exit; \ goto exit; \
} \ } while (0)
PyObject *module = PyImport_ImportModule(known->module); PyObject *module = PyImport_ImportModule(known->module);
if (module) { if (module) {
@ -1978,11 +1998,15 @@ test_pythread_tss_key_state(PyObject *self, PyObject *args)
"an already initialized key"); "an already initialized key");
} }
#define CHECK_TSS_API(expr) \ #define CHECK_TSS_API(expr) \
do { \
(void)(expr); \ (void)(expr); \
if (!PyThread_tss_is_created(&tss_key)) { \ if (!PyThread_tss_is_created(&tss_key)) { \
return raiseTestError(self, "test_pythread_tss_key_state", \ return raiseTestError(self, "test_pythread_tss_key_state", \
"TSS key initialization state was not " \ "TSS key initialization state was not " \
"preserved after calling " #expr); } "preserved after calling " #expr); \
} \
} while (0)
CHECK_TSS_API(PyThread_tss_set(&tss_key, NULL)); CHECK_TSS_API(PyThread_tss_set(&tss_key, NULL));
CHECK_TSS_API(PyThread_tss_get(&tss_key)); CHECK_TSS_API(PyThread_tss_get(&tss_key));
#undef CHECK_TSS_API #undef CHECK_TSS_API
@ -2304,7 +2328,7 @@ test_py_setref(PyObject *self, PyObject *Py_UNUSED(ignored))
\ \
Py_DECREF(obj); \ Py_DECREF(obj); \
Py_RETURN_NONE; \ Py_RETURN_NONE; \
} while (0) \ } while (0)
// Test Py_NewRef() and Py_XNewRef() macros // Test Py_NewRef() and Py_XNewRef() macros