Skip to content

Commit 4d18f3e

Browse files
Fix use-after-free crash when using --clang (#5367)
Still ran into an assert failure in `Tokenizer::hasIfdef()`, since some checks assume that the tokenizer is always present. Seems like clangimport is yet another rogue under-tested feature...
1 parent 737e2f2 commit 4d18f3e

5 files changed

Lines changed: 57 additions & 5 deletions

File tree

lib/checkvaarg.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ void CheckVaarg::va_start_argument()
6767
if (var && var->isReference())
6868
referenceAs_va_start_error(param2, var->name());
6969
if (var && var->index() + 2 < function->argCount() && printWarnings) {
70-
wrongParameterTo_va_start_error(tok, var->name(), function->argumentList[function->argumentList.size()-2].name());
70+
auto it = function->argumentList.end();
71+
std::advance(it, -2);
72+
wrongParameterTo_va_start_error(tok, var->name(), it->name()); // cppcheck-suppress derefInvalidIterator // FP due to isVariableChangedByFunctionCall()
7173
}
7274
tok = tok->linkAt(1);
7375
}

lib/clangimport.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1373,7 +1373,6 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
13731373
function->nestedIn = nestedIn;
13741374
function->argDef = par1;
13751375
// Function arguments
1376-
function->argumentList.reserve(children.size());
13771376
for (int i = 0; i < children.size(); ++i) {
13781377
AstNodePtr child = children[i];
13791378
if (child->nodeType != ParmVarDecl)

lib/symboldatabase.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4427,8 +4427,11 @@ const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType
44274427

44284428
const Variable* Function::getArgumentVar(nonneg int num) const
44294429
{
4430-
if (num < argumentList.size())
4431-
return &argumentList[num];
4430+
if (num < argumentList.size()) {
4431+
auto it = argumentList.begin();
4432+
std::advance(it, num);
4433+
return &*it;
4434+
}
44324435
return nullptr;
44334436
}
44344437

lib/symboldatabase.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,7 @@ class CPPCHECKLIB Function {
907907
const ::Type* retType{}; ///< function return type
908908
const Scope* functionScope{}; ///< scope of function body
909909
const Scope* nestedIn{}; ///< Scope the function is declared in
910-
std::vector<Variable> argumentList; ///< argument list
910+
std::list<Variable> argumentList; ///< argument list, must remain list due to clangimport usage!
911911
nonneg int initArgCount{}; ///< number of args with default values
912912
Type type = eFunction; ///< constructor, destructor, ...
913913
const Token* noexceptArg{}; ///< noexcept token

test/testclangimport.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ class TestClangImport : public TestFixture {
134134

135135
TEST_CASE(valueType1);
136136
TEST_CASE(valueType2);
137+
138+
TEST_CASE(crash);
137139
}
138140

139141
std::string parse(const char clang[]) {
@@ -1314,6 +1316,52 @@ class TestClangImport : public TestFixture {
13141316
ASSERT(!!tok->valueType());
13151317
ASSERT_EQUALS("const signed char *", tok->valueType()->str());
13161318
}
1319+
1320+
void crash() {
1321+
const char* clang = "TranslationUnitDecl 0x56037914f998 <<invalid sloc>> <invalid sloc>\n"
1322+
"|-TypedefDecl 0x560379150200 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'\n"
1323+
"| `-BuiltinType 0x56037914ff60 '__int128'\n"
1324+
"|-TypedefDecl 0x560379150270 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'\n"
1325+
"| `-BuiltinType 0x56037914ff80 'unsigned __int128'\n"
1326+
"|-TypedefDecl 0x5603791505e8 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'\n"
1327+
"| `-RecordType 0x560379150360 '__NSConstantString_tag'\n"
1328+
"| `-CXXRecord 0x5603791502c8 '__NSConstantString_tag'\n"
1329+
"|-TypedefDecl 0x560379150680 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'\n"
1330+
"| `-PointerType 0x560379150640 'char *'\n"
1331+
"| `-BuiltinType 0x56037914fa40 'char'\n"
1332+
"|-TypedefDecl 0x5603791968f8 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag[1]'\n"
1333+
"| `-ConstantArrayType 0x5603791968a0 '__va_list_tag[1]' 1 \n"
1334+
"| `-RecordType 0x560379150770 '__va_list_tag'\n"
1335+
"| `-CXXRecord 0x5603791506d8 '__va_list_tag'\n"
1336+
"|-ClassTemplateDecl 0x560379196b58 <test1.cpp:1:1, col:50> col:37 A\n"
1337+
"| |-TemplateTypeParmDecl 0x560379196950 <col:11> col:19 typename depth 0 index 0\n"
1338+
"| |-TemplateTypeParmDecl 0x5603791969f8 <col:21> col:29 typename depth 0 index 1\n"
1339+
"| `-CXXRecordDecl 0x560379196ac8 <col:31, col:50> col:37 class A definition\n"
1340+
"| |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init\n"
1341+
"| | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr\n"
1342+
"| | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param\n"
1343+
"| | |-MoveConstructor exists simple trivial needs_implicit\n"
1344+
"| | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param\n"
1345+
"| | |-MoveAssignment exists simple trivial needs_implicit\n"
1346+
"| | `-Destructor simple irrelevant trivial needs_implicit\n"
1347+
"| |-CXXRecordDecl 0x560379196de0 <col:31, col:37> col:37 implicit referenced class A\n"
1348+
"| `-CXXRecordDecl 0x560379196e70 <col:41, col:47> col:47 class b\n"
1349+
"|-CXXRecordDecl 0x560379197110 parent 0x560379196ac8 prev 0x560379196e70 <line:2:1, col:63> col:50 class b definition\n"
1350+
"| |-DefinitionData empty standard_layout trivially_copyable has_user_declared_ctor can_const_default_init\n"
1351+
"| | |-DefaultConstructor defaulted_is_constexpr\n"
1352+
"| | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param\n"
1353+
"| | |-MoveConstructor exists simple trivial needs_implicit\n"
1354+
"| | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param\n"
1355+
"| | |-MoveAssignment exists simple trivial needs_implicit\n"
1356+
"| | `-Destructor simple irrelevant trivial needs_implicit\n"
1357+
"| |-CXXRecordDecl 0x560379197250 <col:35, col:50> col:50 implicit referenced class b\n"
1358+
"| `-CXXConstructorDecl 0x5603791974b8 <col:54, col:60> col:54 b 'void (A<type-parameter-0-0, type-parameter-0-1> &)'\n"
1359+
"| `-ParmVarDecl 0x560379197380 <col:56, col:59> col:59 a 'A<type-parameter-0-0, type-parameter-0-1> &'\n"
1360+
"`-CXXConstructorDecl 0x5603791b5600 parent 0x560379197110 prev 0x5603791974b8 <line:3:1, col:55> col:47 b 'void (A<type-parameter-0-0, type-parameter-0-1> &)'\n"
1361+
" |-ParmVarDecl 0x5603791b5570 <col:49, col:51> col:52 'A<type-parameter-0-0, type-parameter-0-1> &'\n"
1362+
" `-CompoundStmt 0x5603791b5700 <col:54, col:55>\n";
1363+
parse(clang); // don't crash
1364+
}
13171365
};
13181366

13191367
REGISTER_TEST(TestClangImport)

0 commit comments

Comments
 (0)