mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
misc: fix crashes and leaks in wayland, drm, replay index and drivers (#19630)
Small, independent fixes for crashes and leaks on reachable paths: - wayland: gfx_ctx_wl_get_video_size_common dereferenced a NULL output when no window output was set and all_outputs was empty. The DnD drop handler leaked the received buffer when fmemopen failed, and always leaked the line getline allocated. - drm: drm_plane_setup logged a NULL drmModeGetPlaneResources result and then dereferenced it. init_drm read `connector` uninitialised when the card reported no connectors. - uint32s_index (replay statestream): uint32s_bucket_free left the freed pointer and length in the bucket. RHMAP_CLEAR keeps value slots, so a later RHMAP_PTR on the same slot could see them and free the vector again. uint32s_index_pop now also refuses an empty index and checks RHMAP_HAS before RHMAP_PTR, which would otherwise create a bucket for a missing hash. - ozone: ozone_context_reset_horizontal_list allocated a node for an entry without one but never stored it in the list, so it leaked. - discord: discord_json_next_strdup leaked the previous string when a key repeated. - core_backup: core_backup_add_entry leaked an empty filename. - audioworklet, caca, sixel, vga: the init functions leaked their struct when the second allocation or the font renderer failed. Tested on Linux: full build. The touched Linux files show no new warnings; the C89 build of the Wayland and DRM files fails on this host in system headers and existing lines, with no diagnostic on a changed line. drm_gfx.c was compiled although HAVE_PLAIN_DRM is off. samples/tasks/core_backup passes. The audioworklet, caca, sixel and vga drivers are not buildable here and were not compiled. Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
ffa4ec336a
commit
67c857e163
11 files changed
+71
-5
No files matched your search
@@ -300,7 +300,10 @@ static void *audioworklet_init(const char *device, unsigned rate,
|
||||
return NULL;
|
||||
audioworklet->worklet_stack = memalign(16, WORKLET_STACK_SIZE);
|
||||
if (!audioworklet->worklet_stack)
|
||||
{
|
||||
free(audioworklet);
|
||||
return NULL;
|
||||
}
|
||||
audioworklet_static_data = audioworklet;
|
||||
|
||||
audioworklet->latency = latency;
|
||||
|
||||
+6
-1
@@ -379,8 +379,13 @@ static bool core_backup_add_entry(core_backup_list_t *backup_list,
|
||||
return false;
|
||||
|
||||
backup_filename = strdup(path_basename(backup_path));
|
||||
if (!backup_filename || !*backup_filename)
|
||||
if (!backup_filename)
|
||||
return false;
|
||||
if (!*backup_filename)
|
||||
{
|
||||
free(backup_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Ensure base backup filename matches core */
|
||||
if (!string_starts_with(backup_filename, core_filename))
|
||||
|
||||
@@ -414,6 +414,12 @@ void gfx_ctx_wl_get_video_size_common(void *data, unsigned *dims)
|
||||
break;
|
||||
};
|
||||
|
||||
/* all_outputs may legitimately be empty (last monitor was hot-
|
||||
* unplugged before frame size was queried); leave the caller's
|
||||
* dims unchanged rather than NULL-deref oi. */
|
||||
if (!oi)
|
||||
return;
|
||||
|
||||
*dims = oi->dims;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -89,7 +89,10 @@ static void *caca_font_init(void *data,
|
||||
if (!font_renderer_create_default(
|
||||
&font->font_driver,
|
||||
&font->font_data, font_path, font_size, FONT_ATLAS_FORMAT_A8))
|
||||
{
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
@@ -476,6 +476,7 @@ static void drm_plane_setup(struct drm_surface *surface)
|
||||
if (!plane_resources)
|
||||
{
|
||||
RARCH_ERR("[DRM] No scaling planes available.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
RARCH_LOG("[DRM] Number of planes on FD %d is %d.\n",
|
||||
@@ -639,7 +640,7 @@ static int modeset_create_dumbfb(int fd, struct modeset_buf *buf,
|
||||
static bool init_drm(void)
|
||||
{
|
||||
uint i;
|
||||
drmModeConnector *connector;
|
||||
drmModeConnector *connector = NULL;
|
||||
struct modeset_buf buf;
|
||||
|
||||
drm.fd = open("/dev/dri/card0", O_RDWR);
|
||||
|
||||
@@ -93,7 +93,10 @@ static void *sixel_font_init(void *data,
|
||||
if (!font_renderer_create_default(
|
||||
&font->font_driver,
|
||||
&font->font_data, font_path, font_size, FONT_ATLAS_FORMAT_A8))
|
||||
{
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,10 @@ static void *vga_font_init(void *data,
|
||||
if (!font_renderer_create_default(
|
||||
&font->font_driver,
|
||||
&font->font_data, font_path, font_size, FONT_ATLAS_FORMAT_A8))
|
||||
{
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,16 @@ uint32s_index_t *uint32s_index_new(size_t object_size,
|
||||
void uint32s_bucket_free(struct uint32s_bucket *bucket)
|
||||
{
|
||||
if (bucket->len > 3)
|
||||
{
|
||||
free(bucket->contents.vec.idxs);
|
||||
bucket->contents.vec.idxs = NULL;
|
||||
bucket->contents.vec.cap = 0;
|
||||
}
|
||||
/* RHMAP_CLEAR leaves value-array entries untouched; subsequent
|
||||
* RHMAP_PTR (which auto-creates) on the cleared slot would re-read
|
||||
* the stale len/vec.idxs and double-free. Reset len to 0 so the
|
||||
* bucket is unambiguously inline-empty after free. */
|
||||
bucket->len = 0;
|
||||
}
|
||||
|
||||
bool uint32s_bucket_get(uint32s_index_t *index, struct uint32s_bucket *bucket, uint32_t *object, size_t size_bytes, uint32_t *out_idx)
|
||||
@@ -280,9 +289,28 @@ uint32_t *uint32s_index_get(uint32s_index_t *index, uint32_t which)
|
||||
|
||||
void uint32s_index_pop(uint32s_index_t *index)
|
||||
{
|
||||
uint32_t idx = RBUF_LEN(index->objects)-1;
|
||||
uint32_t hash = index->hashes[idx];
|
||||
if (index->objects[idx] != NULL) {
|
||||
uint32_t idx;
|
||||
uint32_t hash;
|
||||
/* Trust boundary: BSV replay file controls index state. Bail before
|
||||
* RBUF_LEN(...)-1 underflows to UINT32_MAX (turning the next line
|
||||
* into a wild read of index->hashes[]). */
|
||||
if (RBUF_LEN(index->objects) == 0)
|
||||
{
|
||||
RARCH_ERR("[STATESTREAM] trying to pop from empty index\n");
|
||||
return;
|
||||
}
|
||||
idx = RBUF_LEN(index->objects) - 1;
|
||||
hash = index->hashes[idx];
|
||||
/* RHMAP_PTR has add-on-miss semantics; gate on RHMAP_HAS so a
|
||||
* corrupted hashes[] entry that points to a no-longer-present hash
|
||||
* can't auto-create a stale-content bucket and fall through into
|
||||
* uint32s_bucket_remove with garbage len. The counts are still
|
||||
* adjusted below, so uint32s_index_remove_after keeps making
|
||||
* progress. */
|
||||
if (index->objects[idx] != NULL && !RHMAP_HAS(index->index, hash))
|
||||
RARCH_ERR("[STATESTREAM] pop: missing hash %x for idx %u\n",
|
||||
hash, idx);
|
||||
else if (index->objects[idx] != NULL) {
|
||||
struct uint32s_bucket *bucket = RHMAP_PTR(index->index, hash);
|
||||
uint32_t old_len = bucket->len;
|
||||
if (old_len == 0)
|
||||
|
||||
@@ -1110,6 +1110,7 @@ static void wl_data_device_handle_drop(void *data,
|
||||
if (!(stream = fmemopen(buffer, __len, "r")))
|
||||
{
|
||||
RARCH_WARN("[Wayland] Failed to open DnD buffer.\n");
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1127,6 +1128,8 @@ static void wl_data_device_handle_drop(void *data,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* getline allocates line on the first call and reuses it. */
|
||||
free(line);
|
||||
fclose(stream);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -5338,8 +5338,14 @@ static void ozone_context_reset_horizontal_list(ozone_handle_t *ozone)
|
||||
ozone_node_t *node = (ozone_node_t*)ozone->horizontal_list.list[i].userdata;
|
||||
|
||||
if (!node)
|
||||
{
|
||||
if (!(node = ozone_alloc_node()))
|
||||
continue;
|
||||
/* Store the new node in the list, which owns and frees it.
|
||||
* Otherwise it is only reachable from playlist_db_node_map,
|
||||
* which does not free its values, or from nothing at all. */
|
||||
ozone->horizontal_list.list[i].userdata = node;
|
||||
}
|
||||
|
||||
if (!(path = ozone->horizontal_list.list[i].path))
|
||||
continue;
|
||||
|
||||
@@ -859,7 +859,12 @@ static void discord_json_next_strdup(rjson_t *r, char **out)
|
||||
{
|
||||
const char *s = rjson_get_string(r, NULL);
|
||||
if (s)
|
||||
{
|
||||
/* A payload that repeats a key would otherwise leak the
|
||||
* previous copy. */
|
||||
free(*out);
|
||||
*out = strdup(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user