Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,50 @@ else()
# A version test rather than a flag probe, deliberately: the flags all EXIST here, it is
# their judgement that is wrong, so CheckCXXCompilerFlag would happily confirm them.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16)
add_compile_options(-Wno-error=null-dereference
-Wno-error=restrict
add_compile_options(-Wno-error=restrict
-Wno-error=stringop-overflow
-Wno-error=format-truncation)
endif()

# -Wnull-dereference also fires on GCC 16.2.1, past the version bound above, but only for one
# real class of site: a plain `this->member_` read inlined through a lambda/callback chain
# (MoonModule::enabled()'s `enabled_ && !held_`, reached through several tests' std::function
# plumbing) where GCC's analysis loses track of `this` and can't prove it non-null. There is no
# source fix for that shape (testing `this == nullptr` in a member function is not meaningful),
# so it stays unconditional for GCC pending a version where it is confirmed to stop. Two other
# sites GCC flagged under the same warning turned out to be real, provably-safe `rootNode()`
# calls gated on a prior `json::parse()` success and are fixed directly instead (StateDocument.cpp,
# ControlModule.h::readHeader) — this exception covers only the this-across-a-thunk shape now.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-error=null-dereference)
endif()

# -Warray-bounds= fires on GCC 16.2.1 too: MoonModule::setName's std::memcpy(name_, n, len)
# is bound-checked (len < sizeof(name_), a real fixed array) before the call, but GCC 16.2.1,
# inlining it through several unit tests' DOCTEST_ANON_FUNCs, deduces a 0-byte region for
# name_ at some of those call sites and reports offset 0 as out of [0, 0] bounds — a false
# positive from the same aggressive-inlining-loses-the-real-size class as the others here.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-error=array-bounds=)
endif()

# -Wmaybe-uninitialized fires on GCC 16.2.1 too: unit_Hub75Driver_pins.cpp reads out[i] only
# for i < n (n itself checked == 14 just above), but GCC 16.2.1 flags out[14]/out[15] anyway,
# past the loop's own dynamic bound — a `fixedPins(out, 16)` return value it isn't correlating
# with the loop condition after inlining, not a real read of memory the loop never reaches.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-error=maybe-uninitialized)
endif()

# Vendored doctest.h always includes <ciso646> on Clang, unconditionally, to detect libc++ via
# _LIBCPP_VERSION (doctest's own long-standing quirk: github.com/doctest/doctest/issues/126, #356).
# A Clang new enough to deprecate that pre-C++20 header turns its #warning into a build failure
# under -Werror. Third-party header code we don't own, so this stays unconditional rather than
# version-gated, matching the MSVC C5285 suppression above for the same vendored file.
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options("-Wno-error=#warnings") # quoted: a bare # starts a CMake comment, truncating the rest of the file
endif()

# Hot-path discipline, enforced by the compiler. MM_NONBLOCKING marks tick/tick20ms/tick1s
# (platform.h); -Wfunction-effects then checks TRANSITIVELY that nothing they reach
# allocates or blocks, through the whole call graph. Clang 20+ only; the flag does not
Expand Down
3 changes: 2 additions & 1 deletion src/core/module/StateDocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ StateDocumentResult applyStateDocument(Scheduler& scheduler, const char* text, S
JsonDoc doc;
if (!json::parse(text, doc)) { r.ok = false; r.error = doc.outOfMemory ? "out of memory" : "malformed JSON"; return r; }
const JsonNode* root = doc.rootNode();
if (root->type != JsonType::Object) { r.ok = false; r.error = "a document is a JSON object"; return r; }
if (!root || root->type != JsonType::Object) { r.ok = false; r.error = "a document is a JSON object"; return r; }

Applier a{scheduler, doc, r, source};
for (int pass = 0; pass < 3 && a.runPass(pass, root); pass++) {}
Expand Down Expand Up @@ -702,6 +702,7 @@ namespace {
// The flat file's values directly under `prefix`, each as `,"key":value`.
void writeFlatValues(JsonSink& out, const JsonDoc& doc, const char* prefix) {
const JsonNode* root = doc.rootNode();
if (!root) return;
const size_t pl = std::strlen(prefix);
for (const JsonNode* n = doc.node(root->firstChild); n; n = doc.node(n->next)) {
if (std::strncmp(n->key, prefix, pl) != 0) continue;
Expand Down
7 changes: 5 additions & 2 deletions src/core/system/ControlModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -970,8 +970,11 @@ class ControlModule : public MoonModule, public ListSource {
char* body = readFile(path);
if (!body) return;
json::JsonDoc doc;
if (json::parse(body, doc) && doc.rootNode()->type == json::JsonType::Object)
for (const json::JsonNode* m = doc.node(doc.rootNode()->firstChild); m; m = doc.node(m->next)) readRootKey(p, *m);
if (json::parse(body, doc)) {
const json::JsonNode* root = doc.rootNode();
if (root && root->type == json::JsonType::Object)
for (const json::JsonNode* m = doc.node(root->firstChild); m; m = doc.node(m->next)) readRootKey(p, *m);
}
platform::free(body);
}

Expand Down
2 changes: 2 additions & 0 deletions src/platform/desktop/platform_desktop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2965,6 +2965,8 @@ bool ndiLoad() {
}
// NDIlib_initialize returns false when the CPU is unsupported, a real "cannot use it" that must not read as "installed and working".
if (!ndiInit_()) { ndiSendVideo_ = nullptr; return false; }
// NDIlib_destroy pairs with NDIlib_initialize at process exit, since a sender may reopen later in the same run. Only with no sender open: a quit closes it first, while a reboot exits with the render thread still sending, where the process ending is the teardown.
std::atexit([]() { if (ndiDestroy_ && !ndiSender_) ndiDestroy_(); });
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion test/unit/core/unit_Buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ TEST_CASE("Buffer allocate and accessors") {
// clear() zeroes every byte in the allocated range.
TEST_CASE("Buffer clear zeros data") {
mm::Buffer buf;
buf.allocate(10, 3);
REQUIRE(buf.allocate(10, 3));
// Write some data
buf.data()[0] = 0xFF;
buf.data()[15] = 0xAB;
Expand Down
Loading