Skip to content

Commit f790009

Browse files
authored
Fix infinite loop with circular includes (#497)
1 parent 1678b7d commit f790009

File tree

3 files changed

+99
-51
lines changed

3 files changed

+99
-51
lines changed

simplecpp.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3109,15 +3109,13 @@ bool simplecpp::FileDataCache::getFileId(const std::string &path, FileID &id)
31093109
#endif
31103110
}
31113111

3112-
simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, std::vector<std::string> &filenames, const simplecpp::DUI &dui, simplecpp::OutputList *outputList)
3112+
simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens, std::vector<std::string> &filenames, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, FileDataCache cache)
31133113
{
31143114
#ifdef SIMPLECPP_WINDOWS
31153115
if (dui.clearIncludeCache)
31163116
nonExistingFilesCache.clear();
31173117
#endif
31183118

3119-
FileDataCache cache;
3120-
31213119
std::list<const Token *> filelist;
31223120

31233121
// -include files
@@ -3173,15 +3171,21 @@ simplecpp::FileDataCache simplecpp::load(const simplecpp::TokenList &rawtokens,
31733171
const bool systemheader = (htok->str()[0] == '<');
31743172
const std::string header(htok->str().substr(1U, htok->str().size() - 2U));
31753173

3176-
FileData *const filedata = cache.get(sourcefile, header, dui, systemheader, filenames, outputList).first;
3177-
if (!filedata)
3174+
const auto loadResult = cache.get(sourcefile, header, dui, systemheader, filenames, outputList);
3175+
const bool loaded = loadResult.second;
3176+
3177+
if (!loaded)
3178+
continue;
3179+
3180+
FileData *const filedata = loadResult.first;
3181+
3182+
if (!filedata->tokens.front())
31783183
continue;
31793184

31803185
if (dui.removeComments)
31813186
filedata->tokens.removeComments();
31823187

3183-
if (filedata->tokens.front())
3184-
filelist.push_back(filedata->tokens.front());
3188+
filelist.push_back(filedata->tokens.front());
31853189
}
31863190

31873191
return cache;

simplecpp.h

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -353,49 +353,6 @@ namespace simplecpp {
353353
bool removeComments; /** remove comment tokens from included files */
354354
};
355355

356-
SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str);
357-
358-
SIMPLECPP_LIB FileDataCache load(const TokenList &rawtokens, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList = nullptr);
359-
360-
/**
361-
* Preprocess
362-
* @todo simplify interface
363-
* @param output TokenList that receives the preprocessing output
364-
* @param rawtokens Raw tokenlist for top sourcefile
365-
* @param files internal data of simplecpp
366-
* @param cache output from simplecpp::load()
367-
* @param dui defines, undefs, and include paths
368-
* @param outputList output: list that will receive output messages
369-
* @param macroUsage output: macro usage
370-
* @param ifCond output: #if/#elif expressions
371-
*/
372-
SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector<std::string> &files, FileDataCache &cache, const DUI &dui, OutputList *outputList = nullptr, std::list<MacroUsage> *macroUsage = nullptr, std::list<IfCond> *ifCond = nullptr);
373-
374-
/**
375-
* Deallocate data
376-
*/
377-
SIMPLECPP_LIB void cleanup(FileDataCache &cache);
378-
379-
/** Simplify path */
380-
SIMPLECPP_LIB std::string simplifyPath(std::string path);
381-
382-
/** Convert Cygwin path to Windows path */
383-
SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath);
384-
385-
/** Returns the C version a given standard */
386-
SIMPLECPP_LIB cstd_t getCStd(const std::string &std);
387-
388-
/** Returns the C++ version a given standard */
389-
SIMPLECPP_LIB cppstd_t getCppStd(const std::string &std);
390-
391-
/** Returns the __STDC_VERSION__ value for a given standard */
392-
SIMPLECPP_LIB std::string getCStdString(const std::string &std);
393-
SIMPLECPP_LIB std::string getCStdString(cstd_t std);
394-
395-
/** Returns the __cplusplus value for a given standard */
396-
SIMPLECPP_LIB std::string getCppStdString(const std::string &std);
397-
SIMPLECPP_LIB std::string getCppStdString(cppstd_t std);
398-
399356
struct SIMPLECPP_LIB FileData {
400357
/** The canonical filename associated with this data */
401358
std::string filename;
@@ -503,8 +460,50 @@ namespace simplecpp {
503460
container_type mData;
504461
name_map_type mNameMap;
505462
id_map_type mIdMap;
506-
507463
};
464+
465+
SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str);
466+
467+
SIMPLECPP_LIB FileDataCache load(const TokenList &rawtokens, std::vector<std::string> &filenames, const DUI &dui, OutputList *outputList = nullptr, FileDataCache cache = {});
468+
469+
/**
470+
* Preprocess
471+
* @todo simplify interface
472+
* @param output TokenList that receives the preprocessing output
473+
* @param rawtokens Raw tokenlist for top sourcefile
474+
* @param files internal data of simplecpp
475+
* @param cache output from simplecpp::load()
476+
* @param dui defines, undefs, and include paths
477+
* @param outputList output: list that will receive output messages
478+
* @param macroUsage output: macro usage
479+
* @param ifCond output: #if/#elif expressions
480+
*/
481+
SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector<std::string> &files, FileDataCache &cache, const DUI &dui, OutputList *outputList = nullptr, std::list<MacroUsage> *macroUsage = nullptr, std::list<IfCond> *ifCond = nullptr);
482+
483+
/**
484+
* Deallocate data
485+
*/
486+
SIMPLECPP_LIB void cleanup(FileDataCache &cache);
487+
488+
/** Simplify path */
489+
SIMPLECPP_LIB std::string simplifyPath(std::string path);
490+
491+
/** Convert Cygwin path to Windows path */
492+
SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath);
493+
494+
/** Returns the C version a given standard */
495+
SIMPLECPP_LIB cstd_t getCStd(const std::string &std);
496+
497+
/** Returns the C++ version a given standard */
498+
SIMPLECPP_LIB cppstd_t getCppStd(const std::string &std);
499+
500+
/** Returns the __STDC_VERSION__ value for a given standard */
501+
SIMPLECPP_LIB std::string getCStdString(const std::string &std);
502+
SIMPLECPP_LIB std::string getCStdString(cstd_t std);
503+
504+
/** Returns the __cplusplus value for a given standard */
505+
SIMPLECPP_LIB std::string getCppStdString(const std::string &std);
506+
SIMPLECPP_LIB std::string getCppStdString(cppstd_t std);
508507
}
509508

