Running Cppcheck 1b807e1f1a9da3ad62d32ba07197e7d394f9bbd7 on the C++ source below produces a use-after-free warning from Valgrind (or, when enabled at build-time, ASan) because simplifyUsing has some overlap in token ranges for the two using expressions.
usinga=b;usingc=d;
$ valgrind./bin/cppchecktest.cpp==722153== Memcheck, a memory error detector==722153== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.==722153== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info==722153== Command: ./bin/cppcheck test.cpp==722153== Checking test.cpp ...==722153== Invalid read of size 8==722153== at 0x20AC8E: Token::next() (token.h:900)==722153== by 0x2C5CAE: Tokenizer::simplifyUsing() (tokenize.cpp:3396)==722153== by 0x2D5EF2: Tokenizer::simplifyTokenList1(char const*) (tokenize.cpp:5739)==722153== by 0x2C6999: Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (tokenize.cpp:3438)==722153== by 0x61EFCA: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*) (cppcheck.cpp:1157)==722153== by 0x61B88F: CppCheck::check(FileWithDetails const&) (cppcheck.cpp:776)==722153== by 0x1ACE75: SingleExecutor::check() (singleexecutor.cpp:53)==722153== by 0x17EB52: CppCheckExecutor::check_internal(Settings const&) const (cppcheckexecutor.cpp:438)==722153== by 0x17E396: CppCheckExecutor::check_wrapper(Settings const&) (cppcheckexecutor.cpp:377)==722153== by 0x17E295: CppCheckExecutor::check(int, char const* const*) (cppcheckexecutor.cpp:363)==722153== by 0x14960B: main (main.cpp:90)==722153== Address 0x53d1158 is 40 bytes inside a block of size 96 free'd==722153== at 0x484C41B: operator delete(void*) (vg_replace_malloc.c:1051)==722153== by 0x80A860: Token::deletePrevious(int) (token.cpp:277)==722153== by 0x80AE29: Token::deleteThis() (token.cpp:340)==722153== by 0x2C5C9D: Tokenizer::simplifyUsing() (tokenize.cpp:3393)==722153== by 0x2D5EF2: Tokenizer::simplifyTokenList1(char const*) (tokenize.cpp:5739)==722153== by 0x2C6999: Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (tokenize.cpp:3438)==722153== by 0x61EFCA: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*) (cppcheck.cpp:1157)==722153== by 0x61B88F: CppCheck::check(FileWithDetails const&) (cppcheck.cpp:776)==722153== by 0x1ACE75: SingleExecutor::check() (singleexecutor.cpp:53)==722153== by 0x17EB52: CppCheckExecutor::check_internal(Settings const&) const (cppcheckexecutor.cpp:438)==722153== by 0x17E396: CppCheckExecutor::check_wrapper(Settings const&) (cppcheckexecutor.cpp:377)==722153== by 0x17E295: CppCheckExecutor::check(int, char const* const*) (cppcheckexecutor.cpp:363)==722153== Block was alloc'd at==722153== at 0x4848F75: operator new(unsigned long) (vg_replace_malloc.c:483)==722153== by 0x80D6BC: Token::insertToken(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) (token.cpp:1044)==722153== by 0x830A9E: TokenList::createTokens(simplecpp::TokenList&&) (tokenlist.cpp:402)==722153== by 0x61C657: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}::operator()() const (cppcheck.cpp:1131)==722153== by 0x629491: void std::__invoke_impl<void, CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&>(std::__invoke_other, CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&) (invoke.h:61)==722153== by 0x628F39: std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&> >::value, void>::type std::__invoke_r<void, CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&>(CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&) (invoke.h:154)==722153== by 0x628623: std::_Function_handler<void (), CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}>::_M_invoke(std::_Any_data const&) (std_function.h:290)==722153== by 0x3197AF: std::function<void ()>::operator()() const (std_function.h:590)==722153== by 0x315A7D: Timer::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, SHOWTIME_MODES, TimerResultsIntf*, std::function<void ()> const&) (timer.h:86)==722153== by 0x61ED4E: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*) (cppcheck.cpp:1129)==722153== by 0x61B88F: CppCheck::check(FileWithDetails const&) (cppcheck.cpp:776)==722153== by 0x1ACE75: SingleExecutor::check() (singleexecutor.cpp:53)==722153== ==722153== Invalid read of size 8==722153== at 0x20AC8E: Token::next() (token.h:900)==722153== by 0x2C5CC7: Tokenizer::simplifyUsing() (tokenize.cpp:3397)==722153== by 0x2D5EF2: Tokenizer::simplifyTokenList1(char const*) (tokenize.cpp:5739)==722153== by 0x2C6999: Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (tokenize.cpp:3438)==722153== by 0x61EFCA: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*) (cppcheck.cpp:1157)==722153== by 0x61B88F: CppCheck::check(FileWithDetails const&) (cppcheck.cpp:776)==722153== by 0x1ACE75: SingleExecutor::check() (singleexecutor.cpp:53)==722153== by 0x17EB52: CppCheckExecutor::check_internal(Settings const&) const (cppcheckexecutor.cpp:438)==722153== by 0x17E396: CppCheckExecutor::check_wrapper(Settings const&) (cppcheckexecutor.cpp:377)==722153== by 0x17E295: CppCheckExecutor::check(int, char const* const*) (cppcheckexecutor.cpp:363)==722153== by 0x14960B: main (main.cpp:90)==722153== Address 0x53d1158 is 40 bytes inside a block of size 96 free'd==722153== at 0x484C41B: operator delete(void*) (vg_replace_malloc.c:1051)==722153== by 0x80A860: Token::deletePrevious(int) (token.cpp:277)==722153== by 0x80AE29: Token::deleteThis() (token.cpp:340)==722153== by 0x2C5C9D: Tokenizer::simplifyUsing() (tokenize.cpp:3393)==722153== by 0x2D5EF2: Tokenizer::simplifyTokenList1(char const*) (tokenize.cpp:5739)==722153== by 0x2C6999: Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (tokenize.cpp:3438)==722153== by 0x61EFCA: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*) (cppcheck.cpp:1157)==722153== by 0x61B88F: CppCheck::check(FileWithDetails const&) (cppcheck.cpp:776)==722153== by 0x1ACE75: SingleExecutor::check() (singleexecutor.cpp:53)==722153== by 0x17EB52: CppCheckExecutor::check_internal(Settings const&) const (cppcheckexecutor.cpp:438)==722153== by 0x17E396: CppCheckExecutor::check_wrapper(Settings const&) (cppcheckexecutor.cpp:377)==722153== by 0x17E295: CppCheckExecutor::check(int, char const* const*) (cppcheckexecutor.cpp:363)==722153== Block was alloc'd at==722153== at 0x4848F75: operator new(unsigned long) (vg_replace_malloc.c:483)==722153== by 0x80D6BC: Token::insertToken(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) (token.cpp:1044)==722153== by 0x830A9E: TokenList::createTokens(simplecpp::TokenList&&) (tokenlist.cpp:402)==722153== by 0x61C657: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}::operator()() const (cppcheck.cpp:1131)==722153== by 0x629491: void std::__invoke_impl<void, CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&>(std::__invoke_other, CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&) (invoke.h:61)==722153== by 0x628F39: std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&> >::value, void>::type std::__invoke_r<void, CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&>(CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}&) (invoke.h:154)==722153== by 0x628623: std::_Function_handler<void (), CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*)::{lambda()#4}>::_M_invoke(std::_Any_data const&) (std_function.h:290)==722153== by 0x3197AF: std::function<void ()>::operator()() const (std_function.h:590)==722153== by 0x315A7D: Timer::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, SHOWTIME_MODES, TimerResultsIntf*, std::function<void ()> const&) (timer.h:86)==722153== by 0x61ED4E: CppCheck::checkFile(FileWithDetails const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream*) (cppcheck.cpp:1129)==722153== by 0x61B88F: CppCheck::check(FileWithDetails const&) (cppcheck.cpp:776)==722153== by 0x1ACE75: SingleExecutor::check() (singleexecutor.cpp:53)==722153== ==722153== ==722153== HEAP SUMMARY:==722153== in use at exit: 0 bytes in 0 blocks==722153== total heap usage: 27,050 allocs, 27,050 frees, 4,449,911 bytes allocated==722153== ==722153== All heap blocks were freed -- no leaks are possible==722153== ==722153== For lists of detected and suppressed errors, rerun with: -s
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Running Cppcheck 1b807e1f1a9da3ad62d32ba07197e7d394f9bbd7 on the C++ source below produces a use-after-free warning from Valgrind (or, when enabled at build-time, ASan) because
simplifyUsing
has some overlap in token ranges for the twousing
expressions.A ticket was filed about this: https://trac.cppcheck.net/ticket/13492 (and already fixed).
Amazing, thanks!