Skip to content

Commit d59e664

Browse files
committed
make it possible to pass char buffer to simplecpp
1 parent 527693b commit d59e664

8 files changed

Lines changed: 143 additions & 29 deletions

File tree

democlient/democlient.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ class CppcheckExecutor : public ErrorLogger {
5959
cppcheck.settings().certainty.enable(Certainty::inconclusive);
6060
}
6161

62-
void run(const char code[]) {
63-
cppcheck.check(FileWithDetails("test.cpp"), code);
62+
template<std::size_t size>
63+
void run(const char (&code)[size]) {
64+
cppcheck.check(FileWithDetails("test.cpp"), reinterpret_cast<const uint8_t*>(code), size-1);
6465
}
6566

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

gui/mainwindow.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,10 @@ void MainWindow::analyzeCode(const QString& code, const QString& filename)
700700
checkLockDownUI();
701701
clearResults();
702702
mUI->mResults->checkingStarted(1);
703-
cppcheck.check(FileWithDetails(filename.toStdString()), code.toStdString());
703+
{
704+
const std::string code_s = code.toStdString();
705+
cppcheck.check(FileWithDetails(filename.toStdString()), reinterpret_cast<const std::uint8_t*>(code_s.data()), code_s.size());
706+
}
704707
analysisDone();
705708

706709
// Expand results

lib/cppcheck.cpp

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -559,10 +559,9 @@ unsigned int CppCheck::check(const FileWithDetails &file)
559559
return checkFile(file, emptyString);
560560
}
561561

562-
unsigned int CppCheck::check(const FileWithDetails &file, const std::string &content)
562+
unsigned int CppCheck::check(const FileWithDetails &file, const uint8_t* data, std::size_t size)
563563
{
564-
std::istringstream iss(content);
565-
return checkFile(file, emptyString, &iss);
564+
return checkBuffer(file, emptyString, data, size);
566565
}
567566

568567
unsigned int CppCheck::check(const FileSettings &fs)
@@ -608,15 +607,41 @@ unsigned int CppCheck::check(const FileSettings &fs)
608607
return returnValue;
609608
}
610609

611-
static simplecpp::TokenList createTokenList(const std::string& filename, std::vector<std::string>& files, simplecpp::OutputList* outputList, std::istream* fileStream)
610+
unsigned int CppCheck::checkBuffer(const FileWithDetails &file, const std::string &cfgname, const uint8_t* data, std::size_t size)
612611
{
613-
if (fileStream)
614-
return {*fileStream, files, filename, outputList};
612+
return checkInternal(file, cfgname,
613+
[&file, data, size](TokenList& list) {
614+
list.createTokens(data, size, file.spath());
615+
},
616+
[&file, data, size](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
617+
return simplecpp::TokenList{data, size, files, file.spath(), outputList};
618+
});
619+
}
620+
621+
unsigned int CppCheck::checkStream(const FileWithDetails &file, const std::string &cfgname, std::istream& fileStream)
622+
{
623+
return checkInternal(file, cfgname,
624+
[&file, &fileStream](TokenList& list) {
625+
list.createTokens(fileStream, file.spath());
626+
},
627+
[&file, &fileStream](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
628+
return simplecpp::TokenList{fileStream, files, file.spath(), outputList};
629+
});
630+
}
615631

616-
return {filename, files, outputList};
632+
unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname)
633+
{
634+
return checkInternal(file, cfgname,
635+
[&file](TokenList& list) {
636+
std::ifstream in(file.spath());
637+
list.createTokens(in, file.spath());
638+
},
639+
[&file](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
640+
return simplecpp::TokenList{file.spath(), files, outputList};
641+
});
617642
}
618643

