Skip to content

Commit 4e5f06b

Browse files
committed
core_info: gate string_split on strdup success in CCJSONStringHandler
CCJSONStringHandler in core_info.c had an unchecked strdup whose result fed directly into string_split, which NULL-derefs on NULL input: *pCtx->current_string_val = strdup(pValue); if (pCtx->current_string_list_val) { if (*pCtx->current_string_list_val) string_list_free(*pCtx->current_string_list_val); *pCtx->current_string_list_val = string_split(*pCtx->current_string_val, "|"); } On strdup OOM, *current_string_val = NULL. string_split in libretro-common/lists/string_list.c does: struct string_list *string_split(const char *str, const char *delim) { const char *p = str; struct string_list *list = string_list_new(); if (!list) return NULL; while (*p) /* NULL-deref on str == NULL */ { ... There's no NULL-check on str before dereferencing via p. So strdup OOM -> string_split segfault. Fix: gate the entire string_split block on '*pCtx->current_string_val' being non-NULL. Consequence on OOM: the string_list for this field is not updated (*current_string_list_val retains its previous value, which could be NULL if it was never set or a valid list if this field has been parsed before - either is fine for downstream consumers, which already NULL-guard the list per the deep- copy pattern in core_info_copy). === Swept-clean in the same pass across small modules === - camera/drivers/video4linux2.c (3 sites), pipewire.c (2 sites), ffmpeg.c (1), android.c (1): all NULL-checked. - record/record_driver.c (1 site) and record/drivers/ record_wav.c / record_ffmpeg.c (1 each): all NULL-checked. - location/drivers/android.c (1 site): NULL-checked. - bluetooth/drivers/bluez.c / bluetoothctl.c (1 each): return calloc() directly without NULL-check, but the caller in bluetooth/bluetooth_driver.c does bt_st->data = bt_st->drv->init(); if (!bt_st->data) bt_st->active = false; so the NULL return is handled - these driver init functions are intentionally minimal. - disk_control.c: zero alloc sites. - disk_index_file.c (1 site): strdup in DCifJSONStringHandler, but downstream readers NULL-guard context.image_path, so strdup failure produces empty image_path - graceful degradation, not a crash. - core_info.c other 44 sites: all NULL-checked. Includes the deep-copy strdups in core_info_copy which use the conditional '? strdup(src->x) : NULL' pattern (strdup failure produces NULL, downstream tolerates). core_info_cache_list_new has a two-stage alloc with proper cleanup. core_info_path_list_ new has bulk NULL-check after four parallel callocs. - core_updater_list.c (14 sites): all NULL-checked, proper tmp-pattern reallocs for each remote/local path buffer. - core_backup.c (4 sites): all NULL-checked. Reachability: strdup OOM in JSON parsing is rare but possible. This code path fires during core info parsing at startup - a failure here would previously crash the core scanner silently on memory-starved devices; post-patch the scanner continues with a missing list field. Thread-safety: core info parsing runs on the core scanner task thread, single-threaded per scan. No concurrency concerns.
1 parent 8fd7aa4 commit 4e5f06b

1 file changed

Lines changed: 9 additions & 1 deletion

File tree

core_info.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,15 @@ static bool CCJSONStringHandler(void *context,
307307
free(*pCtx->current_string_val);
308308
*pCtx->current_string_val = strdup(pValue);
309309

310-
if (pCtx->current_string_list_val)
310+
/* Gate the string_list split on strdup success: if strdup
311+
* returned NULL (OOM), the assignment above stored NULL
312+
* into *current_string_val, and string_split dereferences
313+
* its first parameter unconditionally at
314+
* libretro-common/lists/string_list.c:252 ('while (*p)' with
315+
* p = str). On OOM just leave current_string_list_val
316+
* alone; downstream core_info readers already tolerate
317+
* missing split lists. */
318+
if (pCtx->current_string_list_val && *pCtx->current_string_val)
311319
{
312320
if (*pCtx->current_string_list_val)
313321
string_list_free(*pCtx->current_string_list_val);

0 commit comments

Comments
 (0)