diff --git a/libsolutil/CommonIO.cpp b/libsolutil/CommonIO.cpp index d661681bc..3bab3657e 100644 --- a/libsolutil/CommonIO.cpp +++ b/libsolutil/CommonIO.cpp @@ -43,9 +43,17 @@ namespace template inline T readFile(std::string const& _file) { + assertThrow(boost::filesystem::exists(_file), FileNotFound, _file); + + // ifstream does not always fail when the path leads to a directory. Instead it might succeed + // with tellg() returning a nonsensical value so that std::length_error gets raised in resize(). + assertThrow(boost::filesystem::is_regular_file(_file), NotAFile, _file); + T ret; size_t const c_elementSize = sizeof(typename T::value_type); std::ifstream is(_file, std::ifstream::binary); + + // Technically, this can still fail even though we checked above because FS content can change at any time. assertThrow(is, FileNotFound, _file); // get length of file: diff --git a/libsolutil/CommonIO.h b/libsolutil/CommonIO.h index 88f7f9b5c..8538f0aa2 100644 --- a/libsolutil/CommonIO.h +++ b/libsolutil/CommonIO.h @@ -33,6 +33,7 @@ namespace solidity::util /// Retrieve and returns the contents of the given file as a std::string. /// If the file doesn't exist, it will throw a FileNotFound exception. +/// If the file exists but is not a regular file, it will throw NotAFile exception. /// If the file is empty, returns an empty string. std::string readFileAsString(std::string const& _file); diff --git a/libsolutil/Exceptions.h b/libsolutil/Exceptions.h index 563c7951c..379221ab2 100644 --- a/libsolutil/Exceptions.h +++ b/libsolutil/Exceptions.h @@ -49,6 +49,7 @@ DEV_SIMPLE_EXCEPTION(InvalidAddress); DEV_SIMPLE_EXCEPTION(BadHexCharacter); DEV_SIMPLE_EXCEPTION(BadHexCase); DEV_SIMPLE_EXCEPTION(FileNotFound); +DEV_SIMPLE_EXCEPTION(NotAFile); DEV_SIMPLE_EXCEPTION(DataTooLong); DEV_SIMPLE_EXCEPTION(StringTooLong); diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 40fd3649d..a22d711f9 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -668,6 +668,10 @@ bool CommandLineInterface::parseLibraryOption(string const& _input) { // Should not happen if `fs::is_regular_file` is correct. } + catch (NotAFile const&) + { + // Should not happen if `fs::is_regular_file` is correct. + } vector libraries; boost::split(libraries, data, boost::is_space() || boost::is_any_of(","), boost::token_compress_on); @@ -1263,6 +1267,11 @@ bool CommandLineInterface::processInput() serr() << "File not found: " << jsonFile << endl; return false; } + catch (NotAFile const&) + { + serr() << "Not a regular file: " << jsonFile << endl; + return false; + } } StandardCompiler compiler(m_fileReader.reader()); sout() << compiler.compile(std::move(input)) << endl; diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index 3e403976f..1d3ca3868 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -282,6 +282,11 @@ Allowed options)", cerr << "File not found:" << _exception.comment() << endl; return 1; } + catch (NotAFile const& _exception) + { + cerr << "Not a regular file:" << _exception.comment() << endl; + return 1; + } if (arguments.count("input-file")) YulOpti{}.runInteractive(input); diff --git a/test/tools/yulrun.cpp b/test/tools/yulrun.cpp index 9f764f539..7ff7cfc9e 100644 --- a/test/tools/yulrun.cpp +++ b/test/tools/yulrun.cpp @@ -148,6 +148,11 @@ Allowed options)", cerr << "File not found: " << path << endl; return 1; } + catch (NotAFile const&) + { + cerr << "Not a regular file: " << path << endl; + return 1; + } } else input = readStandardInput();