diff --git a/.gitattributes b/.gitattributes index 8c88af1d7..95c524dd0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -31,3 +31,8 @@ *.png binary *.jpg binary *.gif binary + +# Linguist overrides +.cpp linguist-language=C++ +.h linguist-language=C++ + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d771181e7..239272ffd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,12 @@ # Contributing --- -## Bug Reports and Feature requests +## Bug Reports and Feature Requests --- If you think you've found a bug or would like to see a feature in one of the [upcoming releases](https://github.com/pocoproject/poco/milestones), file an [issue](https://github.com/pocoproject/poco/issues). Please make sure that your explanations are clear and coherent; do the homework of understanding the problem and searching for existing solutions before posting. +Possible security issues or vulnerabilities can also be reported via email directly to the core team security AT pocoproject.org. The core team will respond to security issues within 24 hours. + If you're in a hurry, the fastest way to have bugs fixed or features added are code contributions. Good code contributions, to be precise; if you want to contribute, read on ... --- diff --git a/Data/MySQL/src/SessionHandle.cpp b/Data/MySQL/src/SessionHandle.cpp index 9815e4243..5af93044a 100644 --- a/Data/MySQL/src/SessionHandle.cpp +++ b/Data/MySQL/src/SessionHandle.cpp @@ -150,8 +150,17 @@ void SessionHandle::close() void SessionHandle::startTransaction() { - if (mysql_autocommit(_pHandle, false) != 0) - throw TransactionException("Start transaction failed.", _pHandle); + int rc = mysql_autocommit(_pHandle, false); + if (rc != 0) + { + // retry if connection lost + int err = mysql_errno(_pHandle); + if (err == 2006 /* CR_SERVER_GONE_ERROR */ || err == 2013 /* CR_SERVER_LOST */) + { + rc = mysql_autocommit(_pHandle, false); + } + } + if (rc != 0) throw TransactionException("Start transaction failed.", _pHandle); } diff --git a/Data/SQLite/src/Notifier.cpp b/Data/SQLite/src/Notifier.cpp index 6484b07cd..b279db91c 100644 --- a/Data/SQLite/src/Notifier.cpp +++ b/Data/SQLite/src/Notifier.cpp @@ -25,7 +25,9 @@ namespace SQLite { Notifier::Notifier(const Session& session, EnabledEventType enabled): - _session(session) + _session(session), + _row(), + _enabledEvents() { if (enabled & SQLITE_NOTIFY_UPDATE) enableUpdate(); if (enabled & SQLITE_NOTIFY_COMMIT) enableCommit(); @@ -35,7 +37,9 @@ Notifier::Notifier(const Session& session, EnabledEventType enabled): Notifier::Notifier(const Session& session, const Any& value, EnabledEventType enabled): _session(session), - _value(value) + _value(value), + _row(), + _enabledEvents() { if (enabled & SQLITE_NOTIFY_UPDATE) enableUpdate(); if (enabled & SQLITE_NOTIFY_COMMIT) enableCommit(); diff --git a/Data/include/Poco/Data/Extraction.h b/Data/include/Poco/Data/Extraction.h index 81153c979..ddc1f0830 100644 --- a/Data/include/Poco/Data/Extraction.h +++ b/Data/include/Poco/Data/Extraction.h @@ -90,7 +90,8 @@ public: AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()), _rResult(rResult), _default(), - _extracted(false) + _extracted(false), + _null(false) /// Creates an Extraction object at specified position. /// Uses an empty object T as default value. { @@ -100,7 +101,8 @@ public: AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()), _rResult(rResult), _default(def), - _extracted(false) + _extracted(false), + _null(false) /// Creates an Extraction object at specified position. /// Uses the provided def object as default value. { @@ -180,7 +182,6 @@ public: AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()), _rResult(rResult), _default() - { _rResult.clear(); } diff --git a/Data/src/MetaColumn.cpp b/Data/src/MetaColumn.cpp index c743665a7..a4ecb1ef2 100644 --- a/Data/src/MetaColumn.cpp +++ b/Data/src/MetaColumn.cpp @@ -21,7 +21,12 @@ namespace Poco { namespace Data { -MetaColumn::MetaColumn() +MetaColumn::MetaColumn(): + _length(), + _precision(), + _position(), + _type(), + _nullable() { } diff --git a/Data/src/RecordSet.cpp b/Data/src/RecordSet.cpp index b630a3153..555fe2a03 100644 --- a/Data/src/RecordSet.cpp +++ b/Data/src/RecordSet.cpp @@ -256,8 +256,7 @@ bool RecordSet::moveFirst() return true; } - std::size_t currentRow = _currentRow; - currentRow = 0; + std::size_t currentRow = 0; while (!isAllowed(currentRow)) { if (currentRow >= rc - 1) return false; @@ -303,8 +302,7 @@ bool RecordSet::moveLast() { if (storageRowCount() > 0) { - std::size_t currentRow = _currentRow; - currentRow = storageRowCount() - 1; + std::size_t currentRow = subTotalRowCount() - 1; if (!isFiltered()) { _currentRow = currentRow; diff --git a/Data/src/SQLChannel.cpp b/Data/src/SQLChannel.cpp index 7c2afaf08..8e7130317 100644 --- a/Data/src/SQLChannel.cpp +++ b/Data/src/SQLChannel.cpp @@ -47,7 +47,10 @@ SQLChannel::SQLChannel(): _table("T_POCO_LOG"), _timeout(1000), _throw(true), - _async(true) + _async(true), + _pid(), + _tid(), + _priority() { } @@ -61,7 +64,10 @@ SQLChannel::SQLChannel(const std::string& connector, _table("T_POCO_LOG"), _timeout(1000), _throw(true), - _async(true) + _async(true), + _pid(), + _tid(), + _priority() { open(); } diff --git a/Data/src/SessionPool.cpp b/Data/src/SessionPool.cpp index 40b74d2a3..be87fb1c1 100644 --- a/Data/src/SessionPool.cpp +++ b/Data/src/SessionPool.cpp @@ -82,7 +82,7 @@ Session SessionPool::get() _idleSessions.push_front(pHolder); ++_nSessions; } - else throw SessionPoolExhaustedException(_connector, _connectionString); + else throw SessionPoolExhaustedException(_connector); } PooledSessionHolderPtr pHolder(_idleSessions.front()); diff --git a/Foundation/include/Poco/Bugcheck.h b/Foundation/include/Poco/Bugcheck.h index 941676029..06f12c24d 100644 --- a/Foundation/include/Poco/Bugcheck.h +++ b/Foundation/include/Poco/Bugcheck.h @@ -22,6 +22,7 @@ #include "Poco/Foundation.h" #include +#include #if defined(_DEBUG) # include #endif @@ -81,6 +82,28 @@ protected: // // useful macros (these automatically supply line number and file name) // +#if defined(__KLOCWORK__) || defined(__clang_analyzer__) + + +// Short-circuit these macros when under static analysis. +// Ideally, static analysis tools should understand and reason correctly about +// noreturn methods such as Bugcheck::bugcheck(). In practice, they don't. +// Help them by turning these macros into std::abort() as described here: +// https://developer.klocwork.com/documentation/en/insight/10-1/tuning-cc-analysis#Usingthe__KLOCWORK__macro + +#include // for abort +#define poco_assert_dbg(cond) do { if (!(cond)) std::abort(); } while (0) +#define poco_assert_msg_dbg(cond, text) do { if (!(cond)) std::abort(); } while (0) +#define poco_assert(cond) do { if (!(cond)) std::abort(); } while (0) +#define poco_assert_msg(cond, text) do { if (!(cond)) std::abort(); } while (0) +#define poco_check_ptr(ptr) do { if (!(ptr)) std::abort(); } while (0) +#define poco_bugcheck() do { std::abort(); } while (0) +#define poco_bugcheck_msg(msg) do { std::abort(); } while (0) + + +#else // defined(__KLOCWORK__) || defined(__clang_analyzer__) + + #if defined(_DEBUG) #define poco_assert_dbg(cond) \ if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__); else (void) 0 @@ -113,6 +136,9 @@ protected: Poco::Bugcheck::bugcheck(msg, __FILE__, __LINE__) +#endif // defined(__KLOCWORK__) || defined(__clang_analyzer__) + + #define poco_unexpected() \ Poco::Bugcheck::unexpected(__FILE__, __LINE__); diff --git a/Foundation/include/Poco/ClassLoader.h b/Foundation/include/Poco/ClassLoader.h index 1dd63a7ac..d8a5682e3 100644 --- a/Foundation/include/Poco/ClassLoader.h +++ b/Foundation/include/Poco/ClassLoader.h @@ -158,11 +158,13 @@ public: if (it == _map.end()) { LibraryInfo li; - li.pLibrary = new SharedLibrary(path); - li.pManifest = new Manif(); + li.pLibrary = 0; + li.pManifest = 0; li.refCount = 1; try { + li.pLibrary = new SharedLibrary(path); + li.pManifest = new Manif(); std::string pocoBuildManifestSymbol("pocoBuildManifest"); pocoBuildManifestSymbol.append(manifest); if (li.pLibrary->hasSymbol("pocoInitializeLibrary")) diff --git a/Foundation/include/Poco/Delegate.h b/Foundation/include/Poco/Delegate.h index eaed9c3e3..1a6a315e6 100644 --- a/Foundation/include/Poco/Delegate.h +++ b/Foundation/include/Poco/Delegate.h @@ -128,7 +128,6 @@ public: { if (&delegate != this) { - this->_pTarget = delegate._pTarget; this->_receiverObject = delegate._receiverObject; this->_receiverMethod = delegate._receiverMethod; } @@ -341,7 +340,6 @@ public: { if (&delegate != this) { - this->_pTarget = delegate._pTarget; this->_receiverObject = delegate._receiverObject; this->_receiverMethod = delegate._receiverMethod; } diff --git a/Foundation/include/Poco/Exception.h b/Foundation/include/Poco/Exception.h index fb76576c3..5e582e045 100644 --- a/Foundation/include/Poco/Exception.h +++ b/Foundation/include/Poco/Exception.h @@ -255,6 +255,8 @@ POCO_DECLARE_EXCEPTION(Foundation_API, OpenFileException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, WriteFileException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, ReadFileException, FileException) POCO_DECLARE_EXCEPTION(Foundation_API, UnknownURISchemeException, RuntimeException) +POCO_DECLARE_EXCEPTION(Foundation_API, TooManyURIRedirectsException, RuntimeException) +POCO_DECLARE_EXCEPTION(Foundation_API, URISyntaxException, SyntaxException) POCO_DECLARE_EXCEPTION(Foundation_API, ApplicationException, Exception) POCO_DECLARE_EXCEPTION(Foundation_API, BadCastException, RuntimeException) diff --git a/Foundation/include/Poco/MemoryPool.h b/Foundation/include/Poco/MemoryPool.h index 048c9e199..2ab807031 100644 --- a/Foundation/include/Poco/MemoryPool.h +++ b/Foundation/include/Poco/MemoryPool.h @@ -73,6 +73,8 @@ private: MemoryPool(const MemoryPool&); MemoryPool& operator = (const MemoryPool&); + void clear(); + enum { BLOCK_RESERVE = 128 diff --git a/Foundation/include/Poco/Nullable.h b/Foundation/include/Poco/Nullable.h index adceafd87..4b23aac6c 100644 --- a/Foundation/include/Poco/Nullable.h +++ b/Foundation/include/Poco/Nullable.h @@ -63,28 +63,32 @@ public: Nullable(): /// Creates an empty Nullable. _value(), - _isNull(true) + _isNull(true), + _null() { } Nullable(const NullType&): /// Creates an empty Nullable. _value(), - _isNull(true) + _isNull(true), + _null() { } Nullable(const C& value): /// Creates a Nullable with the given value. _value(value), - _isNull(false) + _isNull(false), + _null() { } Nullable(const Nullable& other): /// Creates a Nullable by copying another one. _value(other._value), - _isNull(other._isNull) + _isNull(other._isNull), + _null() { } diff --git a/Foundation/include/Poco/Thread_POSIX.h b/Foundation/include/Poco/Thread_POSIX.h index 5d43603ed..6963929c5 100644 --- a/Foundation/include/Poco/Thread_POSIX.h +++ b/Foundation/include/Poco/Thread_POSIX.h @@ -132,6 +132,7 @@ private: ThreadData(): thread(0), prio(PRIO_NORMAL_IMPL), + osPrio(), policy(SCHED_OTHER), done(Event::EVENT_MANUALRESET), stackSize(POCO_THREAD_STACK_SIZE), diff --git a/Foundation/src/DeflatingStream.cpp b/Foundation/src/DeflatingStream.cpp index 1adb54fb3..56d7b9146 100644 --- a/Foundation/src/DeflatingStream.cpp +++ b/Foundation/src/DeflatingStream.cpp @@ -27,13 +27,20 @@ DeflatingStreamBuf::DeflatingStreamBuf(std::istream& istr, StreamType type, int _pOstr(0), _eof(false) { + _zstr.next_in = 0; + _zstr.avail_in = 0; + _zstr.total_in = 0; + _zstr.next_out = 0; + _zstr.avail_out = 0; + _zstr.total_out = 0; + _zstr.msg = 0; + _zstr.state = 0; _zstr.zalloc = Z_NULL; _zstr.zfree = Z_NULL; _zstr.opaque = Z_NULL; - _zstr.next_in = 0; - _zstr.avail_in = 0; - _zstr.next_out = 0; - _zstr.avail_out = 0; + _zstr.data_type = 0; + _zstr.adler = 0; + _zstr.reserved = 0; _buffer = new char[DEFLATE_BUFFER_SIZE]; diff --git a/Foundation/src/Exception.cpp b/Foundation/src/Exception.cpp index fd1eacd66..e3cdd7ca7 100644 --- a/Foundation/src/Exception.cpp +++ b/Foundation/src/Exception.cpp @@ -179,9 +179,11 @@ POCO_IMPLEMENT_EXCEPTION(OpenFileException, FileException, "Cannot open file") POCO_IMPLEMENT_EXCEPTION(WriteFileException, FileException, "Cannot write file") POCO_IMPLEMENT_EXCEPTION(ReadFileException, FileException, "Cannot read file") POCO_IMPLEMENT_EXCEPTION(UnknownURISchemeException, RuntimeException, "Unknown URI scheme") - +POCO_IMPLEMENT_EXCEPTION(TooManyURIRedirectsException, RuntimeException, "Too many URI redirects") +POCO_IMPLEMENT_EXCEPTION(URISyntaxException, SyntaxException, "Bad URI syntax") POCO_IMPLEMENT_EXCEPTION(ApplicationException, Exception, "Application exception") POCO_IMPLEMENT_EXCEPTION(BadCastException, RuntimeException, "Bad cast exception") + } // namespace Poco diff --git a/Foundation/src/InflatingStream.cpp b/Foundation/src/InflatingStream.cpp index 77ecb500b..1eac3fa1a 100644 --- a/Foundation/src/InflatingStream.cpp +++ b/Foundation/src/InflatingStream.cpp @@ -16,6 +16,7 @@ #include "Poco/InflatingStream.h" #include "Poco/Exception.h" +#include namespace Poco { @@ -28,13 +29,20 @@ InflatingStreamBuf::InflatingStreamBuf(std::istream& istr, StreamType type): _eof(false), _check(type != STREAM_ZIP) { + _zstr.next_in = 0; + _zstr.avail_in = 0; + _zstr.total_in = 0; + _zstr.next_out = 0; + _zstr.avail_out = 0; + _zstr.total_out = 0; + _zstr.msg = 0; + _zstr.state = 0; _zstr.zalloc = Z_NULL; _zstr.zfree = Z_NULL; _zstr.opaque = Z_NULL; - _zstr.next_in = 0; - _zstr.avail_in = 0; - _zstr.next_out = 0; - _zstr.avail_out = 0; + _zstr.data_type = 0; + _zstr.adler = 0; + _zstr.reserved = 0; _buffer = new char[INFLATE_BUFFER_SIZE]; diff --git a/Foundation/src/MemoryPool.cpp b/Foundation/src/MemoryPool.cpp index ee940fc3f..fb83b7403 100644 --- a/Foundation/src/MemoryPool.cpp +++ b/Foundation/src/MemoryPool.cpp @@ -35,19 +35,35 @@ MemoryPool::MemoryPool(std::size_t blockLength, int preAlloc, int maxAlloc): if (maxAlloc > 0 && maxAlloc < r) r = maxAlloc; _blocks.reserve(r); - for (int i = 0; i < preAlloc; ++i) + + try { - _blocks.push_back(new char[_blockSize]); + for (int i = 0; i < preAlloc; ++i) + { + _blocks.push_back(new char[_blockSize]); + } + } + catch (...) + { + clear(); + throw; } } MemoryPool::~MemoryPool() +{ + clear(); +} + + +void MemoryPool::clear() { for (BlockVec::iterator it = _blocks.begin(); it != _blocks.end(); ++it) { delete [] *it; } + _blocks.clear(); } @@ -77,7 +93,14 @@ void MemoryPool::release(void* ptr) { FastMutex::ScopedLock lock(_mutex); - _blocks.push_back(reinterpret_cast(ptr)); + try + { + _blocks.push_back(reinterpret_cast(ptr)); + } + catch (...) + { + delete [] reinterpret_cast(ptr); + } } diff --git a/Foundation/src/StreamCopier.cpp b/Foundation/src/StreamCopier.cpp index f0c4445b1..92f923ec6 100644 --- a/Foundation/src/StreamCopier.cpp +++ b/Foundation/src/StreamCopier.cpp @@ -119,7 +119,7 @@ Poco::UInt64 StreamCopier::copyToString64(std::istream& istr, std::string& str, std::streamsize StreamCopier::copyStreamUnbuffered(std::istream& istr, std::ostream& ostr) { - char c; + char c = 0; std::streamsize len = 0; istr.get(c); while (istr && ostr) @@ -135,7 +135,7 @@ std::streamsize StreamCopier::copyStreamUnbuffered(std::istream& istr, std::ostr #if defined(POCO_HAVE_INT64) Poco::UInt64 StreamCopier::copyStreamUnbuffered64(std::istream& istr, std::ostream& ostr) { - char c; + char c = 0; Poco::UInt64 len = 0; istr.get(c); while (istr && ostr) diff --git a/Foundation/src/URI.cpp b/Foundation/src/URI.cpp index 0f375bd29..e0cbb241a 100644 --- a/Foundation/src/URI.cpp +++ b/Foundation/src/URI.cpp @@ -660,9 +660,9 @@ void URI::decode(const std::string& str, std::string& decodedStr, bool plusAsSpa if (inQuery && plusAsSpace && c == '+') c = ' '; else if (c == '%') { - if (it == end) throw SyntaxException("URI encoding: no hex digit following percent sign", str); + if (it == end) throw URISyntaxException("URI encoding: no hex digit following percent sign", str); char hi = *it++; - if (it == end) throw SyntaxException("URI encoding: two hex digits must follow percent sign", str); + if (it == end) throw URISyntaxException("URI encoding: two hex digits must follow percent sign", str); char lo = *it++; if (hi >= '0' && hi <= '9') c = hi - '0'; @@ -670,7 +670,7 @@ void URI::decode(const std::string& str, std::string& decodedStr, bool plusAsSpa c = hi - 'A' + 10; else if (hi >= 'a' && hi <= 'f') c = hi - 'a' + 10; - else throw SyntaxException("URI encoding: not a hex digit"); + else throw URISyntaxException("URI encoding: not a hex digit"); c *= 16; if (lo >= '0' && lo <= '9') c += lo - '0'; @@ -678,7 +678,7 @@ void URI::decode(const std::string& str, std::string& decodedStr, bool plusAsSpa c += lo - 'A' + 10; else if (lo >= 'a' && lo <= 'f') c += lo - 'a' + 10; - else throw SyntaxException("URI encoding: not a hex digit"); + else throw URISyntaxException("URI encoding: not a hex digit"); } decodedStr += c; } @@ -732,7 +732,7 @@ void URI::parse(const std::string& uri) if (it != end && *it == ':') { ++it; - if (it == end) throw SyntaxException("URI scheme must be followed by authority or path", uri); + if (it == end) throw URISyntaxException("URI scheme must be followed by authority or path", uri); setScheme(scheme); if (*it == '/') { @@ -786,7 +786,7 @@ void URI::parseHostAndPort(std::string::const_iterator& it, const std::string::c // IPv6 address ++it; while (it != end && *it != ']') host += *it++; - if (it == end) throw SyntaxException("unterminated IPv6 address"); + if (it == end) throw URISyntaxException("unterminated IPv6 address"); ++it; } else @@ -804,7 +804,7 @@ void URI::parseHostAndPort(std::string::const_iterator& it, const std::string::c if (NumberParser::tryParse(port, nport) && nport > 0 && nport < 65536) _port = (unsigned short) nport; else - throw SyntaxException("bad or invalid port number", port); + throw URISyntaxException("bad or invalid port number", port); } else _port = getWellKnownPort(); } diff --git a/Foundation/src/URIStreamOpener.cpp b/Foundation/src/URIStreamOpener.cpp index 825fb1c60..b9494c4e2 100644 --- a/Foundation/src/URIStreamOpener.cpp +++ b/Foundation/src/URIStreamOpener.cpp @@ -62,13 +62,27 @@ std::istream* URIStreamOpener::open(const std::string& pathOrURI) const std::string scheme(uri.getScheme()); FactoryMap::const_iterator it = _map.find(scheme); if (it != _map.end()) + { return openURI(scheme, uri); + } + else if (scheme.length() <= 1) // could be Windows path + { + Path path; + if (path.tryParse(pathOrURI, Path::PATH_GUESS)) + { + return openFile(path); + } + } + throw UnknownURISchemeException(pathOrURI); } - catch (Exception&) + catch (URISyntaxException&) { + Path path; + if (path.tryParse(pathOrURI, Path::PATH_GUESS)) + return openFile(path); + else + throw; } - Path path(pathOrURI, Path::PATH_GUESS); - return openFile(path); } @@ -84,16 +98,32 @@ std::istream* URIStreamOpener::open(const std::string& basePathOrURI, const std: if (it != _map.end()) { uri.resolve(pathOrURI); + scheme = uri.getScheme(); return openURI(scheme, uri); } + else if (scheme.length() <= 1) // could be Windows path + { + Path base; + Path path; + if (base.tryParse(basePathOrURI, Path::PATH_GUESS) && path.tryParse(pathOrURI, Path::PATH_GUESS)) + { + base.resolve(path); + return openFile(base); + } + } + throw UnknownURISchemeException(basePathOrURI); } - catch (Exception&) + catch (URISyntaxException&) { + Path base; + Path path; + if (base.tryParse(basePathOrURI, Path::PATH_GUESS) && path.tryParse(pathOrURI, Path::PATH_GUESS)) + { + base.resolve(path); + return openFile(base); + } + else throw; } - Path base(basePathOrURI, Path::PATH_GUESS); - Path path(pathOrURI, Path::PATH_GUESS); - base.resolve(path); - return openFile(base); } @@ -176,7 +206,7 @@ std::istream* URIStreamOpener::openURI(const std::string& scheme, const URI& uri ++redirects; } } - throw IOException("Too many redirects while opening URI", uri.toString()); + throw TooManyURIRedirectsException(uri.toString()); } diff --git a/JSON/src/Template.cpp b/JSON/src/Template.cpp index 862a7783a..4effd54e2 100644 --- a/JSON/src/Template.cpp +++ b/JSON/src/Template.cpp @@ -350,14 +350,16 @@ private: Template::Template(const Path& templatePath) - : _parts(NULL) + : _parts(0) + , _currentPart(0) , _templatePath(templatePath) { } Template::Template() - : _parts(NULL) + : _parts(0) + , _currentPart(0) { } diff --git a/MongoDB/include/Poco/MongoDB/Element.h b/MongoDB/include/Poco/MongoDB/Element.h index 346bef60c..e383adb7c 100644 --- a/MongoDB/include/Poco/MongoDB/Element.h +++ b/MongoDB/include/Poco/MongoDB/Element.h @@ -247,6 +247,54 @@ inline void BSONWriter::write(NullValue& from) } +struct BSONTimestamp +{ + Poco::Timestamp ts; + Poco::Int32 inc; +}; + + +// BSON Timestamp +// spec: int64 +template<> +struct ElementTraits +{ + enum { TypeId = 0x11 }; + + static std::string toString(const BSONTimestamp& value, int indent = 0) + { + std::string result; + result.append(1, '"'); + result.append(DateTimeFormatter::format(value.ts, "%Y-%m-%dT%H:%M:%s%z")); + result.append(1, ' '); + result.append(NumberFormatter::format(value.inc)); + result.append(1, '"'); + return result; + } +}; + + +template<> +inline void BSONReader::read(BSONTimestamp& to) +{ + Poco::Int64 value; + _reader >> value; + to.inc = value & 0xffffffff; + value >>= 32; + to.ts = Timestamp::fromEpochTime(static_cast(value)); +} + + +template<> +inline void BSONWriter::write(BSONTimestamp& from) +{ + Poco::Int64 value = from.ts.epochMicroseconds() / 1000; + value <<= 32; + value += from.inc; + _writer << value; +} + + // BSON 64-bit integer // spec: int64 template<> diff --git a/MongoDB/src/Document.cpp b/MongoDB/src/Document.cpp index 43f652358..a968f1780 100644 --- a/MongoDB/src/Document.cpp +++ b/MongoDB/src/Document.cpp @@ -118,6 +118,9 @@ void Document::read(BinaryReader& reader) case ElementTraits::TypeId: element = new ConcreteElement(name, Poco::Timestamp()); break; + case ElementTraits::TypeId: + element = new ConcreteElement(name, BSONTimestamp()); + break; case ElementTraits::TypeId: element = new ConcreteElement(name, NullValue(0)); break; @@ -133,7 +136,7 @@ void Document::read(BinaryReader& reader) default: { std::stringstream ss; - ss << "Element " << name << " contains an unsupported type " << std::hex << (int) type; + ss << "Element " << name << " contains an unsupported type 0x" << std::hex << (int) type; throw Poco::NotImplementedException(ss.str()); } //TODO: x0F -> JavaScript code with scope diff --git a/Net/include/Poco/Net/ICMPSocket.h b/Net/include/Poco/Net/ICMPSocket.h index 3b98dd6e8..ebc5d175e 100644 --- a/Net/include/Poco/Net/ICMPSocket.h +++ b/Net/include/Poco/Net/ICMPSocket.h @@ -42,7 +42,7 @@ public: ICMPSocket(const Socket& socket); /// Creates the ICMPSocket with the SocketImpl /// from another socket. The SocketImpl must be - /// a DatagramSocketImpl, otherwise an InvalidArgumentException + /// a ICMPSocketImpl, otherwise an InvalidArgumentException /// will be thrown. ~ICMPSocket(); @@ -84,35 +84,9 @@ protected: /// /// The SocketImpl must be a ICMPSocketImpl, otherwise /// an InvalidArgumentException will be thrown. - -private: - int _dataSize; - int _ttl; - int _timeout; }; -// -// inlines -// -inline int ICMPSocket::dataSize() const -{ - return _dataSize; -} - - -inline int ICMPSocket::ttl() const -{ - return _ttl; -} - - -inline int ICMPSocket::timeout() const -{ - return _timeout; -} - - } } // namespace Poco::Net diff --git a/Net/include/Poco/Net/ICMPSocketImpl.h b/Net/include/Poco/Net/ICMPSocketImpl.h index 771c5a227..b59988e0b 100644 --- a/Net/include/Poco/Net/ICMPSocketImpl.h +++ b/Net/include/Poco/Net/ICMPSocketImpl.h @@ -50,15 +50,46 @@ public: /// /// Returns the time elapsed since the originating request was sent. + int dataSize() const; + /// Returns the data size in bytes. + + int ttl() const; + /// Returns the Time-To-Live value. + + int timeout() const; + /// Returns the socket timeout value. + protected: ~ICMPSocketImpl(); private: ICMPPacket _icmpPacket; + int _ttl; int _timeout; }; +// +// inlines +// +inline int ICMPSocketImpl::dataSize() const +{ + return _icmpPacket.getDataSize(); +} + + +inline int ICMPSocketImpl::ttl() const +{ + return _ttl; +} + + +inline int ICMPSocketImpl::timeout() const +{ + return _timeout; +} + + } } // namespace Poco::Net diff --git a/Net/src/HTTPResponse.cpp b/Net/src/HTTPResponse.cpp index cf6a47b4f..8782d3cc8 100644 --- a/Net/src/HTTPResponse.cpp +++ b/Net/src/HTTPResponse.cpp @@ -242,6 +242,7 @@ void HTTPResponse::read(std::istream& istr) while (ch != '\r' && ch != '\n' && ch != eof && reason.length() < MAX_REASON_LENGTH) { reason += (char) ch; ch = istr.get(); } if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP reason string too long"); if (ch == '\r') ch = istr.get(); + if (ch != '\n') throw MessageException("Unterminated HTTP response line"); HTTPMessage::read(istr); ch = istr.get(); diff --git a/Net/src/ICMPSocket.cpp b/Net/src/ICMPSocket.cpp index ece9871c3..7e1204fe1 100644 --- a/Net/src/ICMPSocket.cpp +++ b/Net/src/ICMPSocket.cpp @@ -27,10 +27,7 @@ namespace Net { ICMPSocket::ICMPSocket(IPAddress::Family family, int dataSize, int ttl, int timeout): - Socket(new ICMPSocketImpl(family, dataSize, ttl, timeout)), - _dataSize(dataSize), - _ttl(ttl), - _timeout(timeout) + Socket(new ICMPSocketImpl(family, dataSize, ttl, timeout)) { } @@ -78,4 +75,22 @@ int ICMPSocket::receiveFrom(SocketAddress& address, int flags) } +int ICMPSocket::dataSize() const +{ + return static_cast(impl())->dataSize(); +} + + +int ICMPSocket::ttl() const +{ + return static_cast(impl())->ttl(); +} + + +int ICMPSocket::timeout() const +{ + return static_cast(impl())->timeout(); +} + + } } // namespace Poco::Net diff --git a/Net/src/ICMPSocketImpl.cpp b/Net/src/ICMPSocketImpl.cpp index 2deefbaae..11ebc30d2 100644 --- a/Net/src/ICMPSocketImpl.cpp +++ b/Net/src/ICMPSocketImpl.cpp @@ -19,6 +19,7 @@ #include "Poco/Timespan.h" #include "Poco/Timestamp.h" #include "Poco/Exception.h" +#include "Poco/Buffer.h" using Poco::TimeoutException; @@ -33,6 +34,7 @@ namespace Net { ICMPSocketImpl::ICMPSocketImpl(IPAddress::Family family, int dataSize, int ttl, int timeout): RawSocketImpl(family, IPPROTO_ICMP), _icmpPacket(family, dataSize), + _ttl(ttl), _timeout(timeout) { setOption(IPPROTO_IP, IP_TTL, ttl); @@ -55,7 +57,7 @@ int ICMPSocketImpl::sendTo(const void*, int, const SocketAddress& address, int f int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags) { int maxPacketSize = _icmpPacket.maxPacketSize(); - unsigned char* buffer = new unsigned char[maxPacketSize]; + Poco::Buffer buffer(maxPacketSize); try { @@ -68,31 +70,24 @@ int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags) // fake ping responses will cause an endless loop. throw TimeoutException(); } - SocketImpl::receiveFrom(buffer, maxPacketSize, address, flags); + SocketImpl::receiveFrom(buffer.begin(), maxPacketSize, address, flags); } - while (!_icmpPacket.validReplyID(buffer, maxPacketSize)); - } - catch (TimeoutException&) - { - delete [] buffer; - throw; + while (!_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)); } catch (Exception&) { - std::string err = _icmpPacket.errorDescription(buffer, maxPacketSize); - delete [] buffer; + std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize); if (!err.empty()) throw ICMPException(err); else throw; } - struct timeval then = _icmpPacket.time(buffer, maxPacketSize); + struct timeval then = _icmpPacket.time(buffer.begin(), maxPacketSize); struct timeval now = _icmpPacket.time(); int elapsed = (((now.tv_sec * 1000000) + now.tv_usec) - ((then.tv_sec * 1000000) + then.tv_usec))/1000; - delete[] buffer; return elapsed; } diff --git a/Net/src/MailMessage.cpp b/Net/src/MailMessage.cpp index 69a6d88c1..3fa4641ba 100644 --- a/Net/src/MailMessage.cpp +++ b/Net/src/MailMessage.cpp @@ -105,18 +105,21 @@ namespace poco_check_ptr (pPS); NameValueCollection::ConstIterator it = header.begin(); NameValueCollection::ConstIterator end = header.end(); + bool added = false; for (; it != end; ++it) { - if (MailMessage::HEADER_CONTENT_DISPOSITION == it->first) + if (!added && MailMessage::HEADER_CONTENT_DISPOSITION == it->first) { if (it->second == "inline") _pMsg->addContent(pPS, cte); else _pMsg->addAttachment("", pPS, cte); + added = true; } pPS->headers().set(it->first, it->second); } + if (!added) delete pPS; } } @@ -191,6 +194,7 @@ const std::string MailMessage::CTE_BASE64("base64"); MailMessage::MailMessage(PartStoreFactory* pStoreFactory): + _encoding(), _pStoreFactory(pStoreFactory) { Poco::Timestamp now; diff --git a/Net/src/MultipartReader.cpp b/Net/src/MultipartReader.cpp index 1ee9a98e5..d167906d3 100644 --- a/Net/src/MultipartReader.cpp +++ b/Net/src/MultipartReader.cpp @@ -88,13 +88,13 @@ int MultipartStreamBuf::readFromDevice(char* buffer, std::streamsize length) { if (ch == '\r') { - ch = buf.sbumpc(); // '\n' + buf.sbumpc(); // '\n' } return 0; } else if (ch == '-' && buf.sgetc() == '-') { - ch = buf.sbumpc(); // '-' + buf.sbumpc(); // '-' _lastPart = true; return 0; } @@ -268,7 +268,7 @@ void MultipartReader::guessBoundary() ch = _istr.peek(); } if (ch == '\r' || ch == '\n') - ch = _istr.get(); + _istr.get(); if (_istr.peek() == '\n') _istr.get(); } @@ -281,7 +281,7 @@ void MultipartReader::parseHeader(MessageHeader& messageHeader) messageHeader.clear(); messageHeader.read(_istr); int ch = _istr.get(); - if (ch == '\r' && _istr.peek() == '\n') ch = _istr.get(); + if (ch == '\r' && _istr.peek() == '\n') _istr.get(); } diff --git a/Net/src/NetworkInterface.cpp b/Net/src/NetworkInterface.cpp index 85ae403f2..359df059b 100644 --- a/Net/src/NetworkInterface.cpp +++ b/Net/src/NetworkInterface.cpp @@ -228,7 +228,8 @@ NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, _pointToPoint(false), _up(false), _running(false), - _mtu(0) + _mtu(0), + _type(NetworkInterface::NI_TYPE_OTHER) { _addressList.push_back(AddressTuple(address, subnetMask, broadcastAddress)); setPhyParams(); diff --git a/Net/src/QuotedPrintableDecoder.cpp b/Net/src/QuotedPrintableDecoder.cpp index 331d8b148..d664f63ae 100644 --- a/Net/src/QuotedPrintableDecoder.cpp +++ b/Net/src/QuotedPrintableDecoder.cpp @@ -48,7 +48,7 @@ int QuotedPrintableDecoderBuf::readFromDevice() ch = _buf.sbumpc(); if (ch == '\r') { - ch = _buf.sbumpc(); // read \n + _buf.sbumpc(); // read \n } else if (Poco::Ascii::isHexDigit(ch)) { diff --git a/Net/src/SocketAddress.cpp b/Net/src/SocketAddress.cpp index 1c2608394..fa5290472 100644 --- a/Net/src/SocketAddress.cpp +++ b/Net/src/SocketAddress.cpp @@ -170,7 +170,7 @@ SocketAddress& SocketAddress::operator = (const SocketAddress& socketAddress) destruct(); if (socketAddress.family() == IPv4) newIPv4(reinterpret_cast(socketAddress.addr())); -#if defined(POCO_HAVE_IPv6) +#if defined(POCO_HAVE_IPv6) else if (socketAddress.family() == IPv6) newIPv6(reinterpret_cast(socketAddress.addr())); #endif @@ -252,7 +252,7 @@ void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber { #if defined(POCO_HAVE_IPv6) // if we get both IPv4 and IPv6 addresses, prefer IPv4 - std::sort(addresses.begin(), addresses.end(), AFLT()); + std::stable_sort(addresses.begin(), addresses.end(), AFLT()); #endif init(addresses[0], portNumber); } @@ -285,7 +285,7 @@ void SocketAddress::init(const std::string& hostAndPort) std::string port; std::string::const_iterator it = hostAndPort.begin(); std::string::const_iterator end = hostAndPort.end(); - + #if defined(POCO_OS_FAMILY_UNIX) if (*it == '/') { diff --git a/NetSSL_OpenSSL/src/ConsoleCertificateHandler.cpp b/NetSSL_OpenSSL/src/ConsoleCertificateHandler.cpp index 40cf8ce8b..839ea13a9 100644 --- a/NetSSL_OpenSSL/src/ConsoleCertificateHandler.cpp +++ b/NetSSL_OpenSSL/src/ConsoleCertificateHandler.cpp @@ -43,7 +43,7 @@ void ConsoleCertificateHandler::onInvalidCertificate(const void*, VerificationEr std::cout << "The certificate yielded the error: " << errorCert.errorMessage() << "\n\n"; std::cout << "The error occurred in the certificate chain at position " << errorCert.errorDepth() << "\n"; std::cout << "Accept the certificate (y,n)? "; - char c; + char c = 0; std::cin >> c; if (c == 'y' || c == 'Y') errorCert.setIgnoreError(true); diff --git a/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp b/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp index 37c3a47be..67296cd6d 100644 --- a/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp +++ b/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp @@ -132,7 +132,8 @@ std::istream* HTTPSStreamFactory::open(const URI& uri) resolvedURI.setUserInfo(username + ":" + password); authorize = false; } - delete pSession; pSession = 0; + delete pSession; + pSession = 0; ++redirects; retry = true; } diff --git a/PageCompiler/src/PageReader.cpp b/PageCompiler/src/PageReader.cpp index d435ca07f..02a08a110 100644 --- a/PageCompiler/src/PageReader.cpp +++ b/PageCompiler/src/PageReader.cpp @@ -267,7 +267,7 @@ void PageReader::nextToken(std::istream& istr, std::string& token) if (ch == '<' && istr.peek() == '%') { token += "<%"; - ch = istr.get(); + istr.get(); ch = istr.peek(); switch (ch) { @@ -300,7 +300,7 @@ void PageReader::nextToken(std::istream& istr, std::string& token) else if (ch == '%' && istr.peek() == '>') { token += "%>"; - ch = istr.get(); + istr.get(); } else token += (char) ch; } diff --git a/README.md b/README.md index 7e67491b7..90f1024d0 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Build Status - Travis: [![Travis Build Status](https://travis-ci.org/pocoproject/poco.png?branch=develop)](https://travis-ci.org/pocoproject/poco) - AppVeyor: [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/7iyrx3f233s3akae)](https://ci.appveyor.com/project/obiltschnig/poco) +- [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/370/badge)](https://bestpractices.coreinfrastructure.org/projects/370) ![alt text][logo] @@ -21,11 +22,13 @@ POrtable COmponents C++ Libraries are: - Open Source, licensed under the [Boost Software License](https://spdx.org/licenses/BSL-1.0). ---- -To start using POCO, see the [Guided Tour](http://pocoproject.org/docs/00100-GuidedTour.html) and [Getting Started](http://pocoproject.org/docs/00200-GettingStarted.html) documents. +To start using POCO, see the [Guided Tour](https://pocoproject.org/docs/00100-GuidedTour.html) and [Getting Started](https://pocoproject.org/docs/00200-GettingStarted.html) documents. ---- -POCO has an active user and contributing community, please visit our [web site](http://pocoproject.org), [forum](http://pocoproject.org/forum) and [blog](http://pocoproject.org/blog). -Answers to POCO-related questions can also be found on [Stack Overflow](http://stackoverflow.com/questions/tagged/poco-libraries). +POCO has an active user and contributing community, please visit our [web site](https://pocoproject.org), [forum](https://pocoproject.org/forum) and [blog](https://pocoproject.org/blog). +Answers to POCO-related questions can also be found on [Stack Overflow](https://stackoverflow.com/questions/tagged/poco-libraries). + +Please see [CONTRIBUTING](CONTRIBUTING.md) for submitting contributions, bugs reports, feature requests or security issues. ---- In regards to Boost, in spite of some functional overlapping, diff --git a/XML/src/ParserEngine.cpp b/XML/src/ParserEngine.cpp index 89c2385f1..bd1cdc5dd 100644 --- a/XML/src/ParserEngine.cpp +++ b/XML/src/ParserEngine.cpp @@ -450,19 +450,27 @@ void ParserEngine::init() if (dynamic_cast(_pNamespaceStrategy)) { _parser = XML_ParserCreateNS(_encodingSpecified ? _encoding.c_str() : 0, '\t'); - XML_SetNamespaceDeclHandler(_parser, handleStartNamespaceDecl, handleEndNamespaceDecl); + if (_parser) + { + XML_SetNamespaceDeclHandler(_parser, handleStartNamespaceDecl, handleEndNamespaceDecl); + } } else if (dynamic_cast(_pNamespaceStrategy)) { _parser = XML_ParserCreateNS(_encodingSpecified ? _encoding.c_str() : 0, '\t'); - XML_SetReturnNSTriplet(_parser, 1); - XML_SetNamespaceDeclHandler(_parser, handleStartNamespaceDecl, handleEndNamespaceDecl); + if (_parser) + { + XML_SetReturnNSTriplet(_parser, 1); + XML_SetNamespaceDeclHandler(_parser, handleStartNamespaceDecl, handleEndNamespaceDecl); + } } else { _parser = XML_ParserCreate(_encodingSpecified ? _encoding.c_str() : 0); } + if (!_parser) throw XMLException("Cannot create Expat parser"); + XML_SetUserData(_parser, this); XML_SetElementHandler(_parser, handleStartElement, handleEndElement); XML_SetCharacterDataHandler(_parser, handleCharacterData); @@ -720,6 +728,8 @@ int ParserEngine::handleExternalEntityRef(XML_Parser parser, const XML_Char* con if (pInputSource) { XML_Parser extParser = XML_ExternalEntityParserCreate(pThis->_parser, context, 0); + if (!extParser) throw XMLException("Cannot create external entity parser"); + try { pThis->parseExternal(extParser, pInputSource); diff --git a/Zip/include/Poco/Zip/ZipArchive.h b/Zip/include/Poco/Zip/ZipArchive.h index aa5a8498c..150f003e9 100644 --- a/Zip/include/Poco/Zip/ZipArchive.h +++ b/Zip/include/Poco/Zip/ZipArchive.h @@ -24,7 +24,6 @@ #include "Poco/Zip/ZipLocalFileHeader.h" #include "Poco/Zip/ZipFileInfo.h" #include "Poco/Zip/ZipArchiveInfo.h" - #include #include diff --git a/Zip/src/AutoDetectStream.cpp b/Zip/src/AutoDetectStream.cpp index 1229e3294..3664df9a1 100644 --- a/Zip/src/AutoDetectStream.cpp +++ b/Zip/src/AutoDetectStream.cpp @@ -69,6 +69,7 @@ int AutoDetectStreamBuf::readFromDevice(char* buffer, std::streamsize length) { _pIstr->seekg(_start, std::ios_base::beg); _reposition = false; + if (!_pIstr->good()) return -1; } if (!_prefix.empty()) @@ -145,11 +146,9 @@ int AutoDetectStreamBuf::readFromDevice(char* buffer, std::streamsize length) { if (c-1 == byte3) { - // a match, pushback - _pIstr->putback(c); - _pIstr->putback(byte3); - _pIstr->putback(ZipLocalFileHeader::HEADER[1]); - _pIstr->putback(ZipLocalFileHeader::HEADER[0]); + // a match, seek back + _pIstr->seekg(-4, std::ios::cur); + if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream"); _eofDetected = true; return tempPos; } diff --git a/Zip/src/Compress.cpp b/Zip/src/Compress.cpp index b335a3074..b74333d1a 100644 --- a/Zip/src/Compress.cpp +++ b/Zip/src/Compress.cpp @@ -78,7 +78,7 @@ void Compress::addEntry(std::istream& in, const Poco::DateTime& lastModifiedAt, _offset = hdr.getEndPos(); _offset += extraDataSize; _files.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), hdr)); - poco_assert (_out); + if (!_out) throw Poco::IOException("Bad output stream"); ZipFileInfo nfo(hdr); nfo.setOffset(localHeaderOffset); nfo.setZip64Data(); @@ -89,12 +89,13 @@ void Compress::addEntry(std::istream& in, const Poco::DateTime& lastModifiedAt, void Compress::addFileRaw(std::istream& in, const ZipLocalFileHeader& h, const Poco::Path& fileName) { + if (!in.good()) + throw ZipException("Invalid input stream"); + std::string fn = ZipUtil::validZipEntryFileName(fileName); //bypass the header of the input stream and point to the first byte of the data payload in.seekg(h.getDataStartPos(), std::ios_base::beg); - - if (!in.good()) - throw ZipException("Invalid input stream"); + if (!in.good()) throw Poco::IOException("Failed to seek on input stream"); std::streamoff localHeaderOffset = _offset; ZipLocalFileHeader hdr(h); @@ -161,7 +162,7 @@ void Compress::addFileRaw(std::istream& in, const ZipLocalFileHeader& h, const P } _files.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), hdr)); - poco_assert (_out); + if (!_out) throw Poco::IOException("Bad output stream"); ZipFileInfo nfo(hdr); nfo.setOffset(localHeaderOffset); nfo.setZip64Data(); @@ -229,7 +230,7 @@ void Compress::addDirectory(const Poco::Path& entryName, const Poco::DateTime& l if (hdr.searchCRCAndSizesAfterData()) _offset += extraDataSize; _files.insert(std::make_pair(entryName.toString(Poco::Path::PATH_UNIX), hdr)); - poco_assert (_out); + if (!_out) throw Poco::IOException("Bad output stream"); ZipFileInfo nfo(hdr); nfo.setOffset(localHeaderOffset); nfo.setZip64Data(); @@ -314,7 +315,7 @@ ZipArchive Compress::close() centralDirSize64 += entrySize; _offset += entrySize; } - poco_assert (_out); + if (!_out) throw Poco::IOException("Bad output stream"); Poco::UInt64 numEntries64 = _infos.size(); needZip64 = needZip64 || _offset >= ZipCommon::ZIP64_MAGIC; diff --git a/Zip/src/Decompress.cpp b/Zip/src/Decompress.cpp index 2f94fa949..e01f47e9d 100644 --- a/Zip/src/Decompress.cpp +++ b/Zip/src/Decompress.cpp @@ -39,7 +39,7 @@ Decompress::Decompress(std::istream& in, const Poco::Path& outputDir, bool flatt { _outDir.makeAbsolute(); _outDir.makeDirectory(); - poco_assert (_in.good()); + if (!_in.good()) throw Poco::IOException("Bad input stream"); Poco::File tmp(_outDir); if (!tmp.exists()) { diff --git a/Zip/src/PartialStream.cpp b/Zip/src/PartialStream.cpp index 85587278e..d6d9e302b 100644 --- a/Zip/src/PartialStream.cpp +++ b/Zip/src/PartialStream.cpp @@ -69,7 +69,7 @@ int PartialStreamBuf::readFromDevice(char* buffer, std::streamsize length) _pIstr->clear(); _pIstr->seekg(_start, std::ios_base::beg); if (_pIstr->fail()) - throw Poco::IOException("Failed to reposition in stream"); + throw Poco::IOException("Failed to seek on input stream"); } if (!_prefix.empty()) { diff --git a/Zip/src/SkipCallback.cpp b/Zip/src/SkipCallback.cpp index 20d0ca491..febbd0af6 100644 --- a/Zip/src/SkipCallback.cpp +++ b/Zip/src/SkipCallback.cpp @@ -17,6 +17,7 @@ #include "Poco/Zip/SkipCallback.h" #include "Poco/Zip/ZipLocalFileHeader.h" #include "Poco/Zip/ZipUtil.h" +#include "Poco/Exception.h" namespace Poco { @@ -39,6 +40,7 @@ bool SkipCallback::handleZipEntry(std::istream& zipStream, const ZipLocalFileHea zipStream.seekg(hdr.getCompressedSize(), std::ios_base::cur); else ZipUtil::sync(zipStream); + if (!zipStream.good()) throw Poco::IOException("Failed to seek on input stream"); return true; } diff --git a/Zip/src/ZipArchiveInfo.cpp b/Zip/src/ZipArchiveInfo.cpp index 9299eb4cb..6985efab3 100644 --- a/Zip/src/ZipArchiveInfo.cpp +++ b/Zip/src/ZipArchiveInfo.cpp @@ -59,12 +59,16 @@ void ZipArchiveInfo::parse(std::istream& inp, bool assumeHeaderRead) if (!assumeHeaderRead) { inp.read(_rawInfo, ZipCommon::HEADER_SIZE); + if (inp.gcount() != ZipCommon::HEADER_SIZE) + throw Poco::IOException("Failed to read archive info header"); + if (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) != 0) + throw Poco::DataFormatException("Bad archive info header"); } else { std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE); } - poco_assert (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) == 0); + // read the rest of the header inp.read(_rawInfo + ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE); Poco::UInt16 len = getZipCommentSize(); @@ -136,12 +140,16 @@ void ZipArchiveInfo64::parse(std::istream& inp, bool assumeHeaderRead) if (!assumeHeaderRead) { inp.read(_rawInfo, ZipCommon::HEADER_SIZE); + if (inp.gcount() != ZipCommon::HEADER_SIZE) + throw Poco::IOException("Failed to read archive info header"); + if (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) != 0) + throw Poco::DataFormatException("Bad archive info header"); } else { std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE); } - poco_assert (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) == 0); + std::memset(_rawInfo + ZipCommon::HEADER_SIZE, 0, FULL_HEADER_SIZE - ZipCommon::HEADER_SIZE); // read the rest of the header @@ -164,7 +172,11 @@ void ZipArchiveInfo64::parse(std::istream& inp, bool assumeHeaderRead) ZipUtil::set64BitValue(FULL_HEADER_SIZE + len - offset, _rawInfo, RECORDSIZE_POS); } inp.read(_locInfo, FULL_LOCATOR_SIZE); - poco_assert (std::memcmp(_locInfo, LOCATOR_HEADER, ZipCommon::HEADER_SIZE) == 0); + if (inp.gcount() != FULL_LOCATOR_SIZE) + throw Poco::IOException("Failed to read locator"); + if (std::memcmp(_locInfo, LOCATOR_HEADER, ZipCommon::HEADER_SIZE) != 0) + throw Poco::DataFormatException("Bad locator header"); + } diff --git a/Zip/src/ZipDataInfo.cpp b/Zip/src/ZipDataInfo.cpp index c2b6bf645..e03b82074 100644 --- a/Zip/src/ZipDataInfo.cpp +++ b/Zip/src/ZipDataInfo.cpp @@ -15,6 +15,7 @@ #include "Poco/Zip/ZipDataInfo.h" +#include "Poco/Exception.h" #include #include @@ -47,10 +48,11 @@ ZipDataInfo::ZipDataInfo(std::istream& in, bool assumeHeaderRead): else { in.read(_rawInfo, ZipCommon::HEADER_SIZE); - if ((!in) || (in.gcount() != ZipCommon::HEADER_SIZE)) - return; + if (in.gcount() != ZipCommon::HEADER_SIZE) + throw Poco::IOException("Failed to read data info header"); + if (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) != 0) + throw Poco::DataFormatException("Bad data info header"); } - poco_assert (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) == 0); // now copy the rest of the header in.read(_rawInfo+ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE); _valid = (!in.eof() && in.good()); @@ -87,10 +89,12 @@ ZipDataInfo64::ZipDataInfo64(std::istream& in, bool assumeHeaderRead): else { in.read(_rawInfo, ZipCommon::HEADER_SIZE); - if ((!in) || (in.gcount() != ZipCommon::HEADER_SIZE)) - return; + if (in.gcount() != ZipCommon::HEADER_SIZE) + throw Poco::IOException("Failed to read data info header"); + if (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) != 0) + throw Poco::DataFormatException("Bad data info header"); } - poco_assert (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) == 0); + // now copy the rest of the header in.read(_rawInfo+ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE); _valid = (!in.eof() && in.good()); diff --git a/Zip/src/ZipFileInfo.cpp b/Zip/src/ZipFileInfo.cpp index c426e247a..e23d0870e 100644 --- a/Zip/src/ZipFileInfo.cpp +++ b/Zip/src/ZipFileInfo.cpp @@ -87,12 +87,16 @@ void ZipFileInfo::parse(std::istream& inp, bool assumeHeaderRead) if (!assumeHeaderRead) { inp.read(_rawInfo, ZipCommon::HEADER_SIZE); + if (inp.gcount() != ZipCommon::HEADER_SIZE) + throw Poco::IOException("Failed to read file info header"); + if (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) != 0) + throw Poco::DataFormatException("Bad file info header"); } else { std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE); } - poco_assert (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) == 0); + // read the rest of the header inp.read(_rawInfo + ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE); _crc32 = getCRCFromHeader(); @@ -101,34 +105,53 @@ void ZipFileInfo::parse(std::istream& inp, bool assumeHeaderRead) _localHeaderOffset = getOffsetFromHeader(); parseDateTime(); Poco::UInt16 len = getFileNameLength(); - Poco::Buffer buf(len); - inp.read(buf.begin(), len); - _fileName = std::string(buf.begin(), len); + if (len > 0) + { + Poco::Buffer buf(len); + inp.read(buf.begin(), len); + _fileName = std::string(buf.begin(), len); + } if (hasExtraField()) { len = getExtraFieldLength(); - Poco::Buffer xtra(len); - inp.read(xtra.begin(), len); - _extraField = std::string(xtra.begin(), len); - char* ptr = xtra.begin(); - while(ptr <= xtra.begin() + len - 4) { - Poco::UInt16 id = ZipUtil::get16BitValue(ptr, 0); ptr +=2; - Poco::UInt16 size = ZipUtil::get16BitValue(ptr, 0); ptr += 2; - if(id == ZipCommon::ZIP64_EXTRA_ID) { - poco_assert(size >= 8); - if(getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) { - setUncompressedSize(ZipUtil::get64BitValue(ptr, 0)); size -= 8; ptr += 8; - } - if(size >= 8 && getCompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) { - setCompressedSize(ZipUtil::get64BitValue(ptr, 0)); size -= 8; ptr += 8; - } - if(size >= 8 && getOffsetFromHeader() == ZipCommon::ZIP64_MAGIC) { - setOffset(ZipUtil::get64BitValue(ptr, 0)); size -= 8; ptr += 8; - } - } - else + if (len > 0) + { + Poco::Buffer xtra(len); + inp.read(xtra.begin(), len); + _extraField = std::string(xtra.begin(), len); + char* ptr = xtra.begin(); + while (ptr <= xtra.begin() + len - 4) { - ptr += size; + Poco::UInt16 id = ZipUtil::get16BitValue(ptr, 0); + ptr += 2; + Poco::UInt16 size = ZipUtil::get16BitValue(ptr, 0); + ptr += 2; + if (id == ZipCommon::ZIP64_EXTRA_ID) + { + poco_assert(size >= 8); + if (getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) + { + setUncompressedSize(ZipUtil::get64BitValue(ptr, 0)); + size -= 8; + ptr += 8; + } + if (size >= 8 && getCompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) + { + setCompressedSize(ZipUtil::get64BitValue(ptr, 0)); + size -= 8; + ptr += 8; + } + if (size >= 8 && getOffsetFromHeader() == ZipCommon::ZIP64_MAGIC) + { + setOffset(ZipUtil::get64BitValue(ptr, 0)); + size -= 8; + ptr += 8; + } + } + else + { + ptr += size; + } } } } diff --git a/Zip/src/ZipLocalFileHeader.cpp b/Zip/src/ZipLocalFileHeader.cpp index a2a7eb7ba..aab16fdf1 100644 --- a/Zip/src/ZipLocalFileHeader.cpp +++ b/Zip/src/ZipLocalFileHeader.cpp @@ -118,23 +118,30 @@ void ZipLocalFileHeader::parse(std::istream& inp, bool assumeHeaderRead) if (!assumeHeaderRead) { inp.read(_rawHeader, ZipCommon::HEADER_SIZE); + if (inp.gcount() != ZipCommon::HEADER_SIZE) + throw Poco::IOException("Failed to read local file header"); + if (std::memcmp(_rawHeader, HEADER, ZipCommon::HEADER_SIZE) != 0) + throw Poco::DataFormatException("Bad local file header"); } else { std::memcpy(_rawHeader, HEADER, ZipCommon::HEADER_SIZE); } - poco_assert (std::memcmp(_rawHeader, HEADER, ZipCommon::HEADER_SIZE) == 0); - // read the rest of the header + + // read the rest of the header inp.read(_rawHeader + ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE); poco_assert (_rawHeader[VERSION_POS + 1]>= ZipCommon::HS_FAT && _rawHeader[VERSION_POS + 1] < ZipCommon::HS_UNUSED); poco_assert (getMajorVersionNumber() <= 4); // Allow for Zip64 version 4.5 poco_assert (ZipUtil::get16BitValue(_rawHeader, COMPR_METHOD_POS) < ZipCommon::CM_UNUSED); parseDateTime(); Poco::UInt16 len = getFileNameLength(); - Poco::Buffer buf(len); - inp.read(buf.begin(), len); - _fileName = std::string(buf.begin(), len); - + if (len > 0) + { + Poco::Buffer buf(len); + inp.read(buf.begin(), len); + _fileName = std::string(buf.begin(), len); + } + if (!searchCRCAndSizesAfterData()) { _crc32 = getCRCFromHeader(); @@ -145,33 +152,41 @@ void ZipLocalFileHeader::parse(std::istream& inp, bool assumeHeaderRead) if (hasExtraField()) { len = getExtraFieldLength(); - Poco::Buffer xtra(len); - inp.read(xtra.begin(), len); - _extraField = std::string(xtra.begin(), len); - char* ptr = xtra.begin(); - while (ptr <= xtra.begin() + len - 4) + if (len > 0) { - Poco::UInt16 id = ZipUtil::get16BitValue(ptr, 0); ptr +=2; - Poco::UInt16 size = ZipUtil::get16BitValue(ptr, 0); ptr += 2; - if (id == ZipCommon::ZIP64_EXTRA_ID) - { - poco_assert(size >= 8); - if (getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) - { - setUncompressedSize(ZipUtil::get64BitValue(ptr, 0)); size -= 8; ptr += 8; - } - if (size >= 8 && getCompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) - { - setCompressedSize(ZipUtil::get64BitValue(ptr, 0)); size -= 8; ptr += 8; - } - } - else - { - ptr += size; - } + Poco::Buffer xtra(len); + inp.read(xtra.begin(), len); + _extraField = std::string(xtra.begin(), len); + char* ptr = xtra.begin(); + while (ptr <= xtra.begin() + len - 4) + { + Poco::UInt16 id = ZipUtil::get16BitValue(ptr, 0); + ptr += 2; + Poco::UInt16 size = ZipUtil::get16BitValue(ptr, 0); + ptr += 2; + if (id == ZipCommon::ZIP64_EXTRA_ID) + { + poco_assert(size >= 8); + if (getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) + { + setUncompressedSize(ZipUtil::get64BitValue(ptr, 0)); + size -= 8; + ptr += 8; + } + if (size >= 8 && getCompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) + { + setCompressedSize(ZipUtil::get64BitValue(ptr, 0)); + size -= 8; + ptr += 8; + } + } + else + { + ptr += size; + } + } } } - } diff --git a/Zip/src/ZipManipulator.cpp b/Zip/src/ZipManipulator.cpp index 5fc00e9ae..73e8e7e1c 100644 --- a/Zip/src/ZipManipulator.cpp +++ b/Zip/src/ZipManipulator.cpp @@ -111,7 +111,7 @@ const ZipLocalFileHeader& ZipManipulator::getForChange(const std::string& zipPat { ZipArchive::FileHeaders::const_iterator it = _in->findHeader(zipPath); if (it == _in->headerEnd()) - throw ZipManipulationException("entry not found: " + zipPath); + throw ZipManipulationException("Entry not found: " + zipPath); if (_changes.find(zipPath) != _changes.end()) throw ZipManipulationException("A change request exists already for entry " + zipPath); diff --git a/Zip/src/ZipStream.cpp b/Zip/src/ZipStream.cpp index fdda20eb2..26514feb5 100644 --- a/Zip/src/ZipStream.cpp +++ b/Zip/src/ZipStream.cpp @@ -177,8 +177,8 @@ int ZipStreamBuf::readFromDevice(char* buffer, std::streamsize length) Poco::Int32 size = static_cast(nfo.getFullHeaderSize()); _expectedCrc32 = nfo.getCRC32(); const char* rawHeader = nfo.getRawHeader(); - for (Poco::Int32 i = size-1; i >= 0; --i) - _pIstr->putback(rawHeader[i]); + _pIstr->seekg(-size, std::ios::cur); + if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream"); if (!crcValid()) throw ZipException("CRC failure"); } @@ -215,7 +215,8 @@ void ZipStreamBuf::close(Poco::UInt64& extraDataSize) _ptrOHelper->close(); } _ptrOBuf = 0; - poco_assert (*_pOstr); + if (!*_pOstr) throw Poco::IOException("Bad output stream"); + // write an extra datablock if required // or fix the crc entries poco_check_ptr(_pHeader); @@ -248,13 +249,14 @@ void ZipStreamBuf::close(Poco::UInt64& extraDataSize) else { _pOstr->seekp(_pHeader->getStartPos(), std::ios_base::beg); - poco_assert (*_pOstr); + if (!*_pOstr) throw Poco::IOException("Bad output stream"); + if (_pHeader->hasExtraField()) // Update sizes in header extension. _pHeader->setZip64Data(); std::string header = _pHeader->createHeader(); _pOstr->write(header.c_str(), static_cast(header.size())); _pOstr->seekp(0, std::ios_base::end); - poco_assert (*_pOstr); + if (!*_pOstr) throw Poco::IOException("Bad output stream"); } _pHeader = 0; } diff --git a/Zip/src/ZipUtil.cpp b/Zip/src/ZipUtil.cpp index 069074651..7bdb76dfe 100644 --- a/Zip/src/ZipUtil.cpp +++ b/Zip/src/ZipUtil.cpp @@ -117,31 +117,23 @@ void ZipUtil::sync(std::istream& in) { if (std::memcmp(ZipLocalFileHeader::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0) { - in.putback(ZipLocalFileHeader::HEADER[3]); - in.putback(ZipLocalFileHeader::HEADER[2]); - in.putback(ZipLocalFileHeader::HEADER[1]); - in.putback(ZipLocalFileHeader::HEADER[0]); + in.seekg(-4, std::ios::cur); + if (!in.good()) throw Poco::IOException("Failed to seek on input stream"); } else if (std::memcmp(ZipArchiveInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0) { - in.putback(ZipArchiveInfo::HEADER[3]); - in.putback(ZipArchiveInfo::HEADER[2]); - in.putback(ZipArchiveInfo::HEADER[1]); - in.putback(ZipArchiveInfo::HEADER[0]); + in.seekg(-4, std::ios::cur); + if (!in.good()) throw Poco::IOException("Failed to seek on input stream"); } else if (std::memcmp(ZipFileInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0) { - in.putback(ZipFileInfo::HEADER[3]); - in.putback(ZipFileInfo::HEADER[2]); - in.putback(ZipFileInfo::HEADER[1]); - in.putback(ZipFileInfo::HEADER[0]); + in.seekg(-4, std::ios::cur); + if (!in.good()) throw Poco::IOException("Failed to seek on input stream"); } else { - in.putback(ZipDataInfo::HEADER[3]); - in.putback(ZipDataInfo::HEADER[2]); - in.putback(ZipDataInfo::HEADER[1]); - in.putback(ZipDataInfo::HEADER[0]); + in.seekg(-4, std::ios::cur); + if (!in.good()) throw Poco::IOException("Failed to seek on input stream"); } return; } @@ -149,6 +141,7 @@ void ZipUtil::sync(std::istream& in) { // we have read 2 bytes, should only be one: putback the last char in.putback(temp[tempPos - 1]); + if (!in.good()) throw Poco::IOException("Failed to putback on input stream"); --tempPos; } } diff --git a/appveyor.yml b/appveyor.yml index 9f65ccd18..1a266261b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -384,7 +384,7 @@ build_script: } if ($env:builder -eq "msbuild") { - $logger='"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"'; + $logger='"C:\Progra~1\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"'; $verbosity='minimal'; $process = Start-Process -PassThru -nnw -Wait -FilePath "$env:poco_base\buildwin.cmd" -RSO cout -RSE cerr ` diff --git a/build/config/Linux b/build/config/Linux index 39bdc8e81..40ef8f059 100644 --- a/build/config/Linux +++ b/build/config/Linux @@ -69,7 +69,7 @@ RELEASEOPT_LINK = -O2 # # System Specific Flags # -SYSFLAGS = -D_XOPEN_SOURCE=500 -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DPOCO_HAVE_FD_EPOLL -DPOCO_HAVE_ADDRINFO -DPOCO_HAVE_LIBRESOLV +SYSFLAGS = -D_XOPEN_SOURCE=600 -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DPOCO_HAVE_FD_EPOLL -DPOCO_HAVE_ADDRINFO -DPOCO_HAVE_LIBRESOLV # # System Specific Libraries