Skip to content

Commit 6bcecd7

Browse files
committed
make it possible to pass char buffer to simplecpp
1 parent 12e63b4 commit 6bcecd7

8 files changed

Lines changed: 122 additions & 40 deletions

File tree

democlient/democlient.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ class CppcheckExecutor : public ErrorLogger {
6666
, cppcheck(settings, supprs, *this, false, nullptr)
6767
{}
6868

69-
void run(const char code[]) {
70-
cppcheck.check(FileWithDetails("test.cpp", Standards::Language::CPP, 0), code);
69+
template<std::size_t size>
70+
void run(const char (&code)[size]) {
71+
cppcheck.check(FileWithDetails("test.cpp", Standards::Language::CPP, 0), reinterpret_cast<const uint8_t*>(code), size-1);
7172
}
7273

7374
void reportOut(const std::string & /*outmsg*/, Color /*c*/) override {}

gui/mainwindow.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,8 +726,11 @@ void MainWindow::analyzeCode(const QString& code, const QString& filename)
726726
checkLockDownUI();
727727
clearResults();
728728
mUI->mResults->checkingStarted(1);
729-
// TODO: apply enforcedLanguage?
730-
cppcheck.check(FileWithDetails(filename.toStdString(), Path::identify(filename.toStdString(), false), 0), code.toStdString());
729+
{
730+
const std::string code_s = code.toStdString();
731+
// TODO: apply enforcedLanguage?
732+
cppcheck.check(FileWithDetails(filename.toStdString(), Path::identify(filename.toStdString(), false), 0), reinterpret_cast<const std::uint8_t*>(code_s.data()), code_s.size());
733+
}
731734
analysisDone();
732735

733736
// Expand results

lib/cppcheck.cpp

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -799,10 +799,9 @@ unsigned int CppCheck::check(const FileWithDetails &file)
799799
return returnValue;
800800
}
801801

802-
unsigned int CppCheck::check(const FileWithDetails &file, const std::string &content)
802+
unsigned int CppCheck::check(const FileWithDetails &file, const uint8_t* data, std::size_t size)
803803
{
804-
std::istringstream iss(content);
805-
return checkFile(file, "", 0, &iss);
804+
return checkBuffer(file, "", 0, data, size);
806805
}
807806

808807
unsigned int CppCheck::check(const FileSettings &fs)
@@ -851,12 +850,26 @@ unsigned int CppCheck::check(const FileSettings &fs)
851850
return returnValue;
852851
}
853852

854-
static simplecpp::TokenList createTokenList(const std::string& filename, std::vector<std::string>& files, simplecpp::OutputList* outputList, std::istream* fileStream)
853+
unsigned int CppCheck::checkBuffer(const FileWithDetails &file, const std::string &cfgname, int fileIndex, const uint8_t* data, std::size_t size)
855854
{
856-
if (fileStream)
857-
return {*fileStream, files, filename, outputList};
855+
return checkInternal(file, cfgname, fileIndex,
856+
[&file, data, size](std::vector<std::string>& files) {
857+
return simplecpp::TokenList{data, size, files, file.spath()};
858+
},
859+
[&file, data, size](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
860+
return simplecpp::TokenList{data, size, files, file.spath(), outputList};
861+
});
862+
}
858863

859-
return {filename, files, outputList};
864+
unsigned int CppCheck::checkStream(const FileWithDetails &file, const std::string &cfgname, int fileIndex, std::istream& fileStream)
865+
{
866+
return checkInternal(file, cfgname, fileIndex,
867+
[&fileStream](std::vector<std::string>& files) {
868+
return simplecpp::TokenList{fileStream, files};
869+
},
870+
[&file, &fileStream](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
871+
return simplecpp::TokenList{fileStream, files, file.spath(), outputList};
872+
});
860873
}
861874

862875
std::size_t CppCheck::calculateHash(const Preprocessor& preprocessor, const simplecpp::TokenList& tokens, const std::string& filePath) const
@@ -880,7 +893,18 @@ std::size_t CppCheck::calculateHash(const Preprocessor& preprocessor, const simp
880893
return preprocessor.calculateHash(tokens, toolinfo.str());
881894
}
882895

