Commit 7d5a54c
authored
Fix #14877: heap-use-after-free in Tokenizer::simplifyUsing() (#8679)
In a large codebase, constructs like `using C = struct C { C() {} };`
lead to errors such as `Code.cpp:0:0: error: Bailing out from analysis:
Checking file failed: out of memory [internalError]`.
When compiling cppcheck using clang 22's address sanitizer, the analysis
terminates with the following messages:
```
=================================================================
==1390963==ERROR: AddressSanitizer: heap-use-after-free on address 0x7c985f8ff900 at pc 0x55dcbe530972 bp 0x7ffd79cf5010 sp 0x7ffd79cf5008
READ of size 8 at 0x7c985f8ff900 thread T0
#0 0x55dcbe530971 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::size() const /usr/include/c++/bits/basic_string.h:1165:19
#1 0x55dcbe53c624 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::length() const /usr/include/c++/bits/basic_string.h:1176:16
#2 0x55dcbe54f8d6 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /usr/include/c++/bits/basic_string.tcc:313:36
#3 0x55dcbe54f7f0 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /usr/include/c++/bits/basic_string.h:1771:8
#4 0x55dcbe54f7bc in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::operator=(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /usr/include/c++/bits/basic_string.h:906:15
#5 0x55dcbe635d19 in Tokenizer::simplifyUsing() ./src/cppcheck/lib/tokenize.cpp:3214:32
#6 0x55dcbe6470b3 in Tokenizer::simplifyTokenList1(char const*) ./src/cppcheck/lib/tokenize.cpp:5910:12
#7 0x55dcbe643cb8 in Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, int) ./src/cppcheck/lib/tokenize.cpp:3527:14
#8 0x55dcbedb37e7 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::function<simplecpp::TokenList (std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::list<simplecpp::Output, std::allocator<simplecpp::Output>>*)> const&) ./src/cppcheck/lib/cppcheck.cpp:1203:32
#9 0x55dcbeda7bf4 in CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) ./src/cppcheck/lib/cppcheck.cpp:898:12
#10 0x55dcbeda7862 in CppCheck::check(FileWithDetails const&) ./src/cppcheck/lib/cppcheck.cpp:802:23
#11 0x55dcbf294ce0 in SingleExecutor::check() ./src/cppcheck/cli/singleexecutor.cpp:52:29
#12 0x55dcbf23cf66 in CppCheckExecutor::check_internal(Settings const&, Suppressions&) const ./src/cppcheck/cli/cppcheckexecutor.cpp:453:32
#13 0x55dcbf23c4fc in CppCheckExecutor::check_wrapper(Settings const&, Suppressions&) ./src/cppcheck/cli/cppcheckexecutor.cpp:295:12
#14 0x55dcbf23c1af in CppCheckExecutor::check(int, char const* const*) ./src/cppcheck/cli/cppcheckexecutor.cpp:280:21
#15 0x55dcbf23b67d in main ./src/cppcheck/cli/main.cpp:71:17
#16 0x7fe8606517e4 in __libc_start_main (/lib64/libc.so.6+0x3a7e4) (BuildId: b81415c1738806b536fb1599d7af2d15bf6a86b7)
#17 0x55dcbe317bed in _start (./src/cppcheck/build/bin/cppcheck+0x4bbbed)
0x7c985f8ff900 is located 32 bytes inside of 112-byte region [0x7c985f8ff8e0,0x7c985f8ff950)
freed by thread T0 here:
#0 0x55dcbe4642ba in operator delete(void*) /usr/local/src/conda/compiler-rt-packages-22.1.8/compiler-rt/lib/asan/asan_new_delete.cpp:177:44
#1 0x55dcbf144bd0 in Token::deleteNext(int) ./src/cppcheck/lib/token.cpp:281:9
#2 0x55dcbf145e2d in Token::deleteThis() ./src/cppcheck/lib/token.cpp:360:9
#3 0x55dcbe634c84 in Tokenizer::simplifyUsing() ./src/cppcheck/lib/tokenize.cpp:3086:18
#4 0x55dcbe6470b3 in Tokenizer::simplifyTokenList1(char const*) ./src/cppcheck/lib/tokenize.cpp:5910:12
#5 0x55dcbe643cb8 in Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, int) ./src/cppcheck/lib/tokenize.cpp:3527:14
#6 0x55dcbedb37e7 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::function<simplecpp::TokenList (std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::list<simplecpp::Output, std::allocator<simplecpp::Output>>*)> const&) ./src/cppcheck/lib/cppcheck.cpp:1203:32
#7 0x55dcbeda7bf4 in CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) ./src/cppcheck/lib/cppcheck.cpp:898:12
#8 0x55dcbeda7862 in CppCheck::check(FileWithDetails const&) ./src/cppcheck/lib/cppcheck.cpp:802:23
#9 0x55dcbf294ce0 in SingleExecutor::check() ./src/cppcheck/cli/singleexecutor.cpp:52:29
#10 0x55dcbf23cf66 in CppCheckExecutor::check_internal(Settings const&, Suppressions&) const ./src/cppcheck/cli/cppcheckexecutor.cpp:453:32
#11 0x55dcbf23c4fc in CppCheckExecutor::check_wrapper(Settings const&, Suppressions&) ./src/cppcheck/cli/cppcheckexecutor.cpp:295:12
#12 0x55dcbf23c1af in CppCheckExecutor::check(int, char const* const*) ./src/cppcheck/cli/cppcheckexecutor.cpp:280:21
#13 0x55dcbf23b67d in main ./src/cppcheck/cli/main.cpp:71:17
#14 0x7fe8606517e4 in __libc_start_main (/lib64/libc.so.6+0x3a7e4) (BuildId: b81415c1738806b536fb1599d7af2d15bf6a86b7)
previously allocated by thread T0 here:
#0 0x55dcbe4638aa in operator new(unsigned long) /usr/local/src/conda/compiler-rt-packages-22.1.8/compiler-rt/lib/asan/asan_new_delete.cpp:109:35
#1 0x55dcbf14fb4a in Token::insertToken(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, bool) ./src/cppcheck/lib/token.cpp:1069:20
#2 0x55dcbe758b2e in Token::insertToken(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) ./src/cppcheck/lib/token.h:991:16
#3 0x55dcbf18de6e in TokenList::createTokens(simplecpp::TokenList&&) ./src/cppcheck/lib/tokenlist.cpp:392:37
#4 0x55dcbedc8c03 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::function<simplecpp::TokenList (std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::list<simplecpp::Output, std::allocator<simplecpp::Output>>*)> const&)::$_2::operator()() const ./src/cppcheck/lib/cppcheck.cpp:1157:35
#5 0x55dcbedb9322 in void Timer::run<CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::function<simplecpp::TokenList (std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::list<simplecpp::Output, std::allocator<simplecpp::Output>>*)> const&)::$_2>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, TimerResultsIntf*, CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::function<simplecpp::TokenList (std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::list<simplecpp::Output, std::allocator<simplecpp::Output>>*)> const&)::$_2 const&) ./src/cppcheck/lib/timer.h:77:9
#6 0x55dcbedb2f65 in CppCheck::checkInternal(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&, std::function<simplecpp::TokenList (std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::list<simplecpp::Output, std::allocator<simplecpp::Output>>*)> const&) ./src/cppcheck/lib/cppcheck.cpp:1152:17
#7 0x55dcbeda7bf4 in CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) ./src/cppcheck/lib/cppcheck.cpp:898:12
#8 0x55dcbeda7862 in CppCheck::check(FileWithDetails const&) ./src/cppcheck/lib/cppcheck.cpp:802:23
#9 0x55dcbf294ce0 in SingleExecutor::check() ./src/cppcheck/cli/singleexecutor.cpp:52:29
#10 0x55dcbf23cf66 in CppCheckExecutor::check_internal(Settings const&, Suppressions&) const ./src/cppcheck/cli/cppcheckexecutor.cpp:453:32
#11 0x55dcbf23c4fc in CppCheckExecutor::check_wrapper(Settings const&, Suppressions&) ./src/cppcheck/cli/cppcheckexecutor.cpp:295:12
#12 0x55dcbf23c1af in CppCheckExecutor::check(int, char const* const*) ./src/cppcheck/cli/cppcheckexecutor.cpp:280:21
#13 0x55dcbf23b67d in main ./src/cppcheck/cli/main.cpp:71:17
#14 0x7fe8606517e4 in __libc_start_main (/lib64/libc.so.6+0x3a7e4) (BuildId: b81415c1738806b536fb1599d7af2d15bf6a86b7)
SUMMARY: AddressSanitizer: heap-use-after-free ./src/cppcheck/lib/tokenize.cpp:3214:32 in Tokenizer::simplifyUsing()
Shadow bytes around the buggy address:
0x7c985f8ff680: fd fa fa fa fa fa fa fa fa fa fd fd fd fd fd fd
0x7c985f8ff700: fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa fa
0x7c985f8ff780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa fa
0x7c985f8ff800: fa fa fa fa fa fa 00 00 00 00 00 00 00 00 00 00
0x7c985f8ff880: 00 00 00 fa fa fa fa fa fa fa fa fa fd fd fd fd
=>0x7c985f8ff900:[fd]fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
0x7c985f8ff980: fa fa fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x7c985f8ffa00: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x7c985f8ffa80: fd fd fd fd fd fd fa fa fa fa fa fa fa fa 00 00
0x7c985f8ffb00: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa
0x7c985f8ffb80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1390963==ABORTING
```
The proposed fix avoids storing a reference to a memory area that will
eventually be deallocated before the reference is used.1 parent 86f4c91 commit 7d5a54c
3 files changed
Lines changed: 10 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
| 159 | + | |
159 | 160 | | |
160 | 161 | | |
161 | 162 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3015 | 3015 | | |
3016 | 3016 | | |
3017 | 3017 | | |
3018 | | - | |
3019 | 3018 | | |
3020 | 3019 | | |
3021 | 3020 | | |
| |||
3064 | 3063 | | |
3065 | 3064 | | |
3066 | 3065 | | |
3067 | | - | |
| 3066 | + | |
3068 | 3067 | | |
3069 | 3068 | | |
3070 | 3069 | | |
| |||
3211 | 3210 | | |
3212 | 3211 | | |
3213 | 3212 | | |
3214 | | - | |
| 3213 | + | |
3215 | 3214 | | |
3216 | 3215 | | |
3217 | 3216 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
| 101 | + | |
101 | 102 | | |
102 | 103 | | |
103 | 104 | | |
| |||
1667 | 1668 | | |
1668 | 1669 | | |
1669 | 1670 | | |
| 1671 | + | |
| 1672 | + | |
| 1673 | + | |
| 1674 | + | |
| 1675 | + | |
| 1676 | + | |
1670 | 1677 | | |
1671 | 1678 | | |
1672 | 1679 | | |
| |||
0 commit comments