summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/file_access.cpp9
-rw-r--r--zen/file_io.cpp20
-rw-r--r--zen/file_path.cpp32
-rw-r--r--zen/format_unit.cpp13
-rw-r--r--zen/globals.h82
-rw-r--r--zen/http.cpp1
-rw-r--r--zen/json.h4
-rw-r--r--zen/legacy_compiler.h2
-rw-r--r--zen/open_ssl.cpp80
-rw-r--r--zen/socket.h9
-rw-r--r--zen/stl_tools.h28
-rw-r--r--zen/symlink_target.h5
-rw-r--r--zen/sys_error.h3
-rw-r--r--zen/sys_version.cpp4
-rw-r--r--zen/zlib_wrap.cpp1
15 files changed, 158 insertions, 135 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index 6c47936c..4ce66acf 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -622,9 +622,8 @@ void zen::copySymlink(const Zstring& sourcePath, const Zstring& targetPath) //th
}
//allow only consistent objects to be created -> don't place before ::symlink(); targetPath may already exist!
- ZEN_ON_SCOPE_FAIL(try { removeSymlinkPlain(targetPath); /*throw FileError*/ }
- catch (FileError&) {});
- warn_static("log it!")
+ ZEN_ON_SCOPE_FAIL(try { removeSymlinkPlain(targetPath); }
+ catch (const FileError& e) { logExtraError(e.toString()); });
//file times: essential for syncing a symlink: enforce this! (don't just try!)
struct stat sourceInfo = {};
@@ -665,7 +664,7 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
}
FileOutputPlain fileOut(fdTarget, targetFile); //pass ownership
- //preallocate disk space + reduce fragmentation
+ //preallocate disk space + reduce fragmentation
fileOut.reserveSpace(sourceInfo.st_size); //throw FileError
unbufferedStreamCopy([&](void* buffer, size_t bytesToRead)
@@ -684,7 +683,7 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
},
fileOut.getBlockSize() /*throw FileError*/); //throw FileError, X
- //possible improvement: copy_file_range() performs an in-kernel copy: https://github.com/coreutils/coreutils/blob/17479ef60c8edbd2fe8664e31a7f69704f0cd221/src/copy.c#L342
+ //possible improvement: copy_file_range() performs an in-kernel copy: https://github.com/coreutils/coreutils/blob/17479ef60c8edbd2fe8664e31a7f69704f0cd221/src/copy.c#L342
#if 0
//clean file system cache: needed at all? no user complaints at all so far!!!
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 8c985f64..af80a69a 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -58,8 +58,7 @@ FileBase::~FileBase()
{
close(); //throw FileError
}
- catch (FileError&) { assert(false); }
- warn_static("log it!")
+ catch (const FileError& e) { logExtraError(e.toString()); }
}
@@ -170,8 +169,7 @@ size_t FileInputPlain::tryRead(void* buffer, size_t bytesToRead) //throw FileErr
if (bytesRead < 0)
THROW_LAST_SYS_ERROR("read");
- if (makeUnsigned(bytesRead) > bytesToRead) //better safe than sorry
- throw SysError(formatSystemError("read", L"", L"Buffer overflow."));
+ ASSERT_SYSERROR(makeUnsigned(bytesRead) <= bytesToRead); //better safe than sorry
return bytesRead; //"zero indicates end of file"
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), e.toString()); }
@@ -229,10 +227,9 @@ FileOutputPlain::~FileOutputPlain()
if (::unlink(getFilePath().c_str()) != 0)
THROW_LAST_SYS_ERROR("unlink");
}
- catch (const SysError&)
+ catch (const SysError& e)
{
- assert(false);
- warn_static("at least log on failure!")
+ logExtraError(replaceCpy(_("Cannot delete file %x."), L"%x", fmtPath(getFilePath())) + L"\n\n" + e.toString());
}
}
@@ -289,8 +286,8 @@ size_t FileOutputPlain::tryWrite(const void* buffer, size_t bytesToWrite) //thro
THROW_LAST_SYS_ERROR("write");
}
- if (makeUnsigned(bytesWritten) > bytesToWrite) //better safe than sorry
- throw SysError(formatSystemError("write", L"", L"Buffer overflow."));
+
+ ASSERT_SYSERROR(makeUnsigned(bytesWritten) <= bytesToWrite); //better safe than sorry
return bytesWritten;
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), e.toString()); }
@@ -330,9 +327,8 @@ void zen::setFileContent(const Zstring& filePath, const std::string_view byteStr
tmpFile.close(); //throw FileError
//take over ownership:
- ZEN_ON_SCOPE_FAIL( try { removeFilePlain(tmpFilePath); /*throw FileError*/ }
- catch (FileError&) {});
- warn_static("log it!")
+ ZEN_ON_SCOPE_FAIL( try { removeFilePlain(tmpFilePath); }
+ catch (const FileError& e) { logExtraError(e.toString()); });
//operation finished: move temp file transactionally
moveAndRenameItem(tmpFilePath, filePath, true /*replaceExisting*/); //throw FileError, (ErrorMoveUnsupported), (ErrorTargetExisting)
diff --git a/zen/file_path.cpp b/zen/file_path.cpp
index 60ac4eb7..6503ba2f 100644
--- a/zen/file_path.cpp
+++ b/zen/file_path.cpp
@@ -173,13 +173,6 @@ std::unordered_map<Zstring, Zstring> getAllEnvVars()
}
constinit Global<std::unordered_map<Zstring, Zstring>> globalEnvVars;
-GLOBAL_RUN_ONCE(
- //*INDENT-OFF*
- //mitigate static initialization order fiasco: (whatever comes first)
- if (!globalEnvVars.get())
- globalEnvVars.set(std::make_unique<std::unordered_map<Zstring, Zstring>>(getAllEnvVars()))
- //*INDENT-ON*
-);
}
@@ -191,24 +184,17 @@ std::optional<Zstring> zen::getEnvironmentVar(const ZstringView name)
getenv_s() to the rescue!? not implemented on GCC, apparently *still* not threadsafe!!!
=> *eff* this: make a global copy during start up! */
- std::shared_ptr<std::unordered_map<Zstring, Zstring>> envVars = globalEnvVars.get();
- if (!envVars) //access during static init or shutdown?
+ globalEnvVars.setOnce([] { return std::make_unique<std::unordered_map<Zstring, Zstring>>(getAllEnvVars()); });
+
+ if (std::shared_ptr<std::unordered_map<Zstring, Zstring>> envVars = globalEnvVars.get())
{
- if (globalEnvVars.wasDestroyed())
- {
- assert(false);
- return {}; //SOL!
- }
- //mitigate static initialization order fiasco: (whatever comes first)
- globalEnvVars.set(std::make_unique<std::unordered_map<Zstring, Zstring>>(getAllEnvVars()));
- envVars = globalEnvVars.get();
+ if (const auto it = envVars->find(name);
+ it != envVars->end())
+ return it->second;
}
-
- const auto it = envVars->find(name);
- if (it == envVars->end())
- return {};
-
- return it->second;
+ else
+ assert(false); //access during global shutdown => SOL!
+ return {};
}
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index a5dd5152..0ce68d9b 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -27,7 +27,8 @@ std::wstring zen::formatTwoDigitPrecision(double value)
//print two digits: 0,1 | 1,1 | 11
if (std::abs(value) < 9.95) //9.99 must not be formatted as "10.0"
return printNumber<std::wstring>(L"%.1f", value);
- return numberTo<std::wstring>(std::llround(value));
+
+ return formatNumber(std::llround(value));
}
@@ -38,7 +39,8 @@ std::wstring zen::formatThreeDigitPrecision(double value)
return printNumber<std::wstring>(L"%.2f", value);
if (std::abs(value) < 99.95) //99.99 must not be formatted as "100.0"
return printNumber<std::wstring>(L"%.1f", value);
- return numberTo<std::wstring>(std::llround(value));
+
+ return formatNumber(std::llround(value));
}
@@ -151,10 +153,9 @@ std::wstring zen::formatRemainingTime(double timeInSec)
std::wstring zen::formatProgressPercent(double fraction, int decPlaces)
{
-#if 0 //special case for perf!?
- if (decPlaces == 0)
- return numberTo<std::wstring>(static_cast<int>(fraction * 100)) + L'%';
-#endif
+ if (decPlaces == 0) //special case for perf
+ return numberTo<std::wstring>(static_cast<int>(std::floor(fraction * 100))) + L'%';
+
//round down! don't show 100% when not actually done: https://freefilesync.org/forum/viewtopic.php?t=9781
const double blocks = std::pow(10, decPlaces);
const double percent = std::floor(fraction * 100 * blocks) / blocks;
diff --git a/zen/globals.h b/zen/globals.h
index 5d4a7041..1a110373 100644
--- a/zen/globals.h
+++ b/zen/globals.h
@@ -87,16 +87,32 @@ public:
std::swap(pod_.inst, tmpInst);
else
assert(false);
+
+ pod_.initialized = true;
}
delete tmpInst;
}
- bool wasDestroyed()
+ //for initialization via a frequently-called function (which may be running on parallel threads)
+ template <class Function>
+ void setOnce(Function getInitialValue /*-> std::unique_ptr<T>*/)
{
pod_.spinLock.lock();
ZEN_ON_SCOPE_EXIT(pod_.spinLock.unlock());
- return pod_.destroyed;
+ if (!pod_.initialized)
+ {
+ assert(!pod_.inst);
+ if (!pod_.destroyed)
+ {
+ if (std::unique_ptr<T> newInst = getInitialValue()) //throw ?
+ pod_.inst = new std::shared_ptr<T>(std::move(newInst));
+ }
+ else
+ assert(false);
+
+ pod_.initialized = true;
+ }
}
private:
@@ -105,6 +121,7 @@ private:
PodSpinMutex spinLock; //rely entirely on static zero-initialization! => avoid potential contention with worker thread during Global<> construction!
//serialize access: can't use std::mutex: has non-trival destructor
std::shared_ptr<T>* inst = nullptr;
+ bool initialized = false;
bool destroyed = false;
} pod_;
};
@@ -128,29 +145,15 @@ class FunStatGlobal
public:
consteval FunStatGlobal() {}; //demand static zero-initialization!
- //No ~FunStatGlobal()!
+ //No ~FunStatGlobal(): required to avoid generation of magic statics code for a function-scope static!
- void initOnce(std::unique_ptr<T> (*getInitialValue)())
+ std::shared_ptr<T> get()
{
static_assert(std::is_trivially_destructible_v<FunStatGlobal>, "this class must not generate code for magic statics!");
pod_.spinLock.lock();
ZEN_ON_SCOPE_EXIT(pod_.spinLock.unlock());
- if (!pod_.cleanUpEntry.cleanUpFun)
- {
- assert(!pod_.inst);
- if (std::unique_ptr<T> newInst = (*getInitialValue)())
- pod_.inst = new std::shared_ptr<T>(std::move(newInst));
- registerDestruction();
- }
- }
-
- std::shared_ptr<T> get()
- {
- pod_.spinLock.lock();
- ZEN_ON_SCOPE_EXIT(pod_.spinLock.unlock());
-
if (pod_.inst)
return *pod_.inst;
return nullptr;
@@ -165,13 +168,50 @@ public:
pod_.spinLock.lock();
ZEN_ON_SCOPE_EXIT(pod_.spinLock.unlock());
- std::swap(pod_.inst, tmpInst);
+ if (!pod_.destroyed)
+ std::swap(pod_.inst, tmpInst);
+ else
+ assert(false);
+
registerDestruction();
}
delete tmpInst;
}
+ template <class Function>
+ void setOnce(Function getInitialValue /*-> std::unique_ptr<T>*/)
+ {
+ pod_.spinLock.lock();
+ ZEN_ON_SCOPE_EXIT(pod_.spinLock.unlock());
+
+ if (!pod_.cleanUpEntry.cleanUpFun)
+ {
+ assert(!pod_.inst);
+ if (!pod_.destroyed)
+ {
+ if (std::unique_ptr<T> newInst = getInitialValue()) //throw ?
+ pod_.inst = new std::shared_ptr<T>(std::move(newInst));
+ }
+ else
+ assert(false);
+
+ registerDestruction();
+ }
+ }
+
private:
+ void destruct()
+ {
+ static_assert(std::is_trivially_destructible_v<Pod>, "this memory needs to live forever");
+
+ pod_.spinLock.lock();
+ std::shared_ptr<T>* oldInst = std::exchange(pod_.inst, nullptr);
+ pod_.destroyed = true;
+ pod_.spinLock.unlock();
+
+ delete oldInst;
+ }
+
//call while holding pod_.spinLock
void registerDestruction()
{
@@ -182,8 +222,7 @@ private:
pod_.cleanUpEntry.callbackData = this;
pod_.cleanUpEntry.cleanUpFun = [](void* callbackData)
{
- auto thisPtr = static_cast<FunStatGlobal*>(callbackData);
- thisPtr->set(nullptr);
+ static_cast<FunStatGlobal*>(callbackData)->destruct();
};
registerGlobalForDestruction(pod_.cleanUpEntry);
@@ -196,6 +235,7 @@ private:
//serialize access; can't use std::mutex: has non-trival destructor
std::shared_ptr<T>* inst = nullptr;
CleanUpEntry cleanUpEntry;
+ bool destroyed = false;
} pod_;
};
diff --git a/zen/http.cpp b/zen/http.cpp
index e1a828c1..8cdcd65c 100644
--- a/zen/http.cpp
+++ b/zen/http.cpp
@@ -207,7 +207,6 @@ private:
void cleanup()
{
asyncStreamIn_->setReadError(std::make_exception_ptr(ThreadStopRequest()));
- warn_static("log on error!")
}
std::shared_ptr<AsyncStreamBuffer> asyncStreamIn_ = std::make_shared<AsyncStreamBuffer>(HTTP_STREAM_BUFFER_SIZE);
diff --git a/zen/json.h b/zen/json.h
index 8959e995..0ac2ee61 100644
--- a/zen/json.h
+++ b/zen/json.h
@@ -330,7 +330,7 @@ struct Token
class Scanner
{
public:
- Scanner(const std::string& stream) : stream_(stream), pos_(stream_.begin())
+ explicit Scanner(const std::string& stream) : stream_(stream), pos_(stream_.begin())
{
if (zen::startsWith(stream_, BYTE_ORDER_MARK_UTF8))
pos_ += BYTE_ORDER_MARK_UTF8.size();
@@ -435,7 +435,7 @@ private:
class JsonParser
{
public:
- JsonParser(const std::string& stream) :
+ explicit JsonParser(const std::string& stream) :
scn_(stream),
tk_(scn_.getNextToken()) {} //throw JsonParsingError
diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h
index 2070d60f..c853b139 100644
--- a/zen/legacy_compiler.h
+++ b/zen/legacy_compiler.h
@@ -41,7 +41,7 @@ basic_string<Char, Traits, Alloc> operator+(basic_string<Char, Traits, Alloc>&&
//---------------------------------------------------------------------------------
//support for std::string::resize_and_overwrite()
-#define ZEN_HAVE_RESIZE_AND_OVERWRITE 1
+ #define ZEN_HAVE_RESIZE_AND_OVERWRITE 1
namespace zen
{
diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp
index 5cfd7f12..0d4a89ca 100644
--- a/zen/open_ssl.cpp
+++ b/zen/open_ssl.cpp
@@ -22,11 +22,40 @@
using namespace zen;
+namespace
+{
#ifndef OPENSSL_THREADS
#error FFS, we are royally screwed!
#endif
-static_assert(OPENSSL_VERSION_NUMBER >= 0x30000000L, "OpenSSL version too old");
+static_assert(OPENSSL_VERSION_NUMBER >= 0x30000000L, "OpenSSL version is too old!");
+
+
+/* Sign a file using SHA-256:
+ openssl dgst -sha256 -sign private.pem -out file.sig file.txt
+
+ verify the signature: (caveat: public key expected to be in pkix format!)
+ openssl dgst -sha256 -verify public.pem -signature file.sig file.txt */
+
+
+std::wstring formatOpenSSLError(const char* functionName, unsigned long ec)
+{
+ char errorBuf[256] = {}; //== buffer size used by ERR_error_string(); err.c: it seems the message uses at most ~200 bytes
+ ::ERR_error_string_n(ec, errorBuf, sizeof(errorBuf)); //includes null-termination
+
+ return formatSystemError(functionName, replaceCpy(_("Error code %x"), L"%x", numberTo<std::wstring>(ec)), utfTo<std::wstring>(errorBuf));
+}
+
+
+std::wstring formatLastOpenSSLError(const char* functionName)
+{
+ const auto ec = ::ERR_peek_last_error(); //"returns latest error code from the thread's error queue without modifying it" - unlike ERR_get_error()
+ //ERR_get_error: "returns the earliest error code from the thread's error queue and removes the entry.
+ // This function can be called repeatedly until there are no more error codes to return."
+ ::ERR_clear_error(); //clean up for next OpenSSL operation on this thread
+ return formatOpenSSLError(functionName, ec);
+}
+}
void zen::openSslInit()
@@ -36,19 +65,16 @@ void zen::openSslInit()
//see Curl_ossl_cleanup(): https://github.com/curl/curl/blob/master/lib/vtls/openssl.c
assert(runningOnMainThread());
- //excplicitly init OpenSSL on main thread: seems to initialize atomically! But it still might help to avoid issues:
- [[maybe_unused]] const int rv = ::OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT | OPENSSL_INIT_NO_LOAD_CONFIG, nullptr);
- assert(rv == 1); //https://www.openssl.org/docs/man1.1.0/ssl/OPENSSL_init_ssl.html
-
- warn_static("probably should log")
+ //explicitly init OpenSSL on main thread: seems to initialize atomically! But it still might help to avoid issues:
+ //https://www.openssl.org/docs/manmaster/man3/OPENSSL_init_ssl.html
+ if (::OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT | OPENSSL_INIT_NO_LOAD_CONFIG, nullptr) != 1)
+ logExtraError(_("Error during process initialization.") + L"\n\n" + formatLastOpenSSLError("OPENSSL_init_ssl"));
}
void zen::openSslTearDown() {}
//OpenSSL 1.1.0+ deprecates all clean up functions
//=> so much the theory, in practice it leaks, of course: https://github.com/openssl/openssl/issues/6283
-//=> OpenSslThreadCleanUp
-
namespace
{
struct OpenSslThreadCleanUp
@@ -60,30 +86,6 @@ struct OpenSslThreadCleanUp
};
thread_local OpenSslThreadCleanUp tearDownOpenSslThreadData;
-
-/* Sign a file using SHA-256:
- openssl dgst -sha256 -sign private.pem -out file.sig file.txt
-
- verify the signature: (caveat: public key expected to be in pkix format!)
- openssl dgst -sha256 -verify public.pem -signature file.sig file.txt */
-
-
-std::wstring formatOpenSSLError(const char* functionName, unsigned long ec)
-{
- char errorBuf[256] = {}; //== buffer size used by ERR_error_string(); err.c: it seems the message uses at most ~200 bytes
- ::ERR_error_string_n(ec, errorBuf, sizeof(errorBuf)); //includes null-termination
-
- return formatSystemError(functionName, replaceCpy(_("Error code %x"), L"%x", numberTo<std::wstring>(ec)), utfTo<std::wstring>(errorBuf));
-}
-
-
-std::wstring formatLastOpenSSLError(const char* functionName)
-{
- const auto ec = ::ERR_peek_last_error(); //"returns latest error code from the thread's error queue without modifying it" - unlike ERR_get_error()
- ::ERR_clear_error(); //clean up for next OpenSSL operation on this thread
- return formatOpenSSLError(functionName, ec);
-}
-
//================================================================================
std::shared_ptr<EVP_PKEY> generateRsaKeyPair(int bits) //throw SysError
@@ -217,7 +219,7 @@ std::string keyToStream(const EVP_PKEY* evp, RsaStreamType streamType, bool publ
if (keyLen < 0)
throw SysError(formatLastOpenSSLError("BIO_pending"));
if (keyLen == 0)
- throw SysError(formatSystemError("BIO_pending", L"", L"Unexpected failure.")); //no more error details
+ throw SysError(formatSystemError("BIO_pending", L"", L"No more error details.")); //no more error details
std::string keyStream(keyLen, '\0');
@@ -281,7 +283,7 @@ std::string createHash(const std::string_view str, const EVP_MD* type) //throw S
#else //streaming version
EVP_MD_CTX* mdctx = ::EVP_MD_CTX_new();
if (!mdctx)
- throw SysError(formatSystemError("EVP_MD_CTX_new", L"", L"Unexpected failure.")); //no more error details
+ throw SysError(formatSystemError("EVP_MD_CTX_new", L"", L"No more error details.")); //no more error details
ZEN_ON_SCOPE_EXIT(::EVP_MD_CTX_free(mdctx));
if (::EVP_DigestInit(mdctx, //EVP_MD_CTX* ctx
@@ -308,7 +310,7 @@ std::string createSignature(const std::string_view message, EVP_PKEY* privateKey
//https://www.openssl.org/docs/manmaster/man3/EVP_DigestSign.html
EVP_MD_CTX* mdctx = ::EVP_MD_CTX_new();
if (!mdctx)
- throw SysError(formatSystemError("EVP_MD_CTX_new", L"", L"Unexpected failure.")); //no more error details
+ throw SysError(formatSystemError("EVP_MD_CTX_new", L"", L"No more error details.")); //no more error details
ZEN_ON_SCOPE_EXIT(::EVP_MD_CTX_free(mdctx));
if (::EVP_DigestSignInit(mdctx, //EVP_MD_CTX* ctx
@@ -347,7 +349,7 @@ void verifySignature(const std::string_view message, const std::string_view sign
//https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerify.html
EVP_MD_CTX* mdctx = ::EVP_MD_CTX_new();
if (!mdctx)
- throw SysError(formatSystemError("EVP_MD_CTX_new", L"", L"Unexpected failure.")); //no more error details
+ throw SysError(formatSystemError("EVP_MD_CTX_new", L"", L"No more error details.")); //no more error details
ZEN_ON_SCOPE_EXIT(::EVP_MD_CTX_free(mdctx));
if (::EVP_DigestVerifyInit(mdctx, //EVP_MD_CTX* ctx
@@ -553,7 +555,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string_view keyStream, const s
EVP_CIPHER_CTX* cipCtx = ::EVP_CIPHER_CTX_new();
if (!cipCtx)
- throw SysError(formatSystemError("EVP_CIPHER_CTX_new", L"", L"Unexpected failure.")); //no more error details
+ throw SysError(formatSystemError("EVP_CIPHER_CTX_new", L"", L"No more error details.")); //no more error details
ZEN_ON_SCOPE_EXIT(::EVP_CIPHER_CTX_free(cipCtx));
if (::EVP_DecryptInit(cipCtx, //EVP_CIPHER_CTX* ctx
@@ -563,7 +565,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string_view keyStream, const s
throw SysError(formatLastOpenSSLError("EVP_DecryptInit_ex"));
if (::EVP_CIPHER_CTX_set_padding(cipCtx, 0 /*padding*/) != 1)
- throw SysError(formatSystemError("EVP_CIPHER_CTX_set_padding", L"", L"Unexpected failure.")); //no more error details
+ throw SysError(formatSystemError("EVP_CIPHER_CTX_set_padding", L"", L"No more error details.")); //no more error details
privateBlob.resize(privateBlobEnc.size() + ::EVP_CIPHER_block_size(EVP_aes_256_cbc()));
//"EVP_DecryptUpdate() should have room for (inl + cipher_block_size) bytes"
@@ -613,7 +615,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string_view keyStream, const s
static_cast<int>(macData.size()), //int n
reinterpret_cast<unsigned char*>(md), //unsigned char* md
&mdLen)) //unsigned int* md_len
- throw SysError(formatSystemError("HMAC", L"", L"Unexpected failure.")); //no more error details
+ throw SysError(formatSystemError("HMAC", L"", L"No more error details.")); //no more error details
if (mac != std::string_view(md, mdLen))
throw SysError(keyEncrypted ? L"Wrong passphrase (or corrupted key)" : L"Validation failed: corrupted key");
diff --git a/zen/socket.h b/zen/socket.h
index f706daab..c2fdb145 100644
--- a/zen/socket.h
+++ b/zen/socket.h
@@ -59,7 +59,6 @@ std::wstring formatGaiErrorCode(int ec)
using SocketType = int;
const SocketType invalidSocket = -1;
inline void closeSocket(SocketType s) { ::close(s); }
-warn_static("log on error!")
void setNonBlocking(SocketType socket, bool value); //throw SysError
@@ -194,8 +193,7 @@ size_t tryReadSocket(SocketType socket, void* buffer, size_t bytesToRead) //thro
if (bytesReceived < 0)
THROW_LAST_SYS_ERROR_WSA("recv");
- if (static_cast<size_t>(bytesReceived) > bytesToRead) //better safe than sorry
- throw SysError(formatSystemError("recv", L"", L"Buffer overflow."));
+ ASSERT_SYSERROR(makeUnsigned(bytesReceived) <= bytesToRead); //better safe than sorry
return bytesReceived; //"zero indicates end of file"
}
@@ -218,11 +216,12 @@ size_t tryWriteSocket(SocketType socket, const void* buffer, size_t bytesToWrite
}
if (bytesWritten < 0)
THROW_LAST_SYS_ERROR_WSA("send");
- if (bytesWritten > static_cast<int>(bytesToWrite))
- throw SysError(formatSystemError("send", L"", L"Buffer overflow."));
+
if (bytesWritten == 0)
throw SysError(formatSystemError("send", L"", L"Zero bytes processed."));
+ ASSERT_SYSERROR(makeUnsigned(bytesWritten) <= bytesToWrite); //better safe than sorry
+
return bytesWritten;
}
}
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 03e7901a..ff574368 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -187,7 +187,7 @@ void removeDuplicates(std::vector<T, Alloc>& v, CompLess less)
template <class T, class Alloc> inline
void removeDuplicates(std::vector<T, Alloc>& v)
{
- removeDuplicates(v, std::less(), std::equal_to());
+ removeDuplicates(v, std::less{}, std::equal_to{});
}
@@ -196,14 +196,14 @@ void removeDuplicatesStable(std::vector<T, Alloc>& v, CompLess less)
{
std::set<T, CompLess> usedItems(less);
v.erase(std::remove_if(v.begin(), v.end(),
- [&usedItems](const T& e) { return !usedItems.insert(e).second; }), v.end());
+ /**/[&usedItems](const T& e) { return !usedItems.insert(e).second; }), v.end());
}
template <class T, class Alloc> inline
void removeDuplicatesStable(std::vector<T, Alloc>& v)
{
- removeDuplicatesStable(v, std::less());
+ removeDuplicatesStable(v, std::less{});
}
@@ -234,30 +234,28 @@ BidirectionalIterator findLast(const BidirectionalIterator first, const Bidirect
}
-template <class RandomAccessIterator1, class RandomAccessIterator2> inline
+template <class RandomAccessIterator1, class RandomAccessIterator2, class IsEq> inline
RandomAccessIterator1 searchFirst(const RandomAccessIterator1 first, const RandomAccessIterator1 last,
- const RandomAccessIterator2 needleFirst, const RandomAccessIterator2 needleLast)
+ const RandomAccessIterator2 needleFirst, const RandomAccessIterator2 needleLast, IsEq isEqual)
{
if (needleLast - needleFirst == 1) //don't use expensive std::search unless required!
- return std::find(first, last, *needleFirst);
+ return std::find_if(first, last, [needleFirst, isEqual](const auto c) { return isEqual(*needleFirst, c); });
+ //"*needleFirst" could be improved with value rather than pointer access, at least for built-in types like "char"
return std::search(first, last,
- needleFirst, needleLast);
+ needleFirst, needleLast, isEqual);
}
-template <class RandomAccessIterator1, class RandomAccessIterator2, class IsEq> inline
+template <class RandomAccessIterator1, class RandomAccessIterator2> inline
RandomAccessIterator1 searchFirst(const RandomAccessIterator1 first, const RandomAccessIterator1 last,
- const RandomAccessIterator2 needleFirst, const RandomAccessIterator2 needleLast, IsEq isEqual)
+ const RandomAccessIterator2 needleFirst, const RandomAccessIterator2 needleLast)
{
- if (needleLast - needleFirst == 1) //don't use expensive std::search unless required!
- return std::find_if(first, last, [needleFirst, isEqual](const auto c) { return isEqual(*needleFirst, c); });
-
- return std::search(first, last,
- needleFirst, needleLast, isEqual);
+ return searchFirst(first, last, needleFirst, needleLast, std::equal_to{});
}
+
template <class RandomAccessIterator1, class RandomAccessIterator2> inline
RandomAccessIterator1 searchLast(const RandomAccessIterator1 first, RandomAccessIterator1 last,
const RandomAccessIterator2 needleFirst, const RandomAccessIterator2 needleLast)
@@ -335,7 +333,7 @@ class FNV1aHash //FNV-1a: https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%8
{
public:
FNV1aHash() {}
- explicit FNV1aHash(Num startVal) : hashVal_(startVal) { assert(startVal != 0); /*(yes, might be a real hash, but) most likely bad init value*/}
+ explicit FNV1aHash(Num startVal) : hashVal_(startVal) { assert(startVal != 0); /*yes, might be a real hash, but most likely bad init value*/}
void add(Num n)
{
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 8580a9dd..24ce2313 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -50,7 +50,10 @@ SymlinkRawContent getSymlinkRawContent_impl(const Zstring& linkPath) //throw Sys
const ssize_t bytesWritten = ::readlink(linkPath.c_str(), buf.data(), bufSize);
if (bytesWritten < 0)
THROW_LAST_SYS_ERROR("readlink");
- if (makeUnsigned(bytesWritten) >= bufSize) //detect truncation; not an error for readlink!
+
+ ASSERT_SYSERROR(makeUnsigned(bytesWritten) <= bufSize); //better safe than sorry
+
+ if (makeUnsigned(bytesWritten) == bufSize) //detect truncation; not an error for readlink!
throw SysError(formatSystemError("readlink", L"", L"Buffer truncated."));
return {.targetPath = Zstring(buf.data(), bytesWritten)}; //readlink does not append 0-termination!
diff --git a/zen/sys_error.h b/zen/sys_error.h
index 73a92343..53cd2845 100644
--- a/zen/sys_error.h
+++ b/zen/sys_error.h
@@ -10,6 +10,7 @@
#include "scope_guard.h" //
#include "i18n.h" //not used by this header, but the "rest of the world" needs it!
#include "zstring.h" //
+#include "extra_log.h" //
#include <glib.h>
#include <cerrno>
@@ -78,7 +79,7 @@ inline bool validateBool(void* b) { return b; }
bool validateBool(int) = delete; //catch unintended bool conversions, e.g. HRESULT
}
#define ASSERT_SYSERROR_IMPL(expr, exprStr) \
- { if (!impl::validateBool(expr)) \
+ { if (!zen::impl::validateBool(expr)) \
throw zen::SysError(L"Assertion failed: \"" L ## exprStr L"\""); }
}
diff --git a/zen/sys_version.cpp b/zen/sys_version.cpp
index e57c9b69..705fbade 100644
--- a/zen/sys_version.cpp
+++ b/zen/sys_version.cpp
@@ -89,8 +89,8 @@ OsVersion zen::getOsVersion()
}
catch (const SysError& e)
{
- std::cerr << utfTo<std::string>(e.toString()) + '\n';
- return OsVersionDetail{}; //sigh, it's a jungle out there: https://freefilesync.org/forum/viewtopic.php?t=7276
+ logExtraError(_("Cannot get process information.") + L"\n\n" + e.toString());
+ return OsVersionDetail{}; //arrgh, it's a jungle out there: https://freefilesync.org/forum/viewtopic.php?t=7276
}
}();
return verDetail.version;
diff --git a/zen/zlib_wrap.cpp b/zen/zlib_wrap.cpp
index 7e680131..5810ef56 100644
--- a/zen/zlib_wrap.cpp
+++ b/zen/zlib_wrap.cpp
@@ -172,7 +172,6 @@ public:
{
[[maybe_unused]] const int rv = ::deflateEnd(&gzipStream_);
assert(rv == Z_OK);
- warn_static("log on error")
}
size_t read(void* buffer, size_t bytesToRead) //throw SysError, X; return "bytesToRead" bytes unless end of stream!
bgstack15