Merge pull request #10199 from ethereum/readfile

[CLI] Improve error handling of missing/unwriteable files
This commit is contained in:
chriseth 2020-11-10 13:50:40 +01:00 committed by GitHub
commit eaba9a680a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 55 additions and 9 deletions

View File

@ -4,6 +4,8 @@ Language Features:
* Ability to select the abi coder using ``pragma abicoder v1`` and ``pragma abicoder v2``. * Ability to select the abi coder using ``pragma abicoder v1`` and ``pragma abicoder v2``.
Compiler Features: Compiler Features:
* Command Line Interface: Report error if file could not be read in ``--standard-json`` mode.
* Command Line interface: Report proper error for each output file which could not be written. Previously an exception was thrown, and execution aborted, on the first error.
* SMTChecker: Add division by zero checks in the CHC engine. * SMTChecker: Add division by zero checks in the CHC engine.
* SMTChecker: Support ``selector`` for expressions with value known at compile-time. * SMTChecker: Support ``selector`` for expressions with value known at compile-time.
* Command Line Interface: New option ``--model-checker-timeout`` sets a timeout in milliseconds for each individual query performed by the SMTChecker. * Command Line Interface: New option ``--model-checker-timeout`` sets a timeout in milliseconds for each individual query performed by the SMTChecker.

View File

@ -47,8 +47,7 @@ inline T readFile(std::string const& _file)
T ret; T ret;
size_t const c_elementSize = sizeof(typename T::value_type); size_t const c_elementSize = sizeof(typename T::value_type);
std::ifstream is(_file, std::ifstream::binary); std::ifstream is(_file, std::ifstream::binary);
if (!is) assertThrow(is, FileNotFound, _file);
return ret;
// get length of file: // get length of file:
is.seekg(0, is.end); is.seekg(0, is.end);

View File

@ -32,7 +32,8 @@ namespace solidity::util
{ {
/// Retrieve and returns the contents of the given file as a std::string. /// Retrieve and returns the contents of the given file as a std::string.
/// If the file doesn't exist or isn't readable, returns an empty container / bytes. /// If the file doesn't exist, it will throw a FileNotFound exception.
/// If the file is empty, returns an empty string.
std::string readFileAsString(std::string const& _file); std::string readFileAsString(std::string const& _file);
/// Retrieve and returns the contents of standard input (until EOF). /// Retrieve and returns the contents of standard input (until EOF).

View File

@ -48,7 +48,7 @@ private:
DEV_SIMPLE_EXCEPTION(InvalidAddress); DEV_SIMPLE_EXCEPTION(InvalidAddress);
DEV_SIMPLE_EXCEPTION(BadHexCharacter); DEV_SIMPLE_EXCEPTION(BadHexCharacter);
DEV_SIMPLE_EXCEPTION(BadHexCase); DEV_SIMPLE_EXCEPTION(BadHexCase);
DEV_SIMPLE_EXCEPTION(FileError); DEV_SIMPLE_EXCEPTION(FileNotFound);
DEV_SIMPLE_EXCEPTION(DataTooLong); DEV_SIMPLE_EXCEPTION(DataTooLong);
DEV_SIMPLE_EXCEPTION(StringTooLong); DEV_SIMPLE_EXCEPTION(StringTooLong);

View File

@ -614,6 +614,7 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
continue; continue;
} }
// NOTE: we ignore the FileNotFound exception as we manually check above
m_sourceCodes[infile.generic_string()] = readFileAsString(infile.string()); m_sourceCodes[infile.generic_string()] = readFileAsString(infile.string());
path = boost::filesystem::canonical(infile).string(); path = boost::filesystem::canonical(infile).string();
} }
@ -643,6 +644,10 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
{ {
// Thrown e.g. if path is too long. // Thrown e.g. if path is too long.
} }
catch (FileNotFound const&)
{
// Should not happen if `fs::is_regular_file` is correct.
}
vector<string> libraries; vector<string> libraries;
boost::split(libraries, data, boost::is_space() || boost::is_any_of(","), boost::token_compress_on); boost::split(libraries, data, boost::is_space() || boost::is_any_of(","), boost::token_compress_on);
@ -738,7 +743,11 @@ void CommandLineInterface::createFile(string const& _fileName, string const& _da
ofstream outFile(pathName); ofstream outFile(pathName);
outFile << _data; outFile << _data;
if (!outFile) if (!outFile)
BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + pathName)); {
serr() << "Could not write to file \"" << pathName << "\"." << endl;
m_error = true;
return;
}
} }
void CommandLineInterface::createJson(string const& _fileName, string const& _json) void CommandLineInterface::createJson(string const& _fileName, string const& _json)
@ -1146,6 +1155,7 @@ bool CommandLineInterface::processInput()
if (!boost::filesystem::is_regular_file(canonicalPath)) if (!boost::filesystem::is_regular_file(canonicalPath))
return ReadCallback::Result{false, "Not a valid file."}; return ReadCallback::Result{false, "Not a valid file."};
// NOTE: we ignore the FileNotFound exception as we manually check above
auto contents = readFileAsString(canonicalPath.string()); auto contents = readFileAsString(canonicalPath.string());
m_sourceCodes[path.generic_string()] = contents; m_sourceCodes[path.generic_string()] = contents;
return ReadCallback::Result{true, contents}; return ReadCallback::Result{true, contents};
@ -1232,7 +1242,17 @@ bool CommandLineInterface::processInput()
if (jsonFile.empty()) if (jsonFile.empty())
input = readStandardInput(); input = readStandardInput();
else else
input = readFileAsString(jsonFile); {
try
{
input = readFileAsString(jsonFile);
}
catch (FileNotFound const&)
{
serr() << "File not found: " << jsonFile << endl;
return false;
}
}
StandardCompiler compiler(fileReader); StandardCompiler compiler(fileReader);
sout() << compiler.compile(std::move(input)) << endl; sout() << compiler.compile(std::move(input)) << endl;
return true; return true;

