Skip to content

Commit 131c3b6

Browse files
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.
1 parent f62050d commit 131c3b6

3 files changed

Lines changed: 28 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix :c:func:`PyInitConfig_GetStrList` and :c:func:`PyInitConfig_SetStrList`
2+
for empty string lists on platforms where ``malloc(0)`` returns ``NULL``.
3+
Previously these APIs could spuriously report out-of-memory for a valid
4+
empty list.

Programs/_testembed.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,8 @@ static int test_initconfig_get_api(void)
18721872
char **items;
18731873
assert(PyInitConfig_GetStrList(config, "xoptions", &length, &items) == 0);
18741874
assert(length == 0);
1875+
assert(items == NULL);
1876+
PyInitConfig_FreeStrList(length, items);
18751877

18761878
char* xoptions[] = {"faulthandler"};
18771879
assert(PyInitConfig_SetStrList(config, "xoptions",
@@ -1882,6 +1884,14 @@ static int test_initconfig_get_api(void)
18821884
assert(strcmp(items[0], "faulthandler") == 0);
18831885
PyInitConfig_FreeStrList(length, items);
18841886

1887+
// Setting an empty list must succeed even on platforms where malloc(0)
1888+
// returns NULL, and must round-trip through GetStrList().
1889+
assert(PyInitConfig_SetStrList(config, "xoptions", 0, NULL) == 0);
1890+
assert(PyInitConfig_GetStrList(config, "xoptions", &length, &items) == 0);
1891+
assert(length == 0);
1892+
assert(items == NULL);
1893+
PyInitConfig_FreeStrList(length, items);
1894+
18851895
// Setting hash_seed sets use_hash_seed
18861896
assert(initconfig_getint(config, "use_hash_seed") == 0);
18871897
assert(PyInitConfig_SetInt(config, "hash_seed", 123) == 0);

Python/initconfig.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4213,6 +4213,12 @@ PyInitConfig_GetStrList(PyInitConfig *config, const char *name, size_t *length,
42134213
PyWideStringList *list = raw_member;
42144214
*length = list->length;
42154215

4216+
// Don't call malloc(0): it may return NULL on some platforms.
4217+
if (list->length == 0) {
4218+
*items = NULL;
4219+
return 0;
4220+
}
4221+
42164222
*items = malloc(list->length * sizeof(char*));
42174223
if (*items == NULL) {
42184224
config->status = _PyStatus_NO_MEMORY();
@@ -4408,6 +4414,14 @@ initconfig_set_str_list(PyInitConfig *config, PyWideStringList *list,
44084414
Py_ssize_t length, char * const *items)
44094415
{
44104416
PyWideStringList wlist = _PyWideStringList_INIT;
4417+
4418+
// Don't call malloc(0): it may return NULL on some platforms.
4419+
if (length == 0) {
4420+
initconfig_free_wstr_list(list);
4421+
*list = wlist;
4422+
return 0;
4423+
}
4424+
44114425
size_t size = sizeof(wchar_t*) * length;
44124426
wlist.items = (wchar_t **)malloc(size);
44134427
if (wlist.items == NULL) {

0 commit comments

Comments
 (0)