aboutsummaryrefslogtreecommitdiff
path: root/src/zencore
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-06 10:11:51 +0100
committerGitHub Enterprise <[email protected]>2026-03-06 10:11:51 +0100
commit1e731796187ad73b2dee44b48fcecdd487616394 (patch)
tree0ea37769f743ae1fb2eacc37bc8ccfa88ecc0d64 /src/zencore
parentfix oidctoken exe lookup check (#811) (diff)
downloadzen-1e731796187ad73b2dee44b48fcecdd487616394.tar.xz
zen-1e731796187ad73b2dee44b48fcecdd487616394.zip
Claude config, some bug fixes (#813)
* Claude config updates * Bug fixes and hardening across `zencore` and `zenhttp`, identified via static analysis. ### zencore - **`ZEN_ASSERT` macro** -- extended to accept an optional string message literal; added `ZEN_ASSERT_MSG_` helper for message formatting. Callers needing runtime fmt-style formatting should use `ZEN_ASSERT_FORMAT`. - **`MpscQueue`** -- fixed `TypeCompatibleStorage` to use a properly-sized `char Storage[sizeof(T)]` array instead of a single `char`; corrected `Data()` to cast `&Storage` rather than `this`; switched cache-line alignment to a fixed constant to avoid GCC's `-Winterference-size` warning. Enabled previously-disabled tests. - **`StringBuilderImpl`** -- initialized `m_Base`/`m_CurPos`/`m_End` to `nullptr`. Fixed `StringCompare` return type (`bool` -> `int`). Fixed `ParseInt` to reject strings with trailing non-numeric characters. Removed deprecated `<codecvt>` include. - **`NiceNumGeneral`** -- replaced `powl()` with integer `IntPow()` to avoid floating-point precision issues. - **`RwLock::ExclusiveLockScope`** -- added move constructor/assignment; initialized `m_Lock` to `nullptr`. - **`Latch::AddCount`** -- fixed variable type (`std::atomic_ptrdiff_t` -> `std::ptrdiff_t` for the return value of `fetch_add`). - **`thread.cpp`** -- fixed Linux `pthread_setname_np` 16-byte name truncation; added null check before dereferencing in `Event::Close()`; fixed `NamedEvent::Close()` to call `close(Fd)` outside the lock region; added null guard in `NamedMutex` destructor; `Sleep()` now returns early for non-positive durations. - **`MD5Stream`** -- was entirely stubbed out (no-op); now correctly calls `MD5Init`/`MD5Update`/`MD5Final`. Fixed `ToHexString` to use the correct string length. Fixed forward declarations. Fixed tests to compare `compare() == 0`. - **`sentryintegration.cpp`** -- guard against null `filename`/`funcname` in spdlog message handler to prevent a crash in `fmt::format`. - **`jobqueue.cpp`** -- fixed lost job ID when `IdGenerator` wraps around zero; fixed raw `Job*` in `RunningJobs` map (potential use-after-free) to `RefPtr<Job>`; fixed range-loop copies; fixed format string typo. - **`trace.cpp`** -- suppress GCC false-positive warnings in third-party `trace.h` include. ### zenhttp - **WebSocket close race** (`wsasio`, `wshttpsys`, `httpwsclient`) -- `m_CloseSent` promoted from `bool` to `std::atomic<bool>`; close check changed to `exchange(true)` to eliminate the check-then-set data race. - **`wsframecodec.cpp`** -- reject WebSocket frames with payload > 256 MB to prevent OOM from malformed/malicious frames. - **`oidc.cpp`** -- URL-encode refresh token and client ID in token requests (`FormUrlEncode`); parse `end_session_endpoint` and `device_authorization_endpoint` from OIDC discovery document. - **`httpclientcommon.cpp`** -- propagate error code from `AppendData` when flushing the cache buffer. - **`httpclient.h`** -- initialize all uninitialized members (`ErrorCode`, `UploadedBytes`, `DownloadedBytes`, `ElapsedSeconds`, `MultipartBoundary` fields). - **`httpserver.h`** -- fix `operator=` return type for `HttpRpcHandler` (missing `&`). - **`packageformat.h`** -- fix `~0u` (32-bit truncation) to `~uint64_t(0)` for a `uint64_t` field. - **`httpparser`** -- initialize `m_RequestVerb` in both declaration and `ResetState()`. - **`httpplugin.cpp`** -- initialize `m_BasePort`; fix format string missing quotes around connection name. - **`httptracer.h`** -- move `#pragma once` before includes. - **`websocket.h`** -- initialize `WebSocketMessage::Opcode`. ### zenserver - **`hubservice.cpp`** -- fix two `ZEN_ASSERT` calls that incorrectly used fmt-style format args; converted to `ZEN_ASSERT_FORMAT`.
Diffstat (limited to 'src/zencore')
-rw-r--r--src/zencore/blake3.cpp2
-rw-r--r--src/zencore/commandline.cpp1
-rw-r--r--src/zencore/include/zencore/md5.h2
-rw-r--r--src/zencore/include/zencore/mpscqueue.h20
-rw-r--r--src/zencore/include/zencore/string.h22
-rw-r--r--src/zencore/include/zencore/thread.h16
-rw-r--r--src/zencore/include/zencore/xxhash.h2
-rw-r--r--src/zencore/include/zencore/zencore.h34
-rw-r--r--src/zencore/jobqueue.cpp20
-rw-r--r--src/zencore/logging.cpp2
-rw-r--r--src/zencore/md5.cpp24
-rw-r--r--src/zencore/memtrack/tagtrace.cpp2
-rw-r--r--src/zencore/mpscqueue.cpp4
-rw-r--r--src/zencore/sentryintegration.cpp9
-rw-r--r--src/zencore/string.cpp15
-rw-r--r--src/zencore/thread.cpp42
-rw-r--r--src/zencore/trace.cpp9
-rw-r--r--src/zencore/xmake.lua7
18 files changed, 146 insertions, 87 deletions
diff --git a/src/zencore/blake3.cpp b/src/zencore/blake3.cpp
index 123918de5..55f9b74af 100644
--- a/src/zencore/blake3.cpp
+++ b/src/zencore/blake3.cpp
@@ -123,7 +123,7 @@ BLAKE3::ToHexString(StringBuilderBase& outBuilder) const
char str[65];
ToHexString(str);
- outBuilder.AppendRange(str, &str[65]);
+ outBuilder.AppendRange(str, &str[StringLength]);
return outBuilder;
}
diff --git a/src/zencore/commandline.cpp b/src/zencore/commandline.cpp
index 426cf23d6..718ef9678 100644
--- a/src/zencore/commandline.cpp
+++ b/src/zencore/commandline.cpp
@@ -14,6 +14,7 @@ ZEN_THIRD_PARTY_INCLUDES_END
# include <crt_externs.h>
#endif
+#include <locale.h>
#include <functional>
namespace zen {
diff --git a/src/zencore/include/zencore/md5.h b/src/zencore/include/zencore/md5.h
index d934dd86b..3b0b7cae6 100644
--- a/src/zencore/include/zencore/md5.h
+++ b/src/zencore/include/zencore/md5.h
@@ -43,6 +43,8 @@ public:
MD5 GetHash();
private:
+ // Opaque storage for MD5_CTX (104 bytes, aligned to uint32_t)
+ alignas(4) uint8_t m_Context[104];
};
void md5_forcelink(); // internal
diff --git a/src/zencore/include/zencore/mpscqueue.h b/src/zencore/include/zencore/mpscqueue.h
index 19e410d85..d97c433fd 100644
--- a/src/zencore/include/zencore/mpscqueue.h
+++ b/src/zencore/include/zencore/mpscqueue.h
@@ -22,10 +22,10 @@ namespace zen {
template<typename ElementType>
struct TypeCompatibleStorage
{
- ElementType* Data() { return (ElementType*)this; }
- const ElementType* Data() const { return (const ElementType*)this; }
+ ElementType* Data() { return reinterpret_cast<ElementType*>(&Storage); }
+ const ElementType* Data() const { return reinterpret_cast<const ElementType*>(&Storage); }
- alignas(ElementType) char DataMember;
+ alignas(ElementType) char Storage[sizeof(ElementType)];
};
/** Fast multi-producer/single-consumer unbounded concurrent queue.
@@ -58,7 +58,7 @@ public:
Tail = Next;
Next = Tail->Next.load(std::memory_order_relaxed);
- std::destroy_at((ElementType*)&Tail->Value);
+ std::destroy_at(Tail->Value.Data());
delete Tail;
}
}
@@ -67,7 +67,7 @@ public:
void Enqueue(ArgTypes&&... Args)
{
Node* New = new Node;
- new (&New->Value) ElementType(std::forward<ArgTypes>(Args)...);
+ new (New->Value.Data()) ElementType(std::forward<ArgTypes>(Args)...);
Node* Prev = Head.exchange(New, std::memory_order_acq_rel);
Prev->Next.store(New, std::memory_order_release);
@@ -82,7 +82,7 @@ public:
return {};
}
- ElementType* ValuePtr = (ElementType*)&Next->Value;
+ ElementType* ValuePtr = Next->Value.Data();
std::optional<ElementType> Res{std::move(*ValuePtr)};
std::destroy_at(ValuePtr);
@@ -100,9 +100,11 @@ private:
};
private:
- std::atomic<Node*> Head; // accessed only by producers
- alignas(hardware_constructive_interference_size)
- Node* Tail; // accessed only by consumer, hence should be on a different cache line than `Head`
+ // Use a fixed constant to avoid GCC's -Winterference-size warning with std::hardware_destructive_interference_size
+ static constexpr std::size_t CacheLineSize = 64;
+
+ alignas(CacheLineSize) std::atomic<Node*> Head; // accessed only by producers
+ alignas(CacheLineSize) Node* Tail; // accessed only by consumer, separate cache line from Head
};
void mpscqueue_forcelink();
diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h
index 250eb9f56..4deca63ed 100644
--- a/src/zencore/include/zencore/string.h
+++ b/src/zencore/include/zencore/string.h
@@ -8,7 +8,6 @@
#include <stdint.h>
#include <string.h>
#include <charconv>
-#include <codecvt>
#include <compare>
#include <concepts>
#include <optional>
@@ -51,7 +50,7 @@ StringLength(const wchar_t* str)
return wcslen(str);
}
-inline bool
+inline int
StringCompare(const char16_t* s1, const char16_t* s2)
{
char16_t c1, c2;
@@ -66,7 +65,7 @@ StringCompare(const char16_t* s1, const char16_t* s2)
++s1;
++s2;
}
- return uint16_t(c1) - uint16_t(c2);
+ return int(uint16_t(c1)) - int(uint16_t(c2));
}
inline bool
@@ -122,10 +121,10 @@ public:
StringBuilderImpl() = default;
~StringBuilderImpl();
- StringBuilderImpl(const StringBuilderImpl&) = delete;
- StringBuilderImpl(const StringBuilderImpl&&) = delete;
+ StringBuilderImpl(const StringBuilderImpl&) = delete;
+ StringBuilderImpl(StringBuilderImpl&&) = delete;
const StringBuilderImpl& operator=(const StringBuilderImpl&) = delete;
- const StringBuilderImpl& operator=(const StringBuilderImpl&&) = delete;
+ StringBuilderImpl& operator=(StringBuilderImpl&&) = delete;
inline size_t AddUninitialized(size_t Count)
{
@@ -374,9 +373,9 @@ protected:
[[noreturn]] void Fail(const char* FailReason); // note: throws exception
- C* m_Base;
- C* m_CurPos;
- C* m_End;
+ C* m_Base = nullptr;
+ C* m_CurPos = nullptr;
+ C* m_End = nullptr;
bool m_IsDynamic = false;
bool m_IsExtendable = false;
};
@@ -773,8 +772,9 @@ std::optional<T>
ParseInt(const std::string_view& Input)
{
T Out = 0;
- const std::from_chars_result Result = std::from_chars(Input.data(), Input.data() + Input.size(), Out);
- if (Result.ec == std::errc::invalid_argument || Result.ec == std::errc::result_out_of_range)
+ const char* End = Input.data() + Input.size();
+ const std::from_chars_result Result = std::from_chars(Input.data(), End, Out);
+ if (Result.ec == std::errc::invalid_argument || Result.ec == std::errc::result_out_of_range || Result.ptr != End)
{
return std::nullopt;
}
diff --git a/src/zencore/include/zencore/thread.h b/src/zencore/include/zencore/thread.h
index a1c68b0b2..d0d710ee8 100644
--- a/src/zencore/include/zencore/thread.h
+++ b/src/zencore/include/zencore/thread.h
@@ -58,7 +58,7 @@ public:
}
private:
- RwLock* m_Lock;
+ RwLock* m_Lock = nullptr;
};
inline auto WithSharedLock(auto&& Fun)
@@ -69,6 +69,16 @@ public:
struct ExclusiveLockScope
{
+ ExclusiveLockScope(const ExclusiveLockScope& Rhs) = delete;
+ ExclusiveLockScope(ExclusiveLockScope&& Rhs) : m_Lock(Rhs.m_Lock) { Rhs.m_Lock = nullptr; }
+ ExclusiveLockScope& operator=(ExclusiveLockScope&& Rhs)
+ {
+ ReleaseNow();
+ m_Lock = Rhs.m_Lock;
+ Rhs.m_Lock = nullptr;
+ return *this;
+ }
+ ExclusiveLockScope& operator=(const ExclusiveLockScope& Rhs) = delete;
ExclusiveLockScope(RwLock& Lock) : m_Lock(&Lock) { Lock.AcquireExclusive(); }
~ExclusiveLockScope() { ReleaseNow(); }
@@ -82,7 +92,7 @@ public:
}
private:
- RwLock* m_Lock;
+ RwLock* m_Lock = nullptr;
};
inline auto WithExclusiveLock(auto&& Fun)
@@ -195,7 +205,7 @@ public:
// false positive completion results.
void AddCount(std::ptrdiff_t Count)
{
- std::atomic_ptrdiff_t Old = Counter.fetch_add(Count);
+ std::ptrdiff_t Old = Counter.fetch_add(Count);
ZEN_ASSERT(Old > 0);
}
diff --git a/src/zencore/include/zencore/xxhash.h b/src/zencore/include/zencore/xxhash.h
index fc55b513b..f79d39b61 100644
--- a/src/zencore/include/zencore/xxhash.h
+++ b/src/zencore/include/zencore/xxhash.h
@@ -87,7 +87,7 @@ struct XXH3_128Stream
}
private:
- XXH3_state_s m_State;
+ XXH3_state_s m_State{};
};
struct XXH3_128Stream_deprecated
diff --git a/src/zencore/include/zencore/zencore.h b/src/zencore/include/zencore/zencore.h
index 177a19fff..a31950b0b 100644
--- a/src/zencore/include/zencore/zencore.h
+++ b/src/zencore/include/zencore/zencore.h
@@ -70,26 +70,36 @@ protected:
} // namespace zen
-#define ZEN_ASSERT(x, ...) \
- do \
- { \
- if (x) [[unlikely]] \
- break; \
- zen::AssertImpl::ExecAssert(__FILE__, __LINE__, __FUNCTION__, #x); \
+#define ZEN_ASSERT(x, ...) \
+ do \
+ { \
+ if (x) [[unlikely]] \
+ break; \
+ zen::AssertImpl::ExecAssert(__FILE__, __LINE__, __FUNCTION__, ZEN_ASSERT_MSG_(#x, ##__VA_ARGS__)); \
} while (false)
#ifndef NDEBUG
-# define ZEN_ASSERT_SLOW(x, ...) \
- do \
- { \
- if (x) [[unlikely]] \
- break; \
- zen::AssertImpl::ExecAssert(__FILE__, __LINE__, __FUNCTION__, #x); \
+# define ZEN_ASSERT_SLOW(x, ...) \
+ do \
+ { \
+ if (x) [[unlikely]] \
+ break; \
+ zen::AssertImpl::ExecAssert(__FILE__, __LINE__, __FUNCTION__, ZEN_ASSERT_MSG_(#x, ##__VA_ARGS__)); \
} while (false)
#else
# define ZEN_ASSERT_SLOW(x, ...)
#endif
+// Internal: select between "expr" and "expr: message" forms.
+// With no extra args: ZEN_ASSERT_MSG_("expr") -> "expr"
+// With a message arg: ZEN_ASSERT_MSG_("expr", "msg") -> "expr" ": " "msg"
+// With fmt-style args: ZEN_ASSERT_MSG_("expr", "msg", args...) -> "expr" ": " "msg"
+// The extra fmt args are silently discarded here — use ZEN_ASSERT_FORMAT for those.
+#define ZEN_ASSERT_MSG_SELECT_(_1, _2, N, ...) N
+#define ZEN_ASSERT_MSG_1_(expr) expr
+#define ZEN_ASSERT_MSG_2_(expr, msg, ...) expr ": " msg
+#define ZEN_ASSERT_MSG_(expr, ...) ZEN_ASSERT_MSG_SELECT_(unused, ##__VA_ARGS__, ZEN_ASSERT_MSG_2_, ZEN_ASSERT_MSG_1_)(expr, ##__VA_ARGS__)
+
//////////////////////////////////////////////////////////////////////////
#define ZEN_NOT_IMPLEMENTED(...) ZEN_ASSERT(false, __VA_ARGS__)
diff --git a/src/zencore/jobqueue.cpp b/src/zencore/jobqueue.cpp
index 35724b07a..d6a8a6479 100644
--- a/src/zencore/jobqueue.cpp
+++ b/src/zencore/jobqueue.cpp
@@ -90,7 +90,7 @@ public:
uint64_t NewJobId = IdGenerator.fetch_add(1);
if (NewJobId == 0)
{
- IdGenerator.fetch_add(1);
+ NewJobId = IdGenerator.fetch_add(1);
}
RefPtr<Job> NewJob(new Job());
NewJob->Queue = this;
@@ -129,7 +129,7 @@ public:
QueuedJobs.erase(It);
}
});
- ZEN_ERROR("Failed to schedule job {}:'{}' to job queue. Reason: ''", NewJob->Id.Id, NewJob->Name, Ex.what());
+ ZEN_ERROR("Failed to schedule job {}:'{}' to job queue. Reason: '{}'", NewJob->Id.Id, NewJob->Name, Ex.what());
throw;
}
}
@@ -221,11 +221,11 @@ public:
std::vector<JobInfo> Jobs;
QueueLock.WithSharedLock([&]() {
- for (auto It : RunningJobs)
+ for (const auto& It : RunningJobs)
{
Jobs.push_back({.Id = JobId{It.first}, .Status = JobStatus::Running});
}
- for (auto It : CompletedJobs)
+ for (const auto& It : CompletedJobs)
{
if (IsStale(It.second->EndTick))
{
@@ -234,7 +234,7 @@ public:
}
Jobs.push_back({.Id = JobId{It.first}, .Status = JobStatus::Completed});
}
- for (auto It : AbortedJobs)
+ for (const auto& It : AbortedJobs)
{
if (IsStale(It.second->EndTick))
{
@@ -243,7 +243,7 @@ public:
}
Jobs.push_back({.Id = JobId{It.first}, .Status = JobStatus::Aborted});
}
- for (auto It : QueuedJobs)
+ for (const auto& It : QueuedJobs)
{
Jobs.push_back({.Id = It->Id, .Status = JobStatus::Queued});
}
@@ -337,7 +337,7 @@ public:
std::atomic_bool InitializedFlag = false;
RwLock QueueLock;
std::deque<RefPtr<Job>> QueuedJobs;
- std::unordered_map<uint64_t, Job*> RunningJobs;
+ std::unordered_map<uint64_t, RefPtr<Job>> RunningJobs;
std::unordered_map<uint64_t, RefPtr<Job>> CompletedJobs;
std::unordered_map<uint64_t, RefPtr<Job>> AbortedJobs;
@@ -429,20 +429,16 @@ JobQueue::ToString(JobStatus Status)
{
case JobQueue::JobStatus::Queued:
return "Queued"sv;
- break;
case JobQueue::JobStatus::Running:
return "Running"sv;
- break;
case JobQueue::JobStatus::Aborted:
return "Aborted"sv;
- break;
case JobQueue::JobStatus::Completed:
return "Completed"sv;
- break;
default:
ZEN_ASSERT(false);
+ return ""sv;
}
- return ""sv;
}
std::unique_ptr<JobQueue>
diff --git a/src/zencore/logging.cpp b/src/zencore/logging.cpp
index e960a2729..ebd68de09 100644
--- a/src/zencore/logging.cpp
+++ b/src/zencore/logging.cpp
@@ -303,7 +303,7 @@ GetLogLevel()
LoggerRef
Default()
{
- ZEN_ASSERT(TheDefaultLogger);
+ ZEN_ASSERT(TheDefaultLogger, "logging::InitializeLogging() must be called before using the logger");
return TheDefaultLogger;
}
diff --git a/src/zencore/md5.cpp b/src/zencore/md5.cpp
index 83ed53fc8..f8cfee3ac 100644
--- a/src/zencore/md5.cpp
+++ b/src/zencore/md5.cpp
@@ -56,9 +56,9 @@ struct MD5_CTX
unsigned char digest[16]; /* actual digest after MD5Final call */
};
-void MD5Init();
-void MD5Update();
-void MD5Final();
+void MD5Init(MD5_CTX* mdContext);
+void MD5Update(MD5_CTX* mdContext, unsigned char* inBuf, unsigned int inLen);
+void MD5Final(MD5_CTX* mdContext);
/*
**********************************************************************
@@ -370,28 +370,32 @@ MD5 MD5::Zero; // Initialized to all zeroes
MD5Stream::MD5Stream()
{
+ static_assert(sizeof(MD5_CTX) <= sizeof(m_Context));
Reset();
}
void
MD5Stream::Reset()
{
+ MD5Init(reinterpret_cast<MD5_CTX*>(m_Context));
}
MD5Stream&
MD5Stream::Append(const void* Data, size_t ByteCount)
{
- ZEN_UNUSED(Data);
- ZEN_UNUSED(ByteCount);
-
+ MD5Update(reinterpret_cast<MD5_CTX*>(m_Context), (unsigned char*)Data, (unsigned int)ByteCount);
return *this;
}
MD5
MD5Stream::GetHash()
{
- MD5 md5{};
+ MD5_CTX FinalCtx;
+ memcpy(&FinalCtx, m_Context, sizeof(MD5_CTX));
+ MD5Final(&FinalCtx);
+ MD5 md5{};
+ memcpy(md5.Hash, FinalCtx.digest, 16);
return md5;
}
@@ -428,7 +432,7 @@ MD5::ToHexString(StringBuilderBase& outBuilder) const
char str[41];
ToHexString(str);
- outBuilder.AppendRange(str, &str[40]);
+ outBuilder.AppendRange(str, &str[StringLength]);
return outBuilder;
}
@@ -470,11 +474,11 @@ TEST_CASE("MD5")
MD5::String_t Buffer;
Result.ToHexString(Buffer);
- CHECK(Output.compare(Buffer));
+ CHECK(Output.compare(Buffer) == 0);
MD5 Reresult = MD5::FromHexString(Buffer);
Reresult.ToHexString(Buffer);
- CHECK(Output.compare(Buffer));
+ CHECK(Output.compare(Buffer) == 0);
}
TEST_SUITE_END();
diff --git a/src/zencore/memtrack/tagtrace.cpp b/src/zencore/memtrack/tagtrace.cpp
index 70a74365d..fca4a2ec3 100644
--- a/src/zencore/memtrack/tagtrace.cpp
+++ b/src/zencore/memtrack/tagtrace.cpp
@@ -186,7 +186,7 @@ FTagTrace::AnnounceSpecialTags() const
{
auto EmitTag = [](const char16_t* DisplayString, int32_t Tag, int32_t ParentTag) {
const uint32_t DisplayLen = (uint32_t)StringLength(DisplayString);
- UE_TRACE_LOG(Memory, TagSpec, MemAllocChannel, DisplayLen * sizeof(ANSICHAR))
+ UE_TRACE_LOG(Memory, TagSpec, MemAllocChannel, DisplayLen * sizeof(char16_t))
<< TagSpec.Tag(Tag) << TagSpec.Parent(ParentTag) << TagSpec.Display(DisplayString, DisplayLen);
};
diff --git a/src/zencore/mpscqueue.cpp b/src/zencore/mpscqueue.cpp
index f749f1c90..bdd22e20c 100644
--- a/src/zencore/mpscqueue.cpp
+++ b/src/zencore/mpscqueue.cpp
@@ -7,7 +7,7 @@
namespace zen {
-#if ZEN_WITH_TESTS && 0
+#if ZEN_WITH_TESTS
TEST_SUITE_BEGIN("core.mpscqueue");
TEST_CASE("mpsc")
{
@@ -24,4 +24,4 @@ mpscqueue_forcelink()
{
}
-} // namespace zen \ No newline at end of file
+} // namespace zen
diff --git a/src/zencore/sentryintegration.cpp b/src/zencore/sentryintegration.cpp
index 636e182b4..bfff114c3 100644
--- a/src/zencore/sentryintegration.cpp
+++ b/src/zencore/sentryintegration.cpp
@@ -81,8 +81,13 @@ sentry_sink::sink_it_(const spdlog::details::log_msg& msg)
}
try
{
- std::string Message = fmt::format("{}\n{}({}) [{}]", msg.payload, msg.source.filename, msg.source.line, msg.source.funcname);
- sentry_value_t event = sentry_value_new_message_event(
+ auto MaybeNullString = [](const char* Ptr) { return Ptr ? Ptr : "<null>"; };
+ std::string Message = fmt::format("{}\n{}({}) [{}]",
+ msg.payload,
+ MaybeNullString(msg.source.filename),
+ msg.source.line,
+ MaybeNullString(msg.source.funcname));
+ sentry_value_t event = sentry_value_new_message_event(
/* level */ MapToSentryLevel[msg.level],
/* logger */ nullptr,
/* message */ Message.c_str());
diff --git a/src/zencore/string.cpp b/src/zencore/string.cpp
index 3d0451e27..ed0ba6f46 100644
--- a/src/zencore/string.cpp
+++ b/src/zencore/string.cpp
@@ -268,6 +268,17 @@ namespace {
/* kNicenumTime */ 1000};
} // namespace
+uint64_t
+IntPow(uint64_t Base, int Exp)
+{
+ uint64_t Result = 1;
+ for (int I = 0; I < Exp; ++I)
+ {
+ Result *= Base;
+ }
+ return Result;
+}
+
/*
* Convert a number to an appropriately human-readable output.
*/
@@ -315,7 +326,7 @@ NiceNumGeneral(uint64_t Num, std::span<char> Buffer, NicenumFormat Format)
const char* u = UnitStrings[Format][Index];
- if ((Index == 0) || ((Num % (uint64_t)powl((int)KiloUnit[Format], Index)) == 0))
+ if ((Index == 0) || ((Num % IntPow(KiloUnit[Format], Index)) == 0))
{
/*
* If this is an even multiple of the base, always display
@@ -339,7 +350,7 @@ NiceNumGeneral(uint64_t Num, std::span<char> Buffer, NicenumFormat Format)
for (int i = 2; i >= 0; i--)
{
- double Value = (double)Num / (uint64_t)powl((int)KiloUnit[Format], Index);
+ double Value = (double)Num / IntPow(KiloUnit[Format], Index);
/*
* Don't print floating point values for time. Note,
diff --git a/src/zencore/thread.cpp b/src/zencore/thread.cpp
index 9e3486e49..54459cbaa 100644
--- a/src/zencore/thread.cpp
+++ b/src/zencore/thread.cpp
@@ -133,7 +133,10 @@ SetCurrentThreadName([[maybe_unused]] std::string_view ThreadName)
#elif ZEN_PLATFORM_MAC
pthread_setname_np(ThreadNameZ.c_str());
#else
- pthread_setname_np(pthread_self(), ThreadNameZ.c_str());
+ // Linux pthread_setname_np has a 16-byte limit (15 chars + NUL)
+ StringBuilder<16> LinuxThreadName;
+ LinuxThreadName << LimitedThreadName.substr(0, 15);
+ pthread_setname_np(pthread_self(), LinuxThreadName.c_str());
#endif
} // namespace zen
@@ -233,12 +236,15 @@ Event::Close()
#else
std::atomic_thread_fence(std::memory_order_acquire);
auto* Inner = (EventInner*)m_EventHandle.load();
+ if (Inner)
{
- std::unique_lock Lock(Inner->Mutex);
- Inner->bSet.store(true);
- m_EventHandle = nullptr;
+ {
+ std::unique_lock Lock(Inner->Mutex);
+ Inner->bSet.store(true);
+ m_EventHandle = nullptr;
+ }
+ delete Inner;
}
- delete Inner;
#endif
}
@@ -351,7 +357,7 @@ NamedEvent::NamedEvent(std::string_view EventName)
intptr_t Packed;
Packed = intptr_t(Sem) << 32;
Packed |= intptr_t(Fd) & 0xffff'ffff;
- m_EventHandle = (void*)Packed;
+ m_EventHandle = (void*)Packed;
#endif
ZEN_ASSERT(m_EventHandle != nullptr);
}
@@ -372,7 +378,9 @@ NamedEvent::Close()
#if ZEN_PLATFORM_WINDOWS
CloseHandle(m_EventHandle);
#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
- int Fd = int(intptr_t(m_EventHandle.load()) & 0xffff'ffff);
+ const intptr_t Handle = intptr_t(m_EventHandle.load());
+ const int Fd = int(Handle & 0xffff'ffff);
+ const int Sem = int(Handle >> 32);
if (flock(Fd, LOCK_EX | LOCK_NB) == 0)
{
@@ -388,11 +396,10 @@ NamedEvent::Close()
}
flock(Fd, LOCK_UN | LOCK_NB);
- close(Fd);
-
- int Sem = int(intptr_t(m_EventHandle.load()) >> 32);
semctl(Sem, 0, IPC_RMID);
}
+
+ close(Fd);
#endif
m_EventHandle = nullptr;
@@ -481,9 +488,12 @@ NamedMutex::~NamedMutex()
CloseHandle(m_MutexHandle);
}
#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
- int Inner = int(intptr_t(m_MutexHandle));
- flock(Inner, LOCK_UN);
- close(Inner);
+ if (m_MutexHandle)
+ {
+ int Inner = int(intptr_t(m_MutexHandle));
+ flock(Inner, LOCK_UN);
+ close(Inner);
+ }
#endif
}
@@ -516,7 +526,6 @@ NamedMutex::Create(std::string_view MutexName)
if (flock(Inner, LOCK_EX) != 0)
{
close(Inner);
- Inner = 0;
return false;
}
@@ -583,6 +592,11 @@ GetCurrentThreadId()
void
Sleep(int ms)
{
+ if (ms <= 0)
+ {
+ return;
+ }
+
#if ZEN_PLATFORM_WINDOWS
::Sleep(ms);
#else
diff --git a/src/zencore/trace.cpp b/src/zencore/trace.cpp
index a026974c0..7c195e69f 100644
--- a/src/zencore/trace.cpp
+++ b/src/zencore/trace.cpp
@@ -10,7 +10,16 @@
# define TRACE_IMPLEMENT 1
# undef _WINSOCK_DEPRECATED_NO_WARNINGS
+// GCC false positives in thirdparty trace.h (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100137)
+# if ZEN_COMPILER_GCC
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wstringop-overread"
+# pragma GCC diagnostic ignored "-Wdangling-pointer"
+# endif
# include <zencore/trace.h>
+# if ZEN_COMPILER_GCC
+# pragma GCC diagnostic pop
+# endif
# include <zencore/memory/fmalloc.h>
# include <zencore/memory/memorytrace.h>
diff --git a/src/zencore/xmake.lua b/src/zencore/xmake.lua
index ab842f6ed..2f81b7ec8 100644
--- a/src/zencore/xmake.lua
+++ b/src/zencore/xmake.lua
@@ -14,12 +14,7 @@ target('zencore')
end)
set_configdir("include/zencore")
add_files("**.cpp")
- if is_plat("linux") and not (get_config("toolchain") or ""):find("clang") then
- -- GCC false positives in thirdparty trace.h (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100137)
- add_files("trace.cpp", {unity_ignored = true, force = {cxxflags = {"-Wno-stringop-overread", "-Wno-dangling-pointer"}} })
- else
- add_files("trace.cpp", {unity_ignored = true })
- end
+ add_files("trace.cpp", {unity_ignored = true })
add_files("testing.cpp", {unity_ignored = true })
if has_config("zenrpmalloc") then