commit 6bee2f686fcfd190e7017fc08115de247ac9afe9
parent 6a71239cd5ea2a8e993bddd8e7765d1afe3e79e4
Author: glepnir <glephunter@gmail.com>
Date: Thu, 12 Jun 2025 06:31:48 +0800
fix(shada): prevent use-after-free when mapping file marks (#34446)
Problem: When ignore_buf skips buffers during initialization,
shada_read_when_writing uses entry.data.filemark.fname directly
as map key, but later frees the entry, leaving dangling pointers.
Solution: Always create independent copies of filenames as map keys
using xstrdup() for new items, and free all keys during cleanup.
Fix #34440
Diffstat:
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
@@ -1906,7 +1906,11 @@ static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_
}
const char *const fname = entry.data.filemark.fname;
cstr_t *key = NULL;
- ptr_t *val = pmap_put_ref(cstr_t)(&wms->file_marks, fname, &key, NULL);
+ bool new_item = false;
+ ptr_t *val = pmap_put_ref(cstr_t)(&wms->file_marks, fname, &key, &new_item);
+ if (new_item) {
+ *key = xstrdup(fname);
+ }
if (*val == NULL) {
*val = xcalloc(1, sizeof(FileMarks));
}
@@ -2530,7 +2534,12 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
}
const void *local_marks_iter = NULL;
const char *const fname = buf->b_ffname;
- ptr_t *val = pmap_put_ref(cstr_t)(&wms->file_marks, fname, NULL, NULL);
+ cstr_t *map_key = NULL;
+ bool new_item = false;
+ ptr_t *val = pmap_put_ref(cstr_t)(&wms->file_marks, fname, &map_key, &new_item);
+ if (new_item) {
+ *map_key = xstrdup(fname);
+ }
if (*val == NULL) {
*val = xcalloc(1, sizeof(FileMarks));
}
@@ -2711,7 +2720,9 @@ shada_write_exit:
hms_dealloc(&wms->hms[i]);
}
}
- map_foreach_value(&wms->file_marks, val, {
+ const char *stored_key = NULL;
+ map_foreach(&wms->file_marks, stored_key, val, {
+ xfree((char *)stored_key);
xfree(val);
})
map_destroy(cstr_t, &wms->file_marks);