510509
#if defined(_MSC_VER)

test.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <sstream>
1414
#include <stdexcept>
1515
#include <string>
16+
#include <utility>
1617
#include <vector>
1718

1819
#define STRINGIZE_(x) #x
@@ -2087,6 +2088,49 @@ static void systemInclude()
20872088
ASSERT_EQUALS("", toString(outputList));
20882089
}
20892090

2091+
static void circularInclude()
2092+
{
2093+
std::vector<std::string> files;
2094+
simplecpp::FileDataCache cache;
2095+
2096+
{
2097+
const char *const path = "test.h";
2098+
const char code[] =
2099+
"#ifndef TEST_H\n"
2100+
"#define TEST_H\n"
2101+
"#include \"a/a.h\"\n"
2102+
"#endif\n"
2103+
;
2104+
cache.insert({path, makeTokenList(code, files, path)});
2105+
}
2106+
2107+
{
2108+
const char *const path = "a/a.h";
2109+
const char code[] =
2110+
"#ifndef A_H\n"
2111+
"#define A_H\n"
2112+
"#include \"../test.h\"\n"
2113+
"#endif\n"
2114+
;
2115+
cache.insert({path, makeTokenList(code, files, path)});
2116+
}
2117+
2118+
simplecpp::OutputList outputList;
2119+
simplecpp::TokenList tokens2(files);
2120+
{
2121+
std::vector<std::string> filenames;
2122+
const simplecpp::DUI dui;
2123+
2124+
const char code[] = "#include \"test.h\"\n";
2125+
const simplecpp::TokenList rawtokens = makeTokenList(code, files, "test.cpp");
2126+
2127+
cache = simplecpp::load(rawtokens, filenames, dui, &outputList, std::move(cache));
2128+
simplecpp::preprocess(tokens2, rawtokens, files, cache, dui, &outputList);
2129+
}
2130+
2131+
ASSERT_EQUALS("", toString(outputList));
2132+
}
2133+
20902134
static void multiline1()
20912135
{
20922136
const char code[] = "#define A \\\n"
@@ -3314,6 +3358,7 @@ int main(int argc, char **argv)
33143358
TEST_CASE(missingHeader4);
33153359
TEST_CASE(nestedInclude);
33163360
TEST_CASE(systemInclude);
3361+
TEST_CASE(circularInclude);
33173362

33183363
TEST_CASE(nullDirective1);
33193364
TEST_CASE(nullDirective2);

0 commit comments

Comments
 (0)