From 52242627ef2d7075bf79bfb4abb8028f47bb9695 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 21 Apr 2022 19:25:48 -0700 Subject: [PATCH 1/8] Updated storage bad usage --- buildcc/lib/env/include/env/storage.h | 10 ++++++---- buildcc/lib/env/src/storage.cpp | 6 ++++++ buildcc/lib/env/test/test_storage.cpp | 8 ++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/buildcc/lib/env/include/env/storage.h b/buildcc/lib/env/include/env/storage.h index ccd1d1c9..6ca3908b 100644 --- a/buildcc/lib/env/include/env/storage.h +++ b/buildcc/lib/env/include/env/storage.h @@ -104,19 +104,21 @@ class Storage { template static T &Add(const std::string &identifier, Params &&...params) { - return internal_->Add(identifier, - std::forward(params)...); + return Ref().Add(identifier, std::forward(params)...); } template static const T &ConstRef(const std::string &identifier) { - return internal_->ConstRef(identifier); + return Ref().ConstRef(identifier); } template static T &Ref(const std::string &identifier) { - return internal_->Ref(identifier); + return Ref().Ref(identifier); } +private: + static ScopedStorage &Ref(); + private: static std::unique_ptr internal_; }; diff --git a/buildcc/lib/env/src/storage.cpp b/buildcc/lib/env/src/storage.cpp index 37bae38b..6712c008 100644 --- a/buildcc/lib/env/src/storage.cpp +++ b/buildcc/lib/env/src/storage.cpp @@ -20,4 +20,10 @@ namespace buildcc { std::unique_ptr Storage::internal_; +ScopedStorage &Storage::Ref() { + env::assert_fatal(internal_ != nullptr, + "Initialize Storage using the Storage::Init API"); + return *internal_; } + +} // namespace buildcc diff --git a/buildcc/lib/env/test/test_storage.cpp b/buildcc/lib/env/test/test_storage.cpp index ccd4be83..929fc0ba 100644 --- a/buildcc/lib/env/test/test_storage.cpp +++ b/buildcc/lib/env/test/test_storage.cpp @@ -86,6 +86,14 @@ TEST(StorageTestGroup, BasicUsage) { STRCMP_EQUAL(bigobj2.c_str(), "name2"); } +TEST(StorageTestGroup, UsageWithoutInit) { + buildcc::Storage::Deinit(); + + CHECK_THROWS(std::exception, buildcc::Storage::Add("integer")); + CHECK_THROWS(std::exception, buildcc::Storage::Ref("integer")); + CHECK_THROWS(std::exception, buildcc::Storage::ConstRef("integer")); +} + int main(int ac, char **av) { return CommandLineTestRunner::RunAllTests(ac, av); } From 776ff739d62bd8c76ba240c1272a4a5440cb4051 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 21 Apr 2022 19:26:32 -0700 Subject: [PATCH 2/8] Assert fatal uses std::exit instead of std::terminate --- buildcc/lib/env/include/env/assert_fatal.h | 2 +- buildcc/lib/env/src/assert_fatal.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildcc/lib/env/include/env/assert_fatal.h b/buildcc/lib/env/include/env/assert_fatal.h index 481e7a3c..ee159703 100644 --- a/buildcc/lib/env/include/env/assert_fatal.h +++ b/buildcc/lib/env/include/env/assert_fatal.h @@ -24,7 +24,7 @@ namespace buildcc::env { /** - * @brief During Release -> std::terminate + * @brief During Release -> std::exit * During Unit Test -> throw std::exception */ [[noreturn]] void assert_handle_fatal(); diff --git a/buildcc/lib/env/src/assert_fatal.cpp b/buildcc/lib/env/src/assert_fatal.cpp index 7d7becf3..870e18be 100644 --- a/buildcc/lib/env/src/assert_fatal.cpp +++ b/buildcc/lib/env/src/assert_fatal.cpp @@ -20,6 +20,6 @@ namespace buildcc::env { -[[noreturn]] void assert_handle_fatal() { std::terminate(); } +[[noreturn]] void assert_handle_fatal() { std::exit(1); } } // namespace buildcc::env From 7ff4fbe974c87042d91be21acca0b7dded7f4a17 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 21 Apr 2022 20:51:22 -0700 Subject: [PATCH 3/8] Updated assert_fatal implementation --- buildcc/lib/env/include/env/assert_fatal.h | 2 +- buildcc/lib/env/mock/assert_fatal.cpp | 2 +- buildcc/lib/env/src/assert_fatal.cpp | 23 +++++++++++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/buildcc/lib/env/include/env/assert_fatal.h b/buildcc/lib/env/include/env/assert_fatal.h index ee159703..1bd55330 100644 --- a/buildcc/lib/env/include/env/assert_fatal.h +++ b/buildcc/lib/env/include/env/assert_fatal.h @@ -27,7 +27,7 @@ namespace buildcc::env { * @brief During Release -> std::exit * During Unit Test -> throw std::exception */ -[[noreturn]] void assert_handle_fatal(); +void assert_handle_fatal(); /** * @brief Compile time expr asserts fatally when false diff --git a/buildcc/lib/env/mock/assert_fatal.cpp b/buildcc/lib/env/mock/assert_fatal.cpp index 08d1b462..2a64b2e8 100644 --- a/buildcc/lib/env/mock/assert_fatal.cpp +++ b/buildcc/lib/env/mock/assert_fatal.cpp @@ -4,6 +4,6 @@ namespace buildcc::env { -[[noreturn]] void assert_handle_fatal() { throw std::exception(); } +void assert_handle_fatal() { throw std::exception(); } } // namespace buildcc::env diff --git a/buildcc/lib/env/src/assert_fatal.cpp b/buildcc/lib/env/src/assert_fatal.cpp index 870e18be..a7f1f095 100644 --- a/buildcc/lib/env/src/assert_fatal.cpp +++ b/buildcc/lib/env/src/assert_fatal.cpp @@ -17,9 +17,30 @@ #include "env/assert_fatal.h" #include +#include + +namespace { + +std::thread::id main_id = std::this_thread::get_id(); + +bool IsRunningOnThread() { + bool threaded = true; + if (std::this_thread::get_id() == main_id) { + threaded = false; + } + return threaded; +} + +} // namespace namespace buildcc::env { -[[noreturn]] void assert_handle_fatal() { std::exit(1); } +void assert_handle_fatal() { + if (!IsRunningOnThread()) { + std::exit(1); + } + + throw std::exception(); +} } // namespace buildcc::env From 67a74af3b2d79f226b3faac452d72b60c9defec2 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 21 Apr 2022 20:51:46 -0700 Subject: [PATCH 4/8] Added assert_fatal test --- buildcc/lib/env/CMakeLists.txt | 4 ++ buildcc/lib/env/test/test_assert_fatal.cpp | 72 ++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 buildcc/lib/env/test/test_assert_fatal.cpp diff --git a/buildcc/lib/env/CMakeLists.txt b/buildcc/lib/env/CMakeLists.txt index f18d6b24..64808853 100644 --- a/buildcc/lib/env/CMakeLists.txt +++ b/buildcc/lib/env/CMakeLists.txt @@ -42,11 +42,15 @@ if (${TESTING}) add_executable(test_storage test/test_storage.cpp) target_link_libraries(test_storage PRIVATE mock_env) + add_executable(test_assert_fatal test/test_assert_fatal.cpp) + target_link_libraries(test_assert_fatal PRIVATE mock_env) + add_test(NAME test_static_project COMMAND test_static_project) add_test(NAME test_env_util COMMAND test_env_util) add_test(NAME test_task_state COMMAND test_task_state) add_test(NAME test_command COMMAND test_command) add_test(NAME test_storage COMMAND test_storage) + add_test(NAME test_assert_fatal COMMAND test_assert_fatal) endif() set(ENV_SRCS diff --git a/buildcc/lib/env/test/test_assert_fatal.cpp b/buildcc/lib/env/test/test_assert_fatal.cpp new file mode 100644 index 00000000..67e3b986 --- /dev/null +++ b/buildcc/lib/env/test/test_assert_fatal.cpp @@ -0,0 +1,72 @@ +#include + +#include "taskflow/taskflow.hpp" + +// NOTE, Make sure all these includes are AFTER the system and header includes +#include "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/MemoryLeakDetectorNewMacros.h" +#include "CppUTest/TestHarness.h" +#include "CppUTest/Utest.h" +#include "CppUTestExt/MockSupport.h" + +namespace { + +std::thread::id my_main_thread = std::this_thread::get_id(); + +bool IsRunningInThread() { + bool threaded = true; + if (std::this_thread::get_id() == my_main_thread) { + threaded = false; + } + return threaded; +} + +void assert_handle_fatal() { + if (IsRunningInThread()) { + mock().actualCall("assert_handle_fatal_threaded"); + } else { + mock().actualCall("assert_handle_fatal_main"); + } +} + +} // namespace + +// clang-format off +TEST_GROUP(AssertFatalTestGroup) +{ + void teardown() { + mock().clear(); + } +}; +// clang-format on + +TEST(AssertFatalTestGroup, AssertFatal_IsThreadedCheck) { + CHECK_FALSE(IsRunningInThread()); + + tf::Taskflow tf; + tf.emplace([]() { CHECK_TRUE(IsRunningInThread()); }); + + tf::Executor ex(1); + ex.run(tf); + ex.wait_for_all(); +} + +TEST(AssertFatalTestGroup, AssertFatal_Threaded) { + mock().expectOneCall("assert_handle_fatal_threaded"); + + tf::Taskflow tf; + tf.emplace([]() { assert_handle_fatal(); }); + + tf::Executor ex(1); + ex.run(tf); + ex.wait_for_all(); +} + +TEST(AssertFatalTestGroup, AssertFatal_NotThreaded) { + mock().expectOneCall("assert_handle_fatal_main"); + assert_handle_fatal(); +} + +int main(int ac, char **av) { + return CommandLineTestRunner::RunAllTests(ac, av); +} From 85336a9a617e364a81f47a0174cf74375880a625 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 21 Apr 2022 21:16:13 -0700 Subject: [PATCH 5/8] Removed assert_throw --- buildcc/lib/env/CMakeLists.txt | 1 - buildcc/lib/env/include/env/assert_throw.h | 69 ---------------------- 2 files changed, 70 deletions(-) delete mode 100644 buildcc/lib/env/include/env/assert_throw.h diff --git a/buildcc/lib/env/CMakeLists.txt b/buildcc/lib/env/CMakeLists.txt index 64808853..8af914c2 100644 --- a/buildcc/lib/env/CMakeLists.txt +++ b/buildcc/lib/env/CMakeLists.txt @@ -58,7 +58,6 @@ set(ENV_SRCS src/assert_fatal.cpp src/logging.cpp include/env/assert_fatal.h - include/env/assert_throw.h include/env/env.h include/env/logging.h include/env/util.h diff --git a/buildcc/lib/env/include/env/assert_throw.h b/buildcc/lib/env/include/env/assert_throw.h deleted file mode 100644 index b070f22e..00000000 --- a/buildcc/lib/env/include/env/assert_throw.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2021-2022 Niket Naidu. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ENV_ASSERT_THROW_H_ -#define ENV_ASSERT_THROW_H_ - -#include - -#include "logging.h" - -namespace buildcc::env { - -/** - * @brief Compile time expr asserts fatally when false - */ -template -inline void assert_throw([[maybe_unused]] const char *message) { - if constexpr (!expr) { - env::log_critical("assert", message); - // TODO, If needed specialize this - throw std::exception(); - } -} - -/** - * @brief Compile time expr asserts fatally when false - */ -template inline void assert_throw(const std::string &message) { - assert_throw(message.c_str()); -} - -/** - * @brief Runtime expr asserts fatally when false - */ -inline void assert_throw(bool expression, const char *message) { - if (!expression) { - assert_throw(message); - } -} - -/** - * @brief Runtime expr asserts fatally when false - */ -inline void assert_throw(bool expression, const std::string &message) { - assert_throw(expression, message.c_str()); -} - -} // namespace buildcc::env - -/** - * @brief Runtime expr assert throws when false - */ -#define ASSERT_THROW(expr, message) \ - ((expr) ? static_cast(0) : buildcc::env::assert_throw(message)) - -#endif From 7cdadd10e4833784e2116e02dc9cce1b2d460827 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 21 Apr 2022 21:16:51 -0700 Subject: [PATCH 6/8] Replaced assert_throw with assert_fatal --- buildcc/lib/target/src/generator/task.cpp | 4 ++-- buildcc/lib/target/src/target/friend/compile_pch.cpp | 6 +++--- buildcc/lib/target/src/target/friend/link_target.cpp | 2 +- buildcc/lib/target/src/target/tasks.cpp | 4 ++-- buildcc/schema/include/schema/path.h | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/buildcc/lib/target/src/generator/task.cpp b/buildcc/lib/target/src/generator/task.cpp index 60e396fe..673e612e 100644 --- a/buildcc/lib/target/src/generator/task.cpp +++ b/buildcc/lib/target/src/generator/task.cpp @@ -52,7 +52,7 @@ void Generator::GenerateTask() { auto run_command = [this](const std::string &command) { try { bool success = env::Command::Execute(command); - env::assert_throw(success, fmt::format("{} failed", command)); + env::assert_fatal(success, fmt::format("{} failed", command)); } catch (...) { std::lock_guard guard(task_state_mutex_); task_state_ = env::TaskState::FAILURE; @@ -104,7 +104,7 @@ void Generator::GenerateTask() { if (dirty_) { try { serialization_.UpdateStore(user_); - env::assert_throw(serialization_.StoreToFile(), + env::assert_fatal(serialization_.StoreToFile(), fmt::format("Store failed for {}", name_)); } catch (...) { task_state_ = env::TaskState::FAILURE; diff --git a/buildcc/lib/target/src/target/friend/compile_pch.cpp b/buildcc/lib/target/src/target/friend/compile_pch.cpp index 83e7cf62..8af27578 100644 --- a/buildcc/lib/target/src/target/friend/compile_pch.cpp +++ b/buildcc/lib/target/src/target/friend/compile_pch.cpp @@ -54,7 +54,7 @@ void AggregateToFile(const fs::path &filename, }); bool success = buildcc::env::save_file( buildcc::path_as_string(filename).c_str(), constructed_output, false); - buildcc::env::assert_throw(success, "Could not save pch file"); + buildcc::env::assert_fatal(success, "Could not save pch file"); } } // namespace @@ -108,10 +108,10 @@ void CompilePch::BuildCompile() { const std::string p = fmt::format("{}", source_path_); const bool save = env::save_file(p.c_str(), {"//Generated by BuildCC"}, false); - env::assert_throw(save, fmt::format("Could not save {}", p)); + env::assert_fatal(save, fmt::format("Could not save {}", p)); } bool success = env::Command::Execute(command_); - env::assert_throw(success, "Failed to compile pch"); + env::assert_fatal(success, "Failed to compile pch"); } } diff --git a/buildcc/lib/target/src/target/friend/link_target.cpp b/buildcc/lib/target/src/target/friend/link_target.cpp index 49bc52b7..8e1f4b8b 100644 --- a/buildcc/lib/target/src/target/friend/link_target.cpp +++ b/buildcc/lib/target/src/target/friend/link_target.cpp @@ -98,7 +98,7 @@ void LinkTarget::BuildLink() { if (target_.dirty_) { bool success = env::Command::Execute(command_); - env::assert_throw(success, "Failed to link target"); + env::assert_fatal(success, "Failed to link target"); target_.serialization_.UpdateTargetCompiled(); } } diff --git a/buildcc/lib/target/src/target/tasks.cpp b/buildcc/lib/target/src/target/tasks.cpp index 7b659787..7f46c99f 100644 --- a/buildcc/lib/target/src/target/tasks.cpp +++ b/buildcc/lib/target/src/target/tasks.cpp @@ -124,7 +124,7 @@ void CompileObject::Task() { try { bool success = env::Command::Execute( GetObjectData(s.GetPathname()).command); - env::assert_throw(success, "Could not compile source"); + env::assert_fatal(success, "Could not compile source"); target_.serialization_.AddSource(s); } catch (...) { target_.SetTaskStateFailure(); @@ -170,7 +170,7 @@ void Target::EndTask() { if (dirty_) { try { serialization_.UpdateStore(user_); - env::assert_throw(serialization_.StoreToFile(), + env::assert_fatal(serialization_.StoreToFile(), fmt::format("Store failed for {}", GetName())); state_.BuildCompleted(); } catch (...) { diff --git a/buildcc/schema/include/schema/path.h b/buildcc/schema/include/schema/path.h index 2ee2f3ae..1810d3d1 100644 --- a/buildcc/schema/include/schema/path.h +++ b/buildcc/schema/include/schema/path.h @@ -25,7 +25,7 @@ #include // Env -#include "env/assert_throw.h" +#include "env/assert_fatal.h" // Third party #include "fmt/format.h" @@ -51,7 +51,7 @@ class Path { std::filesystem::last_write_time(pathname, errcode) .time_since_epoch() .count(); - env::assert_throw(errcode.value() == 0, + env::assert_fatal(errcode.value() == 0, fmt::format("{} not found", pathname)); return Path(pathname, last_write_timestamp); From 1ecc00f5bf1b50569b62962bc269961f34217fae Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 21 Apr 2022 21:18:58 -0700 Subject: [PATCH 7/8] Updated assert_fatal.h --- buildcc/lib/env/include/env/assert_fatal.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/buildcc/lib/env/include/env/assert_fatal.h b/buildcc/lib/env/include/env/assert_fatal.h index 1bd55330..6b0f9e6f 100644 --- a/buildcc/lib/env/include/env/assert_fatal.h +++ b/buildcc/lib/env/include/env/assert_fatal.h @@ -24,7 +24,11 @@ namespace buildcc::env { /** - * @brief During Release -> std::exit + * @brief During Release -> + * NOT THREADED : std::exit + * THREADED : throw std::exception (it is wrong to exit + * when in a threaded state. We want to handle the exception and gracefully + * exit) * During Unit Test -> throw std::exception */ void assert_handle_fatal(); From 2f16a694cb3316b63d3fdf65a1a8ce7dfca85da4 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Fri, 22 Apr 2022 01:21:24 -0700 Subject: [PATCH 8/8] Updated assert_fatal --- buildcc/lib/env/include/env/assert_fatal.h | 2 +- buildcc/lib/env/mock/assert_fatal.cpp | 2 +- buildcc/lib/env/src/assert_fatal.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/buildcc/lib/env/include/env/assert_fatal.h b/buildcc/lib/env/include/env/assert_fatal.h index 6b0f9e6f..9f048066 100644 --- a/buildcc/lib/env/include/env/assert_fatal.h +++ b/buildcc/lib/env/include/env/assert_fatal.h @@ -31,7 +31,7 @@ namespace buildcc::env { * exit) * During Unit Test -> throw std::exception */ -void assert_handle_fatal(); +[[noreturn]] void assert_handle_fatal(); /** * @brief Compile time expr asserts fatally when false diff --git a/buildcc/lib/env/mock/assert_fatal.cpp b/buildcc/lib/env/mock/assert_fatal.cpp index 2a64b2e8..08d1b462 100644 --- a/buildcc/lib/env/mock/assert_fatal.cpp +++ b/buildcc/lib/env/mock/assert_fatal.cpp @@ -4,6 +4,6 @@ namespace buildcc::env { -void assert_handle_fatal() { throw std::exception(); } +[[noreturn]] void assert_handle_fatal() { throw std::exception(); } } // namespace buildcc::env diff --git a/buildcc/lib/env/src/assert_fatal.cpp b/buildcc/lib/env/src/assert_fatal.cpp index a7f1f095..c1f6dd62 100644 --- a/buildcc/lib/env/src/assert_fatal.cpp +++ b/buildcc/lib/env/src/assert_fatal.cpp @@ -35,12 +35,12 @@ bool IsRunningOnThread() { namespace buildcc::env { -void assert_handle_fatal() { +[[noreturn]] void assert_handle_fatal() { if (!IsRunningOnThread()) { std::exit(1); + } else { + throw std::exception(); } - - throw std::exception(); } } // namespace buildcc::env