Skip to content

Commit 28a35a7

Browse files
committed
make it possible to pass char buffer to simplecpp
1 parent 2d62472 commit 28a35a7

File tree

8 files changed

+143
-29
lines changed

8 files changed

+143
-29
lines changed

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
@@ -662,7 +662,10 @@ void MainWindow::analyzeCode(const QString& code, const QString& filename)
662662
checkLockDownUI();
663663
clearResults();
664664
mUI->mResults->checkingStarted(1);
665-
cppcheck.check(FileWithDetails(filename.toStdString()), code.toStdString());
665+
{
666+
const std::string code_s = code.toStdString();
667+
cppcheck.check(FileWithDetails(filename.toStdString()), reinterpret_cast<const std::uint8_t*>(code_s.data()), code_s.size());
668+
}
666669
analysisDone();
667670

668671
// Expand results

lib/cppcheck.cpp

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

553-
unsigned int CppCheck::check(const FileWithDetails &file, const std::string &content)
553+
unsigned int CppCheck::check(const FileWithDetails &file, const uint8_t* data, std::size_t size)
554554
{
555-
std::istringstream iss(content);
556-
return checkFile(file, emptyString, &iss);
555+
return checkBuffer(file, emptyString, data, size);
557556
}
558557

559558
unsigned int CppCheck::check(const FileSettings &fs)
@@ -593,15 +592,41 @@ unsigned int CppCheck::check(const FileSettings &fs)
593592
return returnValue;
594593
}
595594

596-
static simplecpp::TokenList createTokenList(const std::string& filename, std::vector<std::string>& files, simplecpp::OutputList* outputList, std::istream* fileStream)
595+
unsigned int CppCheck::checkBuffer(const FileWithDetails &file, const std::string &cfgname, const uint8_t* data, std::size_t size)
597596
{
598-
if (fileStream)
599-
return {*fileStream, files, filename, outputList};
597+
return checkInternal(file, cfgname,
598+
[&file, data, size](TokenList& list) {
599+
list.createTokens(data, size, file.spath());
600+
},
601+
[&file, data, size](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
602+
return simplecpp::TokenList{data, size, files, file.spath(), outputList};
603+
});
604+
}
605+
606+
unsigned int CppCheck::checkStream(const FileWithDetails &file, const std::string &cfgname, std::istream& fileStream)
607+
{
608+
return checkInternal(file, cfgname,
609+
[&file, &fileStream](TokenList& list) {
610+
list.createTokens(fileStream, file.spath());
611+
},
612+
[&file, &fileStream](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
613+
return simplecpp::TokenList{fileStream, files, file.spath(), outputList};
614+
});
615+
}
600616

601-
return {filename, files, outputList};
617+
unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname)
618+
{
619+
return checkInternal(file, cfgname,
620+
[&file](TokenList& list) {
621+
std::ifstream in(file.spath());
622+
list.createTokens(in, file.spath());
623+
},
624+
[&file](std::vector<std::string>& files, simplecpp::OutputList* outputList) {
625+
return simplecpp::TokenList{file.spath(), files, outputList};
626+
});
602627
}
603628

604-
unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string &cfgname, std::istream* fileStream)
629+
unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::string &cfgname, const CreateTokensFn& createTokens, const CreateTokenListFn& createTokenList)
605630
{
606631
// TODO: move to constructor when CppCheck no longer owns the settings
607632
if (mSettings.checks.isEnabled(Checks::unusedFunction) && !mUnusedFunctionsCheck)
@@ -647,21 +672,15 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string
647672
Tokenizer tokenizer(mSettings, *this);
648673
// enforce the language since markup files are special and do not adhere to the enforced language
649674
tokenizer.list.setLang(Standards::Language::C, true);
650-
if (fileStream) {
651-
tokenizer.list.createTokens(*fileStream, file.spath());
652-
}
653-
else {
654-
std::ifstream in(file.spath());
655-
tokenizer.list.createTokens(in, file.spath());
656-
}
675+
createTokens(tokenizer.list);
657676
mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings);
658677
}
659678
return EXIT_SUCCESS;
660679
}
661680

662681
simplecpp::OutputList outputList;
663682
std::vector<std::string> files;
664-
simplecpp::TokenList tokens1 = createTokenList(file.spath(), files, &outputList, fileStream);
683+
simplecpp::TokenList tokens1 = createTokenList(files, &outputList);
665684

666685
// If there is a syntax error, report it and stop
667686
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.
@@ -178,7 +182,40 @@ class CPPCHECKLIB CppCheck : ErrorLogger {
178182
* @param fileStream stream the file content can be read from
179183
* @return number of errors found
180184
*/
181-
unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname, std::istream* fileStream = nullptr);
185+
unsigned int checkStream(const FileWithDetails& file, const std::string &cfgname, std::istream& fileStream);
186+
187+
188+
/**
189+
* @brief Check a file
190+
* @param file the file
191+
* @param cfgname cfg name
192+
* @return number of errors found
193+
*/
194+
unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname);
195+
196+
/**
197+
* @brief Check a file using buffer
198+
* @param file the file
199+
* @param cfgname cfg name
200+
* @param data the data to be read
201+
* @param size the size of the data to be read
202+
* @return number of errors found
203+
*/
204+
unsigned int checkBuffer(const FileWithDetails& file, const std::string &cfgname, const uint8_t* data, std::size_t size);
205+
206+
using CreateTokensFn = std::function<void (TokenList&)>;
207+
// TODO: should use simplecpp::OutputList
208+
using CreateTokenListFn = std::function<simplecpp::TokenList(std::vector<std::string>&, std::list<simplecpp::Output>*)>;
209+
210+
/**
211+
* @brief Check a file using stream
212+
* @param file the file
213+
* @param cfgname cfg name
214+
* @param createTokens a function to create the tokens with
215+
* @param createTokenList a function to create the TokenList with
216+
* @return number of errors found
217+
*/
218+
unsigned int checkInternal(const FileWithDetails& file, const std::string &cfgname, const CreateTokensFn& createTokens, const CreateTokenListFn& createTokenList);
182219

183220
/**
184221
* @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)