View File

@ -0,0 +1 @@
--standard-json

View File

@ -0,0 +1 @@
File not found: standard_file_not_found/input.sol

View File

@ -0,0 +1 @@
1

View File

@ -20,6 +20,7 @@
*/ */
#include <libsolutil/CommonIO.h> #include <libsolutil/CommonIO.h>
#include <libsolutil/Exceptions.h>
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <liblangutil/Scanner.h> #include <liblangutil/Scanner.h>
#include <libyul/AsmAnalysis.h> #include <libyul/AsmAnalysis.h>
@ -243,8 +244,18 @@ Allowed options)",
} }
string input; string input;
try
{
input = readFileAsString(arguments["input-file"].as<string>());
}
catch (FileNotFound const& _exception)
{
cerr << "File not found:" << _exception.comment() << endl;
return 1;
}
if (arguments.count("input-file")) if (arguments.count("input-file"))
YulOpti{}.runInteractive(readFileAsString(arguments["input-file"].as<string>())); YulOpti{}.runInteractive(input);
else else
cout << options; cout << options;

View File

@ -35,6 +35,7 @@
#include <libsolutil/CommonIO.h> #include <libsolutil/CommonIO.h>
#include <libsolutil/CommonData.h> #include <libsolutil/CommonData.h>
#include <libsolutil/Exceptions.h>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
@ -137,10 +138,19 @@ Allowed options)",
else else
{ {
string input; string input;
if (arguments.count("input-file")) if (arguments.count("input-file"))
for (string path: arguments["input-file"].as<vector<string>>()) for (string path: arguments["input-file"].as<vector<string>>())
input += readFileAsString(path); {
try
{
input += readFileAsString(path);
}
catch (FileNotFound const&)
{
cerr << "File not found: " << path << endl;
return 1;
}
}
else else
input = readStandardInput(); input = readStandardInput();