From 131c3b6ff03b37e0d63b4a8e6a86bbbbf97e943c Mon Sep 17 00:00:00 2001 From: AayushMainali-Github Date: Thu, 16 Jul 2026 18:18:10 +0000 Subject: [PATCH] gh-153691: Fix empty-list handling in PyInitConfig_*StrList malloc(0) may return NULL on some platforms. Treat empty string lists as a successful no-allocation result instead of out-of-memory. --- .../2026-07-16-18-30-00.gh-issue-153691.kP4nWm.rst | 4 ++++ Programs/_testembed.c | 10 ++++++++++ Python/initconfig.c | 14 ++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 Misc/NEWS.d/next/C_API/2026-07-16-18-30-00.gh-issue-153691.kP4nWm.rst diff --git a/Misc/NEWS.d/next/C_API/2026-07-16-18-30-00.gh-issue-153691.kP4nWm.rst b/Misc/NEWS.d/next/C_API/2026-07-16-18-30-00.gh-issue-153691.kP4nWm.rst new file mode 100644 index 00000000000000..15f9edc53c5c38 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-07-16-18-30-00.gh-issue-153691.kP4nWm.rst @@ -0,0 +1,4 @@ +Fix :c:func:`PyInitConfig_GetStrList` and :c:func:`PyInitConfig_SetStrList` +for empty string lists on platforms where ``malloc(0)`` returns ``NULL``. +Previously these APIs could spuriously report out-of-memory for a valid +empty list. diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 418609abc5f6b8..be03ea28525456 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -1872,6 +1872,8 @@ static int test_initconfig_get_api(void) char **items; assert(PyInitConfig_GetStrList(config, "xoptions", &length, &items) == 0); assert(length == 0); + assert(items == NULL); + PyInitConfig_FreeStrList(length, items); char* xoptions[] = {"faulthandler"}; assert(PyInitConfig_SetStrList(config, "xoptions", @@ -1882,6 +1884,14 @@ static int test_initconfig_get_api(void) assert(strcmp(items[0], "faulthandler") == 0); PyInitConfig_FreeStrList(length, items); + // Setting an empty list must succeed even on platforms where malloc(0) + // returns NULL, and must round-trip through GetStrList(). + assert(PyInitConfig_SetStrList(config, "xoptions", 0, NULL) == 0); + assert(PyInitConfig_GetStrList(config, "xoptions", &length, &items) == 0); + assert(length == 0); + assert(items == NULL); + PyInitConfig_FreeStrList(length, items); + // Setting hash_seed sets use_hash_seed assert(initconfig_getint(config, "use_hash_seed") == 0); assert(PyInitConfig_SetInt(config, "hash_seed", 123) == 0); diff --git a/Python/initconfig.c b/Python/initconfig.c index b9bacb17a66454..aac0fb7b7eeb96 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -4213,6 +4213,12 @@ PyInitConfig_GetStrList(PyInitConfig *config, const char *name, size_t *length, PyWideStringList *list = raw_member; *length = list->length; + // Don't call malloc(0): it may return NULL on some platforms. + if (list->length == 0) { + *items = NULL; + return 0; + } + *items = malloc(list->length * sizeof(char*)); if (*items == NULL) { config->status = _PyStatus_NO_MEMORY(); @@ -4408,6 +4414,14 @@ initconfig_set_str_list(PyInitConfig *config, PyWideStringList *list, Py_ssize_t length, char * const *items) { PyWideStringList wlist = _PyWideStringList_INIT; + + // Don't call malloc(0): it may return NULL on some platforms. + if (length == 0) { + initconfig_free_wstr_list(list); + *list = wlist; + return 0; + } + size_t size = sizeof(wchar_t*) * length; wlist.items = (wchar_t **)malloc(size); if (wlist.items == NULL) {