mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
revert: "memory: Free buffers after freeing variables" (#26356)
This reverts commit fe30d8ccef
.
The original commit intends to prevent heap-use-after-free with EXITFREE
caused by changedtick_di, which is no longer a problem.
Freeing buffers after freeing variables will cause heap-use-after-free
with EXITFREE when a partial is used as prompt callback.
This commit is contained in:
parent
fedbf32250
commit
387c5ba3de
@ -2643,7 +2643,6 @@ int number_width(win_T *wp)
|
|||||||
/// Set must_redraw only if not already set to a higher value.
|
/// Set must_redraw only if not already set to a higher value.
|
||||||
/// e.g. if must_redraw is UPD_CLEAR, type UPD_NOT_VALID will do nothing.
|
/// e.g. if must_redraw is UPD_CLEAR, type UPD_NOT_VALID will do nothing.
|
||||||
void redraw_later(win_T *wp, int type)
|
void redraw_later(win_T *wp, int type)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
|
||||||
{
|
{
|
||||||
if (!exiting && wp->w_redr_type < type) {
|
if (!exiting && wp->w_redr_type < type) {
|
||||||
wp->w_redr_type = type;
|
wp->w_redr_type = type;
|
||||||
|
@ -782,6 +782,25 @@ void free_all_mem(void)
|
|||||||
// Free all option values. Must come after closing windows.
|
// Free all option values. Must come after closing windows.
|
||||||
free_all_options();
|
free_all_options();
|
||||||
|
|
||||||
|
// Free all buffers. Reset 'autochdir' to avoid accessing things that
|
||||||
|
// were freed already.
|
||||||
|
// Must be after eval_clear to avoid it trying to access b:changedtick after
|
||||||
|
// freeing it.
|
||||||
|
p_acd = false;
|
||||||
|
for (buf = firstbuf; buf != NULL;) {
|
||||||
|
bufref_T bufref;
|
||||||
|
set_bufref(&bufref, buf);
|
||||||
|
nextbuf = buf->b_next;
|
||||||
|
|
||||||
|
// Since options (in addition to other stuff) have been freed above we need to ensure no
|
||||||
|
// callbacks are called, so free them before closing the buffer.
|
||||||
|
buf_free_callbacks(buf);
|
||||||
|
|
||||||
|
close_buffer(NULL, buf, DOBUF_WIPE, false, false);
|
||||||
|
// Didn't work, try next one.
|
||||||
|
buf = bufref_valid(&bufref) ? nextbuf : firstbuf;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear registers.
|
// Clear registers.
|
||||||
clear_registers();
|
clear_registers();
|
||||||
ResetRedobuff();
|
ResetRedobuff();
|
||||||
@ -807,25 +826,6 @@ void free_all_mem(void)
|
|||||||
api_extmark_free_all_mem();
|
api_extmark_free_all_mem();
|
||||||
ctx_free_all();
|
ctx_free_all();
|
||||||
|
|
||||||
// Free all buffers. Reset 'autochdir' to avoid accessing things that
|
|
||||||
// were freed already.
|
|
||||||
// Must be after eval_clear to avoid it trying to access b:changedtick after
|
|
||||||
// freeing it.
|
|
||||||
p_acd = false;
|
|
||||||
for (buf = firstbuf; buf != NULL;) {
|
|
||||||
bufref_T bufref;
|
|
||||||
set_bufref(&bufref, buf);
|
|
||||||
nextbuf = buf->b_next;
|
|
||||||
|
|
||||||
// Since options (in addition to other stuff) have been freed above we need to ensure no
|
|
||||||
// callbacks are called, so free them before closing the buffer.
|
|
||||||
buf_free_callbacks(buf);
|
|
||||||
|
|
||||||
close_buffer(NULL, buf, DOBUF_WIPE, false, false);
|
|
||||||
// Didn't work, try next one.
|
|
||||||
buf = bufref_valid(&bufref) ? nextbuf : firstbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
map_destroy(int, &buffer_handles);
|
map_destroy(int, &buffer_handles);
|
||||||
map_destroy(int, &window_handles);
|
map_destroy(int, &window_handles);
|
||||||
map_destroy(int, &tabpage_handles);
|
map_destroy(int, &tabpage_handles);
|
||||||
|
@ -15,6 +15,7 @@ local Screen = require('test.functional.ui.screen')
|
|||||||
local mkdir = helpers.mkdir
|
local mkdir = helpers.mkdir
|
||||||
local clear = helpers.clear
|
local clear = helpers.clear
|
||||||
local eq = helpers.eq
|
local eq = helpers.eq
|
||||||
|
local exec = helpers.exec
|
||||||
local exc_exec = helpers.exc_exec
|
local exc_exec = helpers.exc_exec
|
||||||
local exec_lua = helpers.exec_lua
|
local exec_lua = helpers.exec_lua
|
||||||
local exec_capture = helpers.exec_capture
|
local exec_capture = helpers.exec_capture
|
||||||
@ -28,6 +29,7 @@ local pcall_err = helpers.pcall_err
|
|||||||
local assert_alive = helpers.assert_alive
|
local assert_alive = helpers.assert_alive
|
||||||
local poke_eventloop = helpers.poke_eventloop
|
local poke_eventloop = helpers.poke_eventloop
|
||||||
local feed = helpers.feed
|
local feed = helpers.feed
|
||||||
|
local expect_exit = helpers.expect_exit
|
||||||
|
|
||||||
describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
|
describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
|
||||||
local max_func_args = 20 -- from eval.h
|
local max_func_args = 20 -- from eval.h
|
||||||
@ -312,3 +314,14 @@ it('no double-free in garbage collection #16287', function()
|
|||||||
sleep(10)
|
sleep(10)
|
||||||
assert_alive()
|
assert_alive()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('no heap-use-after-free with EXITFREE and partial as prompt callback', function()
|
||||||
|
clear()
|
||||||
|
exec([[
|
||||||
|
func PromptCallback(text)
|
||||||
|
endfunc
|
||||||
|
setlocal buftype=prompt
|
||||||
|
call prompt_setcallback('', funcref('PromptCallback'))
|
||||||
|
]])
|
||||||
|
expect_exit(command, 'qall!')
|
||||||
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user