From 49a43e69c6ca442956f894029d0d8e2acae8b041 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Wed, 5 May 2021 15:06:18 -0400 Subject: [PATCH] Fix: ctf: free all scopes of ctf_scanner When parsing using a ctf_scanner does not complete, because an error is encountered, ctf_scanner_free does not properly free all the scopes allocated by and held by ctf_scanner. This can be observed on an ASan-enabled build of Babeltrace. Create a test/metadata file with: /* CTF 1.8 */ trace {} and run: $ LIBBABELTRACE2_NO_DLCLOSE=1 ./src/cli/babeltrace2 query src.ctf.fs metadata-info -p 'path=test' I get: Direct leak of 16 byte(s) in 1 object(s) allocated from: #0 0x7ffff7677459 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145 #1 0x7ffff35605b9 in push_scope /home/simark/src/babeltrace/src/plugins/ctf/common/metadata/parser.y:296 #2 0x7ffff356726f in yyparse /home/simark/src/babeltrace/src/plugins/ctf/common/metadata/parser.y:1478 #3 0x7ffff3563297 in ctf_scanner_append_ast /home/simark/src/babeltrace/src/plugins/ctf/common/metadata/parser.y:958 #4 0x7ffff3598a6a in ctf_metadata_decoder_append_content /home/simark/src/babeltrace/src/plugins/ctf/common/metadata/decoder.c:277 #5 0x7ffff3626fff in metadata_info_query /home/simark/src/babeltrace/src/plugins/ctf/fs-src/query.c:118 #6 0x7ffff3625ac1 in ctf_fs_query /home/simark/src/babeltrace/src/plugins/ctf/fs-src/fs.c:2454 #7 0x7ffff74a616d in bt_query_executor_query /home/simark/src/babeltrace/src/lib/graph/query-executor.c:219 #8 0x5555555a09e2 in cli_query /home/simark/src/babeltrace/src/cli/babeltrace2-query.c:62 #9 0x555555574fb3 in query /home/simark/src/babeltrace/src/cli/babeltrace2.c:113 #10 0x5555555775c6 in cmd_query /home/simark/src/babeltrace/src/cli/babeltrace2.c:645 #11 0x555555582ae7 in main /home/simark/src/babeltrace/src/cli/babeltrace2.c:2682 #12 0x7ffff70ebb24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24) What happens is: while parsing, push_scope is called to allocate a new scope and make it current (ctf_scanner::cs). The previous current scope becomes the parent of the new scope. When everything goes right, pop_scope is called as many times as push_scope is called, freeing all the scopes created during parsing. ctf_scanner_free doesn't need to free any scopes in that case. However, if parsing ends early to due to an error, ctf_scanner_free is called on a scanner that may have some scopes that were pushed and not popped. If so, it needs to free them. Change it to start freeing ctf_scanner::cs (the innermost scope) and then go up the chain. The last scope in that chain is ctf_scanner::root_scope. This one doesn't need free'ing, as its storage is allocate within the ctf_scanner structure, but it still needs finalizing. Change-Id: I3a1b83af8128cd1b8a3ee235311dd41e45e29ea2 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/5692 Reviewed-by: Philippe Proulx --- src/plugins/ctf/common/metadata/parser.y | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/plugins/ctf/common/metadata/parser.y b/src/plugins/ctf/common/metadata/parser.y index bada61d7..a75cff05 100644 --- a/src/plugins/ctf/common/metadata/parser.y +++ b/src/plugins/ctf/common/metadata/parser.y @@ -1001,7 +1001,24 @@ void ctf_scanner_free(struct ctf_scanner *scanner) if (!scanner) return; - finalize_scope(&scanner->root_scope); + + struct ctf_scanner_scope *scope = scanner->cs; + + do { + struct ctf_scanner_scope *parent = scope->parent; + finalize_scope(scope); + + /* + * The root scope is allocated within the ctf_scanner structure, + * do doesn't need freeing. All others are allocated on their + * own. + */ + if (scope != &scanner->root_scope) + free(scope); + + scope = parent; + } while (scope); + objstack_destroy(scanner->objstack); ret = yylex_destroy(scanner->scanner); if (ret) -- 2.34.1