883-
unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname, int fileIndex, std::istream* fileStream)
896+
unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname, int fileIndex)
897+
{
898+
return checkInternal(file, cfgname, fileIndex,
899+
[&file](std::vector<std::string>& files) {
900+
return simplecpp::TokenList{file.spath(), files};
901+
},
902+
[&file](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
903+
return simplecpp::TokenList{file.spath(), files, outputList};
904+
});
905+
}
906+
907+
unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::string &cfgname, int fileIndex, const CreateTokensFn& createTokens, const CreateTokenListFn& createTokenList)
884908
{
885909
// TODO: move to constructor when CppCheck no longer owns the settings
886910
if (mSettings.checks.isEnabled(Checks::unusedFunction) && !mUnusedFunctionsCheck)
@@ -931,24 +955,13 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string
931955
std::size_t hash = 0;
932956
// markup files are special and do not adhere to the enforced language
933957
TokenList tokenlist{mSettings, Standards::Language::C};
934-
if (fileStream) {
935-
std::vector<std::string> files;
936-
simplecpp::TokenList tokens(*fileStream, files, file.spath());
937-
if (analyzerInformation) {
938-
const Preprocessor preprocessor(mSettings, mErrorLogger, Standards::Language::C);
939-
hash = calculateHash(preprocessor, tokens);
940-
}
941-
tokenlist.createTokens(std::move(tokens));
942-
}
943-
else {
944-
std::vector<std::string> files;
945-
simplecpp::TokenList tokens(file.spath(), files);
946-
if (analyzerInformation) {
947-
const Preprocessor preprocessor(mSettings, mErrorLogger, file.lang());
948-
hash = calculateHash(preprocessor, tokens);
949-
}
950-
tokenlist.createTokens(std::move(tokens));
958+
std::vector<std::string> files;
959+
simplecpp::TokenList tokens = createTokens(files);
960+
if (analyzerInformation) {
961+
const Preprocessor preprocessor(mSettings, mErrorLogger, file.lang());
962+
hash = calculateHash(preprocessor, tokens);
951963
}
964+
tokenlist.createTokens(std::move(tokens));
952965
// this is not a real source file - we just want to tokenize it. treat it as C anyways as the language needs to be determined.
953966
Tokenizer tokenizer(std::move(tokenlist), mErrorLogger);
954967
mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings);
@@ -967,7 +980,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string
967980

968981
simplecpp::OutputList outputList;
969982
std::vector<std::string> files;
970-
simplecpp::TokenList tokens1 = createTokenList(file.spath(), files, &outputList, fileStream);
983+
simplecpp::TokenList tokens1 = createTokenList(files, &outputList);
971984

972985
// If there is a syntax error, report it and stop
973986
const auto output_it = std::find_if(outputList.cbegin(), outputList.cend(), [](const simplecpp::Output &output){

lib/cppcheck.h

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ class Settings;
4545
struct Suppressions;
4646
class Preprocessor;
4747

48-
namespace simplecpp { class TokenList; }
48+
namespace simplecpp {
49+
class TokenList;
50+
struct Output;
51+
}
4952

5053
/// @addtogroup Core
5154
/// @{
@@ -100,12 +103,13 @@ class CPPCHECKLIB CppCheck {
100103
* the disk but the content is given in @p content. In errors the @p path
101104
* is used as a filename.
102105
* @param file The file to check.
103-
* @param content File content as a string.
106+
* @param data File content as a buffer.
107+
* @param size Size of buffer.
104108
* @return amount of errors found or 0 if none were found.
105109
* @note You must set settings before calling this function (by calling
106110
* settings()).
107111
*/
108-
unsigned int check(const FileWithDetails &file, const std::string &content);
112+
unsigned int check(const FileWithDetails &file, const uint8_t* data, std::size_t size);
109113

110114
/**
111115
* @brief Returns current version number as a string.
@@ -181,7 +185,40 @@ class CPPCHECKLIB CppCheck {
181185
* @param fileStream stream the file content can be read from
182186
* @return number of errors found
183187
*/
184-
unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname, int fileIndex, std::istream* fileStream = nullptr);
188+
unsigned int checkStream(const FileWithDetails& file, const std::string &cfgname, int fileIndex, std::istream& fileStream);
189+
190+
191+
/**
192+
* @brief Check a file
193+
* @param file the file
194+
* @param cfgname cfg name
195+
* @return number of errors found
196+
*/
197+
unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname, int fileIndex);
198+
199+
/**
200+
* @brief Check a file using buffer
201+
* @param file the file
202+
* @param cfgname cfg name
203+
* @param data the data to be read
204+
* @param size the size of the data to be read
205+
* @return number of errors found
206+
*/
207+
unsigned int checkBuffer(const FileWithDetails& file, const std::string &cfgname, int fileIndex, const uint8_t* data, std::size_t size);
208+
209+
using CreateTokensFn = std::function<simplecpp::TokenList (std::vector<std::string>& files)>;
210+
// TODO: should use simplecpp::OutputList
211+
using CreateTokenListFn = std::function<simplecpp::TokenList (std::vector<std::string>&, std::list<simplecpp::Output>*)>;
212+
213+
/**
214+
* @brief Check a file using stream
215+
* @param file the file
216+
* @param cfgname cfg name
217+
* @param createTokens a function to create the tokens with
218+
* @param createTokenList a function to create the TokenList with
219+
* @return number of errors found
220+
*/
221+
unsigned int checkInternal(const FileWithDetails& file, const std::string &cfgname, int fileIndex, const CreateTokensFn& createTokens, const CreateTokenListFn& createTokenList);
185222

186223
/**
187224
* @brief Check normal tokens

lib/tokenlist.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,13 @@ bool TokenList::createTokens(std::istream &code)
328328

329329
//---------------------------------------------------------------------------
330330

331+
bool TokenList::createTokens(const uint8_t* data, size_t size)
332+
{
333+
return createTokensInternal(data, size, mFiles.empty() ? "" : *mFiles.cbegin());
334+
}
335+
336+
//---------------------------------------------------------------------------
337+
331338
bool TokenList::createTokensInternal(std::istream &code, const std::string& file0)
332339
{
333340
simplecpp::OutputList outputList;
@@ -340,6 +347,18 @@ bool TokenList::createTokensInternal(std::istream &code, const std::string& file
340347

341348
//---------------------------------------------------------------------------
342349

350+
bool TokenList::createTokensInternal(const uint8_t* data, size_t size, const std::string& file0)
351+
{
352+
simplecpp::OutputList outputList;
353+
simplecpp::TokenList tokens(data, size, mFiles, file0, &outputList);
354+
355+
createTokens(std::move(tokens));
356+
357+
return outputList.empty();
358+
}
359+
360+
//---------------------------------------------------------------------------
361+
343362
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
344363
void TokenList::createTokens(simplecpp::TokenList&& tokenList)
345364
{

lib/tokenlist.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ class CPPCHECKLIB TokenList {
101101
* @param code input stream for code
102102
*/
103103
bool createTokens(std::istream &code);
104+
bool createTokens(const uint8_t* data, size_t size);
105+
bool createTokens(const char* data, size_t size) {
106+
return createTokens(reinterpret_cast<const uint8_t*>(data), size);
107+
}
108+
template<size_t size>
109+
bool createTokens(const char (&data)[size]) {
110+
return createTokens(reinterpret_cast<const uint8_t*>(data), size-1);
111+
}
104112

105113
void createTokens(simplecpp::TokenList&& tokenList);
106114

@@ -209,6 +217,7 @@ class CPPCHECKLIB TokenList {
209217

210218
private:
211219
bool createTokensInternal(std::istream &code, const std::string& file0);
220+
bool createTokensInternal(const uint8_t* data, std::size_t size, const std::string& file0);
212221

213222
/** Token list */
214223
std::shared_ptr<TokensFrontBack> mTokensFrontBack;

oss-fuzz/main.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ static const Settings s_settings = create_settings();
6060
static DummyErrorLogger s_errorLogger;
6161
static const FileWithDetails s_file("test.cpp", Standards::Language::CPP, 0);
6262

63-
static void doCheck(const std::string& code)
63+
static void doCheck(const uint8_t *data, size_t dataSize)
6464
{
6565
Suppressions supprs;
6666
CppCheck cppcheck(s_settings, supprs, s_errorLogger, false, nullptr);
67-
cppcheck.check(s_file, code);
67+
cppcheck.check(s_file, data, dataSize);
6868
}
6969

7070
#ifndef NO_FUZZ
@@ -74,7 +74,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize)
7474
{
7575
if (dataSize < 10000) {
7676
const std::string code = generateCode2(data, dataSize);
77-
doCheck(code);
77+
doCheck(reinterpret_cast<const unsigned char*>(code.data()), code.size());
7878
}
7979
return 0;
8080
}
@@ -98,7 +98,7 @@ int main(int argc, char * argv[])
9898

9999
const std::string code = oss.str();
100100
for (int i = 0; i < cnt; ++i)
101-
doCheck(code);
101+
doCheck(reinterpret_cast<const unsigned char*>(code.data()), code.size());
102102

103103
return EXIT_SUCCESS;
104104
}

test/testsuppressions.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ class TestSuppressions : public TestFixture {
12521252
CppCheck cppCheck(settings, supprs, *this, false, nullptr); // <- do not "use global suppressions". pretend this is a thread that just checks a file.
12531253

12541254
const char code[] = "int f() { int a; return a; }";
1255-
ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("test.c", Standards::Language::C, 0), code)); // <- no unsuppressed error is seen
1255+
ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("test.c", Standards::Language::C, 0), reinterpret_cast<const std::uint8_t*>(code), sizeof(code))); // <- no unsuppressed error is seen
12561256
ASSERT_EQUALS("[test.c:1:25]: (error) Uninitialized variable: a [uninitvar]\n", errout_str()); // <- report error so ThreadExecutor can suppress it and make sure the global suppression is matched.
12571257
}
12581258

@@ -1296,7 +1296,7 @@ class TestSuppressions : public TestFixture {
12961296
" int y;\n"
12971297
"};";
12981298
CppCheck cppCheck(settings, supprs, *this, true, nullptr);
1299-
ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("/somewhere/test.cpp", Standards::Language::CPP, 0), code));
1299+
ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("/somewhere/test.cpp", Standards::Language::CPP, 0), reinterpret_cast<const std::uint8_t*>(code), sizeof(code)));
13001300
ASSERT_EQUALS("",errout_str());
13011301
}
13021302

0 commit comments

Comments
 (0)