bail out instead of crash when parsing unicode code (#207)

This commit is contained in:
Daniel Marjamäki 2009-04-27 21:29:03 +02:00
parent 7b58e09a07
commit b49997e69d
5 changed files with 62 additions and 32 deletions

View File

@ -32,6 +32,7 @@
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <stdexcept>
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -297,44 +298,53 @@ unsigned int CppCheck::check()
if (_settings._errorsOnly == false) if (_settings._errorsOnly == false)
_errorLogger->reportOut(std::string("Checking ") + fname + std::string("...")); _errorLogger->reportOut(std::string("Checking ") + fname + std::string("..."));
Preprocessor preprocessor; try
std::list<std::string> configurations;
std::string filedata = "";
if (_fileContents.size() > 0 && _fileContents.find(_filenames[c]) != _fileContents.end())
{ {
// File content was given as a string Preprocessor preprocessor;
std::istringstream iss(_fileContents[ _filenames[c] ]); std::list<std::string> configurations;
preprocessor.preprocess(iss, filedata, configurations, fname, _includePaths); std::string filedata = "";
}
else
{
// Only file name was given, read the content from file
std::ifstream fin(fname.c_str());
preprocessor.preprocess(fin, filedata, configurations, fname, _includePaths);
}
int checkCount = 0; if (_fileContents.size() > 0 && _fileContents.find(_filenames[c]) != _fileContents.end())
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it)
{
// Check only 12 first configurations, after that bail out, unless --force
// was used.
if (!_settings._force && checkCount > 11)
{ {
if (_settings._errorsOnly == false) // File content was given as a string
_errorLogger->reportOut(std::string("Bailing out from checking ") + fname + ": Too many configurations. Recheck this file with --force if you want to check them all."); std::istringstream iss(_fileContents[ _filenames[c] ]);
preprocessor.preprocess(iss, filedata, configurations, fname, _includePaths);
break; }
else
{
// Only file name was given, read the content from file
std::ifstream fin(fname.c_str());
preprocessor.preprocess(fin, filedata, configurations, fname, _includePaths);
} }
cfg = *it; int checkCount = 0;
std::string codeWithoutCfg = Preprocessor::getcode(filedata, *it, fname, _errorLogger); for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it)
{
// Check only 12 first configurations, after that bail out, unless --force
// was used.
if (!_settings._force && checkCount > 11)
{
if (_settings._errorsOnly == false)
_errorLogger->reportOut(std::string("Bailing out from checking ") + fname + ": Too many configurations. Recheck this file with --force if you want to check them all.");
// If only errors are printed, print filename after the check break;
if (_settings._errorsOnly == false && it != configurations.begin()) }
_errorLogger->reportOut(std::string("Checking ") + fname + ": " + cfg + std::string("..."));
checkFile(codeWithoutCfg, _filenames[c].c_str()); cfg = *it;
++checkCount; std::string codeWithoutCfg = Preprocessor::getcode(filedata, *it, fname, _errorLogger);
// If only errors are printed, print filename after the check
if (_settings._errorsOnly == false && it != configurations.begin())
_errorLogger->reportOut(std::string("Checking ") + fname + ": " + cfg + std::string("..."));
checkFile(codeWithoutCfg, _filenames[c].c_str());
++checkCount;
}
}
catch (std::runtime_error &e)
{
// Exception was thrown when checking this file..
_errorLogger->reportOut("Bailing out from checking " + fname + ": " + e.what());
} }
_errorLogger->reportStatus(c + 1, _filenames.size()); _errorLogger->reportStatus(c + 1, _filenames.size());

View File

@ -23,6 +23,7 @@
#include "token.h" #include "token.h"
#include <algorithm> #include <algorithm>
#include <stdexcept>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
@ -71,7 +72,7 @@ std::string Preprocessor::read(std::istream &istr)
for (char ch = readChar(istr); istr.good(); ch = readChar(istr)) for (char ch = readChar(istr); istr.good(); ch = readChar(istr))
{ {
if (ch < 0) if (ch < 0)
continue; throw std::runtime_error("The code contains characters that are unhandled");
if (ch == '\n') if (ch == '\n')
++lineno; ++lineno;

View File

@ -27,6 +27,8 @@
#include "../src/tokenize.h" #include "../src/tokenize.h"
#include <map> #include <map>
#include <string> #include <string>
#include <sstream>
#include <stdexcept>
extern std::ostringstream errout; extern std::ostringstream errout;
@ -115,6 +117,8 @@ private:
TEST_CASE(pragma); TEST_CASE(pragma);
TEST_CASE(endifsemicolon); TEST_CASE(endifsemicolon);
TEST_CASE(missing_doublequote); TEST_CASE(missing_doublequote);
TEST_CASE(unicode1);
} }
@ -850,6 +854,13 @@ private:
ASSERT_EQUALS("[abc.h:2]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported.\n", errout.str()); ASSERT_EQUALS("[abc.h:2]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported.\n", errout.str());
} }
} }
void unicode1()
{
const char filedata[] = {'a', (char)200, 0};
std::istringstream istr(filedata);
ASSERT_THROW(Preprocessor::read(istr), std::runtime_error);
}
}; };
REGISTER_TEST(TestPreprocessor) REGISTER_TEST(TestPreprocessor)

View File

@ -123,6 +123,12 @@ void TestFixture::assertEquals(const char *filename, int linenr, unsigned int ex
assertEquals(filename, linenr, ostr1.str(), ostr2.str()); assertEquals(filename, linenr, ostr1.str(), ostr2.str());
} }
void TestFixture::assertThrowFail(const char *filename, int linenr)
{
errmsg << "Assertion failed in " << filename << " at line " << linenr << std::endl
<< "The expected exception was not thrown" << std::endl;
}
void TestFixture::printTests() void TestFixture::printTests()
{ {
const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests(); const std::list<TestFixture *> &tests = TestRegistry::theInstance().tests();

View File

@ -41,6 +41,7 @@ protected:
void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual); void assertEquals(const char *filename, int linenr, const std::string &expected, const std::string &actual);
void assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual); void assertEquals(const char *filename, int linenr, unsigned int expected, unsigned int actual);
void assertThrowFail(const char *filename, int linenr);
public: public:
virtual void reportOut(const std::string &outmsg); virtual void reportOut(const std::string &outmsg);
@ -58,6 +59,7 @@ public:
#define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME (); #define TEST_CASE( NAME ) if ( runTest(#NAME) ) NAME ();
#define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL) #define ASSERT_EQUALS( EXPECTED , ACTUAL ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL)
#define ASSERT_THROW( CMD, EXCEPTION ) try { CMD ; assertThrowFail(__FILE__, __LINE__); } catch (EXCEPTION &) { } catch (...) { assertThrowFail(__FILE__, __LINE__); }
#define TODO_ASSERT_EQUALS( EXPECTED , ACTUAL ) if (EXPECTED==ACTUAL) assertEquals(__FILE__, __LINE__, "TODO assertion", "The assertion succeeded") #define TODO_ASSERT_EQUALS( EXPECTED , ACTUAL ) if (EXPECTED==ACTUAL) assertEquals(__FILE__, __LINE__, "TODO assertion", "The assertion succeeded")
#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance; } #define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance; }