Skip to content

Fix heap-use-after-free in Tokenizer::simplifyUsing()#8679

Open
GilmarSantosJr wants to merge 1 commit into
cppcheck-opensource:mainfrom
GilmarSantosJr:main
Open

Fix heap-use-after-free in Tokenizer::simplifyUsing()#8679
GilmarSantosJr wants to merge 1 commit into
cppcheck-opensource:mainfrom
GilmarSantosJr:main

Conversation

@GilmarSantosJr

Copy link
Copy Markdown

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.

@chrchr-github

Copy link
Copy Markdown
Collaborator

Thanks for your contribution. Please move the test to testsimplifyusing.cpp.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants