@@ -1282,329 +1282,3 @@ void CheckUninitVar::deadPointerError(const Token *pointer, const Token *alias)
12821282 " deadpointer" ,
12831283 " Dead pointer usage. Pointer '" + strpointer + " ' is dead if it has been assigned '" + stralias + " ' at line " + MathLib::toString (alias ? alias->linenr () : 0U ) + " ." , CWE825, false );
12841284}
1285-
1286- static void writeFunctionArgsXml (const std::list<CheckUninitVar::MyFileInfo::FunctionArg> &list, const std::string &elementName, std::ostream &out)
1287- {
1288- for (std::list<CheckUninitVar::MyFileInfo::FunctionArg>::const_iterator it = list.begin (); it != list.end (); ++it)
1289- out << " <" << elementName
1290- << " id=\" " << it->id << ' \" '
1291- << " functionName=\" " << it->functionName << ' \" '
1292- << " argnr=\" " << it->argnr << ' \" '
1293- << " variableName=\" " << it->variableName << " \" "
1294- << " fileName=\" " << it->location .fileName << ' \" '
1295- << " linenr=\" " << it->location .linenr << ' \" '
1296- << " />\n " ;
1297- }
1298-
1299- std::string CheckUninitVar::MyFileInfo::toString () const
1300- {
1301- std::ostringstream ret;
1302- writeFunctionArgsXml (uninitialized, " uninitialized" , ret);
1303- writeFunctionArgsXml (readData, " readData" , ret);
1304- writeFunctionArgsXml (nullPointer, " nullPointer" , ret);
1305- writeFunctionArgsXml (dereferenced, " dereferenced" , ret);
1306- writeFunctionArgsXml (nestedCall, " nestedCall" , ret);
1307- return ret.str ();
1308- }
1309-
1310- #define FUNCTION_ID (function ) _tokenizer->list.file(function->tokenDef) + ' :' + MathLib::toString(function->tokenDef->linenr ())
1311-
1312- CheckUninitVar::MyFileInfo::FunctionArg::FunctionArg(const Tokenizer *_tokenizer, const Scope *scope, unsigned int argnr_, const Token *tok)
1313- :
1314- id(FUNCTION_ID(scope->function)),
1315- functionName(scope->className),
1316- argnr(argnr_),
1317- argnr2(0 ),
1318- variableName(scope->function->getArgumentVar (argnr-1 )->name())
1319- {
1320- location.fileName = _tokenizer->list .file (tok);
1321- location.linenr = tok->linenr ();
1322- }
1323-
1324- bool CheckUninitVar::isUnsafeFunction (const Scope *scope, int argnr, const Token **tok) const
1325- {
1326- const Variable * const argvar = scope->function ->getArgumentVar (argnr);
1327- if (!argvar->isPointer ())
1328- return false ;
1329- for (const Token *tok2 = scope->classStart ; tok2 != scope->classEnd ; tok2 = tok2->next ()) {
1330- if (Token::simpleMatch (tok2, " ) {" )) {
1331- tok2 = tok2->linkAt (1 );
1332- if (Token::findmatch (tok2->link (), " return|throw" , tok2))
1333- return false ;
1334- if (isVariableChanged (tok2->link (), tok2, argvar->declarationId (), false , _settings))
1335- return false ;
1336- }
1337- if (tok2->variable () != argvar)
1338- continue ;
1339- if (!isVariableUsage (tok2, true , Alloc::ARRAY))
1340- return false ;
1341- *tok = tok2;
1342- return true ;
1343- }
1344- return false ;
1345- }
1346-
1347- static int isCallFunction (const Scope *scope, int argnr, const Token **tok)
1348- {
1349- const Variable * const argvar = scope->function ->getArgumentVar (argnr);
1350- if (!argvar->isPointer ())
1351- return -1 ;
1352- for (const Token *tok2 = scope->classStart ; tok2 != scope->classEnd ; tok2 = tok2->next ()) {
1353- if (tok2->variable () != argvar)
1354- continue ;
1355- if (!Token::Match (tok2->previous (), " [(,] %var% [,)]" ))
1356- break ;
1357- int argnr2 = 1 ;
1358- const Token *prev = tok2;
1359- while (prev && prev->str () != " (" ) {
1360- if (Token::Match (prev," ]|)" ))
1361- prev = prev->link ();
1362- else if (prev->str () == " ," )
1363- ++argnr2;
1364- prev = prev->previous ();
1365- }
1366- if (!prev || !Token::Match (prev->previous (), " %name% (" ))
1367- break ;
1368- if (!prev->astOperand1 () || !prev->astOperand1 ()->function ())
1369- break ;
1370- *tok = prev->previous ();
1371- return argnr2;
1372- }
1373- return -1 ;
1374- }
1375-
1376- Check::FileInfo *CheckUninitVar::getFileInfo (const Tokenizer *tokenizer, const Settings *settings) const
1377- {
1378- const CheckUninitVar checker (tokenizer, settings, nullptr );
1379- return checker.getFileInfo ();
1380- }
1381-
1382- Check::FileInfo *CheckUninitVar::getFileInfo () const
1383- {
1384- const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase ();
1385- std::list<Scope>::const_iterator scope;
1386-
1387- MyFileInfo *fileInfo = new MyFileInfo;
1388-
1389- // Parse all functions in TU
1390- for (scope = symbolDatabase->scopeList .begin (); scope != symbolDatabase->scopeList .end (); ++scope) {
1391- if (!scope->isExecutable () || scope->type != Scope::eFunction || !scope->function )
1392- continue ;
1393- const Function *const function = scope->function ;
1394-
1395- // function calls where uninitialized data is passed by address
1396- for (const Token *tok = scope->classStart ; tok != scope->classEnd ; tok = tok->next ()) {
1397- if (tok->str () != " (" || !tok->astOperand1 () || !tok->astOperand2 ())
1398- continue ;
1399- if (!tok->astOperand1 ()->function ())
1400- continue ;
1401- const std::vector<const Token *> args (getArguments (tok->previous ()));
1402- for (int argnr = 0 ; argnr < args.size (); ++argnr) {
1403- const Token *argtok = args[argnr];
1404- if (!argtok)
1405- continue ;
1406- if (argtok->valueType () && argtok->valueType ()->pointer > 0 ) {
1407- // null pointer..
1408- const ValueFlow::Value *value = argtok->getValue (0 );
1409- if (value && !value->isInconclusive ())
1410- fileInfo->nullPointer .push_back (MyFileInfo::FunctionArg (FUNCTION_ID (tok->astOperand1 ()->function ()), tok->astOperand1 ()->str (), argnr+1 , _tokenizer->list .file (argtok), argtok->linenr (), argtok->str ()));
1411- }
1412- // pointer to uninitialized data..
1413- if (argtok->str () != " &" || argtok->astOperand2 ())
1414- continue ;
1415- argtok = argtok->astOperand1 ();
1416- if (!argtok || !argtok->valueType () || argtok->valueType ()->pointer != 0 )
1417- continue ;
1418- if (argtok->values ().size () != 1U )
1419- continue ;
1420- const ValueFlow::Value &v = argtok->values ().front ();
1421- if (v.valueType != ValueFlow::Value::UNINIT || v.isInconclusive ())
1422- continue ;
1423- fileInfo->uninitialized .push_back (MyFileInfo::FunctionArg (FUNCTION_ID (tok->astOperand1 ()->function ()), tok->astOperand1 ()->str (), argnr+1 , _tokenizer->list .file (argtok), argtok->linenr (), argtok->str ()));
1424- }
1425- }
1426-
1427- // "Unsafe" functions unconditionally reads data before it is written..
1428- CheckNullPointer checkNullPointer (_tokenizer, _settings, _errorLogger);
1429- for (int argnr = 0 ; argnr < function->argCount (); ++argnr) {
1430- const Token *tok;
1431- if (isUnsafeFunction (&*scope, argnr, &tok))
1432- fileInfo->readData .push_back (MyFileInfo::FunctionArg (_tokenizer, &*scope, argnr+1 , tok));
1433- if (checkNullPointer.isUnsafeFunction (&*scope, argnr, &tok))
1434- fileInfo->dereferenced .push_back (MyFileInfo::FunctionArg (_tokenizer, &*scope, argnr+1 , tok));
1435- }
1436-
1437- // Nested function calls
1438- for (int argnr = 0 ; argnr < function->argCount (); ++argnr) {
1439- const Token *tok;
1440- int argnr2 = isCallFunction (&*scope, argnr, &tok);
1441- if (argnr2 > 0 ) {
1442- MyFileInfo::FunctionArg fa (_tokenizer, &*scope, argnr+1 , tok);
1443- fa.id = FUNCTION_ID (function);
1444- fa.id2 = FUNCTION_ID (tok->function ());
1445- fa.argnr2 = argnr2;
1446- fileInfo->nestedCall .push_back (fa);
1447- }
1448- }
1449- }
1450-
1451- return fileInfo;
1452- }
1453-
1454- Check::FileInfo * CheckUninitVar::loadFileInfoFromXml (const tinyxml2::XMLElement *xmlElement) const
1455- {
1456- MyFileInfo *fileInfo = nullptr ;
1457- for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement (); e; e = e->NextSiblingElement ()) {
1458- const char *id = e->Attribute (" id" );
1459- if (!id)
1460- continue ;
1461- const char *functionName = e->Attribute (" functionName" );
1462- if (!functionName)
1463- continue ;
1464- const char *argnr = e->Attribute (" argnr" );
1465- if (!argnr || !MathLib::isInt (argnr))
1466- continue ;
1467- const char *fileName = e->Attribute (" fileName" );
1468- if (!fileName)
1469- continue ;
1470- const char *linenr = e->Attribute (" linenr" );
1471- if (!linenr || !MathLib::isInt (linenr))
1472- continue ;
1473- const char *variableName = e->Attribute (" variableName" );
1474- if (!variableName)
1475- continue ;
1476- const MyFileInfo::FunctionArg fa (id, functionName, MathLib::toLongNumber (argnr), fileName, MathLib::toLongNumber (linenr), variableName);
1477- if (!fileInfo)
1478- fileInfo = new MyFileInfo;
1479- if (std::strcmp (e->Name (), " uninitialized" ) == 0 )
1480- fileInfo->uninitialized .push_back (fa);
1481- else if (std::strcmp (e->Name (), " readData" ) == 0 )
1482- fileInfo->readData .push_back (fa);
1483- else if (std::strcmp (e->Name (), " nullPointer" ) == 0 )
1484- fileInfo->nullPointer .push_back (fa);
1485- else if (std::strcmp (e->Name (), " dereferenced" ) == 0 )
1486- fileInfo->dereferenced .push_back (fa);
1487- else if (std::strcmp (e->Name (), " nestedCall" ) == 0 )
1488- fileInfo->nestedCall .push_back (fa);
1489- else
1490- throw InternalError (nullptr , " Wrong analyze info" );
1491- }
1492- return fileInfo;
1493- }
1494-
1495- static bool findPath (const CheckUninitVar::MyFileInfo::FunctionArg &from,
1496- const CheckUninitVar::MyFileInfo::FunctionArg &to,
1497- const std::map<std::string, std::list<CheckUninitVar::MyFileInfo::FunctionArg>> &nestedCalls)
1498- {
1499- if (from.id == to.id && from.argnr == to.argnr )
1500- return true ;
1501-
1502- const std::map<std::string, std::list<CheckUninitVar::MyFileInfo::FunctionArg>>::const_iterator nc = nestedCalls.find (from.id );
1503- if (nc == nestedCalls.end ())
1504- return false ;
1505-
1506- for (std::list<CheckUninitVar::MyFileInfo::FunctionArg>::const_iterator it = nc->second .begin (); it != nc->second .end (); ++it) {
1507- if (from.id == it->id && from.argnr == it->argnr && it->id2 == to.id && it->argnr2 == to.argnr )
1508- return true ;
1509- }
1510-
1511- return false ;
1512- }
1513-
1514- bool CheckUninitVar::analyseWholeProgram (const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger)
1515- {
1516- (void )settings; // This argument is unused
1517-
1518- // Merge all fileinfo..
1519- MyFileInfo all;
1520- for (std::list<Check::FileInfo *>::const_iterator it = fileInfo.begin (); it != fileInfo.end (); ++it) {
1521- const MyFileInfo *fi = dynamic_cast <MyFileInfo*>(*it);
1522- if (!fi)
1523- continue ;
1524- all.uninitialized .insert (all.uninitialized .end (), fi->uninitialized .begin (), fi->uninitialized .end ());
1525- all.readData .insert (all.readData .end (), fi->readData .begin (), fi->readData .end ());
1526- all.nullPointer .insert (all.nullPointer .end (), fi->nullPointer .begin (), fi->nullPointer .end ());
1527- all.dereferenced .insert (all.dereferenced .end (), fi->dereferenced .begin (), fi->dereferenced .end ());
1528- all.nestedCall .insert (all.nestedCall .end (), fi->nestedCall .begin (), fi->nestedCall .end ());
1529- }
1530-
1531- bool foundErrors = false ;
1532-
1533- std::map<std::string, std::list<CheckUninitVar::MyFileInfo::FunctionArg>> nestedCalls;
1534- for (std::list<CheckUninitVar::MyFileInfo::FunctionArg>::const_iterator it = all.nestedCall .begin (); it != all.nestedCall .end (); ++it) {
1535- std::list<CheckUninitVar::MyFileInfo::FunctionArg> &list = nestedCalls[it->id ];
1536- list.push_back (*it);
1537- }
1538-
1539- for (std::list<CheckUninitVar::MyFileInfo::FunctionArg>::const_iterator it1 = all.uninitialized .begin (); it1 != all.uninitialized .end (); ++it1) {
1540- const CheckUninitVar::MyFileInfo::FunctionArg &uninitialized = *it1;
1541- for (std::list<CheckUninitVar::MyFileInfo::FunctionArg>::const_iterator it2 = all.readData .begin (); it2 != all.readData .end (); ++it2) {
1542- const CheckUninitVar::MyFileInfo::FunctionArg &readData = *it2;
1543-
1544- if (!findPath (*it1, *it2, nestedCalls))
1545- continue ;
1546-
1547- ErrorLogger::ErrorMessage::FileLocation fileLoc1;
1548- fileLoc1.setfile (uninitialized.location .fileName );
1549- fileLoc1.line = uninitialized.location .linenr ;
1550- fileLoc1.setinfo (" Calling function " + uninitialized.functionName + " , variable " + uninitialized.variableName + " is uninitialized" );
1551-
1552- ErrorLogger::ErrorMessage::FileLocation fileLoc2;
1553- fileLoc2.setfile (readData.location .fileName );
1554- fileLoc2.line = readData.location .linenr ;
1555- fileLoc2.setinfo (" Using argument " + readData.variableName );
1556-
1557- std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
1558- locationList.push_back (fileLoc1);
1559- locationList.push_back (fileLoc2);
1560-
1561- const ErrorLogger::ErrorMessage errmsg (locationList,
1562- emptyString,
1563- Severity::error,
1564- " using argument " + readData.variableName + " that points at uninitialized variable " + uninitialized.variableName ,
1565- " ctuuninitvar" ,
1566- CWE908, false );
1567- errorLogger.reportErr (errmsg);
1568-
1569- foundErrors = true ;
1570- }
1571- }
1572-
1573- // Null pointer checking
1574- // TODO: This does not belong here.
1575- for (std::list<CheckUninitVar::MyFileInfo::FunctionArg>::const_iterator it1 = all.nullPointer .begin (); it1 != all.nullPointer .end (); ++it1) {
1576- const CheckUninitVar::MyFileInfo::FunctionArg &nullPointer = *it1;
1577- for (std::list<CheckUninitVar::MyFileInfo::FunctionArg>::const_iterator it2 = all.dereferenced .begin (); it2 != all.dereferenced .end (); ++it2) {
1578- const CheckUninitVar::MyFileInfo::FunctionArg &dereference = *it2;
1579-
1580- if (!findPath (*it1, *it2, nestedCalls))
1581- continue ;
1582-
1583- ErrorLogger::ErrorMessage::FileLocation fileLoc1;
1584- fileLoc1.setfile (nullPointer.location .fileName );
1585- fileLoc1.line = nullPointer.location .linenr ;
1586- fileLoc1.setinfo (" Calling function " + nullPointer.functionName + " , " + MathLib::toString (nullPointer.argnr ) + getOrdinalText (nullPointer.argnr ) + " argument is null" );
1587-
1588- ErrorLogger::ErrorMessage::FileLocation fileLoc2;
1589- fileLoc2.setfile (dereference.location .fileName );
1590- fileLoc2.line = dereference.location .linenr ;
1591- fileLoc2.setinfo (" Dereferencing argument " + dereference.variableName + " that is null" );
1592-
1593- std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
1594- locationList.push_back (fileLoc1);
1595- locationList.push_back (fileLoc2);
1596-
1597- const ErrorLogger::ErrorMessage errmsg (locationList,
1598- emptyString,
1599- Severity::error,
1600- " Null pointer dereference: " + dereference.variableName ,
1601- " ctunullpointer" ,
1602- CWE476, false );
1603- errorLogger.reportErr (errmsg);
1604-
1605- foundErrors = true ;
1606- }
1607- }
1608-
1609- return foundErrors;
1610- }
0 commit comments