619-
unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname, std::istream* fileStream)
644+
unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::string &cfgname, const CreateTokensFn& createTokens, const CreateTokenListFn& createTokenList)
620645
{
621646
// TODO: move to constructor when CppCheck no longer owns the settings
622647
if (mSettings.checks.isEnabled(Checks::unusedFunction) && !mUnusedFunctionsCheck)
@@ -662,21 +687,15 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string
662687
Tokenizer tokenizer(mSettings, *this);
663688
// enforce the language since markup files are special and do not adhere to the enforced language
664689
tokenizer.list.setLang(Standards::Language::C, true);
665-
if (fileStream) {
666-
tokenizer.list.createTokens(*fileStream, file.spath());
667-
}
668-
else {
669-
std::ifstream in(file.spath());
670-
tokenizer.list.createTokens(in, file.spath());
671-
}
690+
createTokens(tokenizer.list);
672691
mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings);
673692
}
674693
return EXIT_SUCCESS;
675694
}
676695

677696
simplecpp::OutputList outputList;
678697
std::vector<std::string> files;
679-
simplecpp::TokenList tokens1 = createTokenList(file.spath(), files, &outputList, fileStream);
698+
simplecpp::TokenList tokens1 = createTokenList(files, &outputList);
680699

681700
// If there is a syntax error, report it and stop
682701
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
@@ -48,7 +48,10 @@ class Tokenizer;
4848
class FileWithDetails;
4949
class RemarkComment;
5050

51-
namespace simplecpp { class TokenList; }
51+
namespace simplecpp {
52+
class TokenList;
53+
struct Output;
54+
}
5255

