From 861aade680925a240e6f5ae2ba29513abc1eb8f6 Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 8 May 2020 12:05:34 +0900 Subject: [PATCH 1/3] viml/profile: fix use after free fixes #12255. --- src/nvim/ex_cmds2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index fbdd64e43e..a6bc32581f 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1045,9 +1045,10 @@ static void profile_reset(void) uf->uf_tm_self = profile_zero(); uf->uf_tm_children = profile_zero(); - XFREE_CLEAR(uf->uf_tml_count); - XFREE_CLEAR(uf->uf_tml_total); - XFREE_CLEAR(uf->uf_tml_self); + for (int i = 0; i < uf->uf_lines.ga_len; i++) { + uf->uf_tml_count[i] = 0; + uf->uf_tml_total[i] = uf->uf_tml_self[i] = 0; + } uf->uf_tml_start = profile_zero(); uf->uf_tml_children = profile_zero(); From 949783fdfaf937d8ac4a88c82e432c5613ae2634 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 9 May 2020 11:17:59 +0900 Subject: [PATCH 2/3] viml/profile: fix issue where profile is not reset on stop --- src/nvim/ex_cmds2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index a6bc32581f..9f4055af8d 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1038,7 +1038,7 @@ static void profile_reset(void) if (!HASHITEM_EMPTY(hi)) { n--; ufunc_T *uf = HI2UF(hi); - if (uf->uf_profiling) { + if (uf->uf_prof_initialized) { uf->uf_profiling = 0; uf->uf_tm_count = 0; uf->uf_tm_total = profile_zero(); From 7872877ce537389df6fb461bfda23c823acca5fe Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 9 May 2020 11:57:59 +0900 Subject: [PATCH 3/3] test: add more profile tests - Add a test to make sure that 'profile dump' does not reset the profile. - Add a test to make sure that 'profile stop' does reset the profile. --- test/functional/ex_cmds/profile_spec.lua | 76 ++++++++++++++++++++---- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index f185db192a..2b92f8d0de 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -6,6 +6,9 @@ local eval = helpers.eval local command = helpers.command local eq, neq = helpers.eq, helpers.neq local tempfile = helpers.tmpname() +local source = helpers.source +local matches = helpers.matches +local read_file = helpers.read_file -- tmpname() also creates the file on POSIX systems. Remove it again. -- We just need the name, ignoring any race conditions. @@ -32,20 +35,67 @@ describe(':profile', function() end end) - it('dump', function() - eq(0, eval('v:profiling')) - command('profile start ' .. tempfile) - eq(1, eval('v:profiling')) - assert_file_exists_not(tempfile) - command('profile dump') - assert_file_exists(tempfile) + describe('dump', function() + it('works', function() + eq(0, eval('v:profiling')) + command('profile start ' .. tempfile) + eq(1, eval('v:profiling')) + assert_file_exists_not(tempfile) + command('profile dump') + assert_file_exists(tempfile) + end) + + it('not resetting the profile', function() + source([[ + function! Test() + endfunction + ]]) + command('profile start ' .. tempfile) + assert_file_exists_not(tempfile) + command('profile func Test') + command('call Test()') + command('profile dump') + assert_file_exists(tempfile) + local profile = read_file(tempfile) + matches('Called 1 time', profile) + command('call Test()') + command('profile dump') + assert_file_exists(tempfile) + profile = read_file(tempfile) + matches('Called 2 time', profile) + command('profile stop') + end) end) - it('stop', function() - command('profile start ' .. tempfile) - assert_file_exists_not(tempfile) - command('profile stop') - assert_file_exists(tempfile) - eq(0, eval('v:profiling')) + describe('stop', function() + it('works', function() + command('profile start ' .. tempfile) + assert_file_exists_not(tempfile) + command('profile stop') + assert_file_exists(tempfile) + eq(0, eval('v:profiling')) + end) + + it('resetting the profile', function() + source([[ + function! Test() + endfunction + ]]) + command('profile start ' .. tempfile) + assert_file_exists_not(tempfile) + command('profile func Test') + command('call Test()') + command('profile stop') + assert_file_exists(tempfile) + local profile = read_file(tempfile) + matches('Called 1 time', profile) + command('profile start ' .. tempfile) + command('profile func Test') + command('call Test()') + command('profile stop') + assert_file_exists(tempfile) + profile = read_file(tempfile) + matches('Called 1 time', profile) + end) end) end)