pipe-loader: fix driconf memory management

this had a number of issues:
* pipe_loader_get_driinfo_xml() frees driver_driconf immediately,
  except the driOptionCache struct string pointers are all just copied
  in merge_driconf instead of having the strings copied, which means any
  subsequent access of driver_driconf strings is invalid access
* pipe_loader_drm_get_driconf_by_name() is a disaster that only happened
  to work because the dlopen here is the same lib that gets opened elsewhere
  by mesa and not closed. if the lib here is actually closed, then all
  the statically allocated strings become invalid, which means they need to
  be manually copied

cc: mesa-stable

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30494>
(cherry picked from commit 0c220741e6)
This commit is contained in:
Mike Blumenkrantz 2024-08-05 12:05:42 -04:00 committed by Eric Engestrom
parent 53005aead9
commit 9a1327f2ec
3 changed files with 36 additions and 2 deletions

View file

@ -4504,7 +4504,7 @@
"description": "pipe-loader: fix driconf memory management",
"nominated": true,
"nomination_type": 0,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": null,
"notes": null

View file

@ -159,10 +159,10 @@ pipe_loader_get_driinfo_xml(const char *driver_name)
unsigned merged_count;
const driOptionDescription *merged_driconf =
merge_driconf(driver_driconf, driver_count, &merged_count);
free((void *)driver_driconf);
char *xml = driGetOptionsXml(merged_driconf, merged_count);
free((void *)driver_driconf);
free((void *)merged_driconf);
return xml;

View file

@ -350,8 +350,42 @@ pipe_loader_drm_get_driconf_by_name(const char *driver_name, unsigned *count)
} else {
*count = dd->driconf_count;
size_t size = sizeof(*driconf) * *count;
size_t base_size = size;
/* factor in all the statically allocated string lengths */
for (unsigned i = 0; i < dd->driconf_count; i++) {
if (dd->driconf[i].desc)
size += strlen(dd->driconf[i].desc) + 1;
if (dd->driconf[i].info.name)
size += strlen(dd->driconf[i].info.name) + 1;
if (dd->driconf[i].info.type == DRI_STRING)
size += strlen(dd->driconf[i].value._string) + 1;
}
driconf = malloc(size);
memcpy(driconf, dd->driconf, size);
uint8_t *ptr = (void*)driconf;
ptr += base_size;
/* manually set up pointers and copy in all the statically allocated strings */
for (unsigned i = 0; i < dd->driconf_count; i++) {
if (dd->driconf[i].desc) {
driconf[i].desc = (void*)ptr;
size_t str_size = strlen(dd->driconf[i].desc) + 1;
memcpy((void*)driconf[i].desc, dd->driconf[i].desc, str_size);
ptr += str_size;
}
if (dd->driconf[i].info.name) {
driconf[i].info.name = (void*)ptr;
size_t str_size = strlen(dd->driconf[i].info.name) + 1;
memcpy((void*)driconf[i].info.name, dd->driconf[i].info.name, str_size);
ptr += str_size;
}
if (dd->driconf[i].info.type == DRI_STRING) {
driconf[i].value._string = (void*)ptr;
size_t str_size = strlen(dd->driconf[i].value._string) + 1;
memcpy((void*)driconf[i].value._string, dd->driconf[i].value._string, str_size);
ptr += str_size;
}
}
}
if (lib)
util_dl_close(lib);