5356
/// @addtogroup Core
5457
/// @{
@@ -98,12 +101,13 @@ class CPPCHECKLIB CppCheck : ErrorLogger {
98101
* the disk but the content is given in @p content. In errors the @p path
99102
* is used as a filename.
100103
* @param file The file to check.
101-
* @param content File content as a string.
104+
* @param data File content as a buffer.
105+
* @param size Size of buffer.
102106
* @return amount of errors found or 0 if none were found.
103107
* @note You must set settings before calling this function (by calling
104108
* settings()).
105109
*/
106-
unsigned int check(const FileWithDetails &file, const std::string &content);
110+
unsigned int check(const FileWithDetails &file, const uint8_t* data, std::size_t size);
107111

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

185222
/**
186223
* @brief Check normal tokens

lib/tokenlist.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,17 @@ bool TokenList::createTokens(std::istream &code, const std::string& file0)
345345

346346
//---------------------------------------------------------------------------
347347

348+
bool TokenList::createTokens(const uint8_t* data, size_t size, const std::string& file0)
349+
{
350+
ASSERT_LANG(!file0.empty());
351+
352+
appendFileIfNew(file0);
353+
354+
return createTokensInternal(data, size, file0);
355+
}
356+
357+
//---------------------------------------------------------------------------
358+
348359
bool TokenList::createTokens(std::istream &code, Standards::Language lang)
349360
{
350361
ASSERT_LANG(lang != Standards::Language::None);
@@ -359,6 +370,20 @@ bool TokenList::createTokens(std::istream &code, Standards::Language lang)
359370

360371
//---------------------------------------------------------------------------
361372

373+
bool TokenList::createTokens(const uint8_t* data, size_t size, Standards::Language lang)
374+
{
375+
ASSERT_LANG(lang != Standards::Language::None);
376+
if (mLang == Standards::Language::None) {
377+
mLang = lang;
378+
} else {
379+
ASSERT_LANG(lang == mLang);
380+
}
381+
382+
return createTokensInternal(data, size, "");
383+
}
384+
385+
//---------------------------------------------------------------------------
386+
362387
bool TokenList::createTokensInternal(std::istream &code, const std::string& file0)
363388
{
364389
simplecpp::OutputList outputList;
@@ -371,6 +396,18 @@ bool TokenList::createTokensInternal(std::istream &code, const std::string& file
371396

372397
//---------------------------------------------------------------------------
373398

399+
bool TokenList::createTokensInternal(const uint8_t* data, size_t size, const std::string& file0)
400+
{
401+
simplecpp::OutputList outputList;
402+
simplecpp::TokenList tokens(data, size, mFiles, file0, &outputList);
403+
404+
createTokens(std::move(tokens));
405+
406+
return outputList.empty();
407+
}
408+
409+
//---------------------------------------------------------------------------
410+
374411
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
375412
void TokenList::createTokens(simplecpp::TokenList&& tokenList)
376413
{

lib/tokenlist.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,23 @@ class CPPCHECKLIB TokenList {
106106
* @param file0 source file name
107107
*/
108108
bool createTokens(std::istream &code, const std::string& file0);
109+
bool createTokens(const uint8_t* data, size_t size, const std::string& file0);
110+
bool createTokens(const char* data, size_t size, const std::string& file0) {
111+
return createTokens(reinterpret_cast<const uint8_t*>(data), size, file0);
112+
}
113+
template<size_t size>
114+
bool createTokens(const char (&data)[size], const std::string& file0) {
115+
return createTokens(reinterpret_cast<const uint8_t*>(data), size-1, file0);
116+
}
109117
bool createTokens(std::istream &code, Standards::Language lang);
118+
bool createTokens(const uint8_t* data, size_t size, Standards::Language lang);
119+
bool createTokens(const char* data, size_t size, Standards::Language lang) {
120+
return createTokens(reinterpret_cast<const uint8_t*>(data), size, lang);
121+
}
122+
template<size_t size>
123+
bool createTokens(const char (&data)[size], Standards::Language lang) {
124+
return createTokens(reinterpret_cast<const uint8_t*>(data), size-1, lang);
125+
}
110126

111127
void createTokens(simplecpp::TokenList&& tokenList);
112128

@@ -205,6 +221,7 @@ class CPPCHECKLIB TokenList {
205221
void determineCppC();
206222

207223
bool createTokensInternal(std::istream &code, const std::string& file0);
224+
bool createTokensInternal(const uint8_t* data, std::size_t size, const std::string& file0);
208225

209226
/** Token list */
210227
TokensFrontBack mTokensFrontBack;

oss-fuzz/main.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ class DummyErrorLogger : public ErrorLogger {
4040
static DummyErrorLogger s_errorLogger;
4141
static const FileWithDetails s_file("test.cpp");
4242

43-
static void doCheck(const std::string& code)
43+
static void doCheck(const uint8_t *data, size_t dataSize)
4444
{
4545
CppCheck cppcheck(s_errorLogger, false, nullptr);
4646
cppcheck.settings().addEnabled("all");
4747
cppcheck.settings().certainty.setEnabled(Certainty::inconclusive, true);
48-
cppcheck.check(s_file, code);
48+
cppcheck.check(s_file, data, dataSize);
4949
}
5050

5151
#ifndef NO_FUZZ
@@ -55,7 +55,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize)
5555
{
5656
if (dataSize < 10000) {
5757
const std::string code = generateCode2(data, dataSize);
58-
doCheck(code);
58+
doCheck(reinterpret_cast<const unsigned char*>(code.data()), code.size());
5959
}
6060
return 0;
6161
}
@@ -79,7 +79,7 @@ int main(int argc, char * argv[])
7979

8080
const std::string code = oss.str();
8181
for (int i = 0; i < cnt; ++i)
82-
doCheck(code);
82+
doCheck(reinterpret_cast<const unsigned char*>(code.data()), code.size());
8383

8484
return EXIT_SUCCESS;
8585
}

test/testsuppressions.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@ class TestSuppressions : public TestFixture {
11851185
settings.exitCode = 1;
11861186

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

@@ -1225,7 +1225,7 @@ class TestSuppressions : public TestFixture {
12251225
" // cppcheck-suppress unusedStructMember\n"
12261226
" int y;\n"
12271227
"};";
1228-
ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("/somewhere/test.cpp"), code));
1228+
ASSERT_EQUALS(0, cppCheck.check(FileWithDetails("/somewhere/test.cpp"), reinterpret_cast<const std::uint8_t*>(code), sizeof(code)));
12291229
ASSERT_EQUALS("",errout_str());
12301230
}
12311231

0 commit comments

Comments
 (0)