From 147a479e7ecd35db29b23a4f14557c3dd8dfc6b1 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 17 Dec 2025 12:54:48 +0100 Subject: [PATCH 1/6] add ubsan + hardening for gcc Signed-off-by: Martijn Govers --- CMakePresets.json | 4 +- .../power_grid_model/CMakeLists.txt | 3 +- .../power_grid_model/auxiliary/dataset.hpp | 16 +++--- .../power_grid_model/math_solver/y_bus.hpp | 54 +++++++++++-------- .../include/power_grid_model/topology.hpp | 13 +++-- .../power_grid_model_c/CMakeLists.txt | 22 ++++++++ pyproject.toml | 1 + 7 files changed, 74 insertions(+), 39 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 9e68e113fa..4052c63de0 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -61,7 +61,7 @@ "hidden": true, "environment": { "PreferredToolArchitecture": "x64", - "PLATFORM_C_FLAGS": "/DWIN32 /D_WINDOWS /W4 /WX /GR /EHsc /utf-8 /bigobj /FC" + "PLATFORM_C_FLAGS": "/DWIN32 /D_WINDOWS /W4 /WX /GR /EHsc /utf-8 /bigobj /FC /RTC1" }, "condition": { "type": "equals", @@ -109,7 +109,7 @@ { "name": "unix-sanitizer", "environment": { - "SANITIZER_FLAGS": "-fsanitize=address" + "SANITIZER_FLAGS": "-fsanitize=address,pointer-compare,undefined" }, "inherits": "unix-base", "hidden": true diff --git a/power_grid_model_c/power_grid_model/CMakeLists.txt b/power_grid_model_c/power_grid_model/CMakeLists.txt index 6584a571fa..a2ec3f3b57 100644 --- a/power_grid_model_c/power_grid_model/CMakeLists.txt +++ b/power_grid_model_c/power_grid_model/CMakeLists.txt @@ -29,6 +29,7 @@ target_compile_options( power_grid_model BEFORE INTERFACE + "$<$:-fstack-protector>" "$<$:-Wno-unknown-attributes>" - "$<$:/bigobj>" + "$<$:/bigobj /RTC1>" ) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/dataset.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/dataset.hpp index 3108f6307c..970dc5b6ce 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/dataset.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/dataset.hpp @@ -97,14 +97,14 @@ class ColumnarAttributeRange : public std::ranges::view_interface { - AttributeType const* buffer_ptr = - reinterpret_cast(attribute_buffer.data) + idx_; - auto& attribute_ref = - meta_attribute.template get_attribute(reinterpret_cast(&result)); - attribute_ref = *buffer_ptr; - }); + ctype_func_selector(meta_attribute.ctype, [&result, &attribute_buffer, &meta_attribute, + idx = idx_] { + AttributeType const* buffer_ptr = + reinterpret_cast(attribute_buffer.data) + idx; + AttributeType& attribute_ref = + meta_attribute.template get_attribute(reinterpret_cast(&result)); + attribute_ref = *buffer_ptr; + }); } return result; } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp index 9f76876fb3..33fe9e2003 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp @@ -289,6 +289,9 @@ template class YBus { std::shared_ptr const> const& param, std::shared_ptr const& y_bus_struct = {}) : math_topology_{topo_ptr} { + assert(math_topology_ != nullptr); + assert(param != nullptr); + // use existing struct or make new struct if (y_bus_struct) { y_bus_struct_ = y_bus_struct; @@ -447,29 +450,32 @@ template class YBus { template requires std::same_as> || std::same_as> std::vector calculate_branch_flow(ComplexValueVector const& u) const { - std::vector branch_flow(math_topology_->branch_bus_idx.size()); - std::transform(math_topology_->branch_bus_idx.cbegin(), math_topology_->branch_bus_idx.cend(), - math_model_param_->branch_param.cbegin(), branch_flow.begin(), - [&u](BranchIdx branch_idx, BranchCalcParam const& param) { - auto const [f, t] = branch_idx; - // if one side is disconnected, use zero voltage at that side - ComplexValue const uf = f != -1 ? u[f] : ComplexValue{0.0}; - ComplexValue const ut = t != -1 ? u[t] : ComplexValue{0.0}; - T output; - - // See "Branch Flow Calculation" in "State Estimation Alliander" - output.i_f = dot(param.yff(), uf) + dot(param.yft(), ut); - output.i_t = dot(param.ytf(), uf) + dot(param.ytt(), ut); - - if constexpr (std::same_as>) { - // See "Shunt Injection Flow Calculation" in "State Estimation Alliander" - output.s_f = uf * conj(output.i_f); - output.s_t = ut * conj(output.i_t); - } - - return output; - }); - return branch_flow; + assert(math_topology_ != nullptr); + + return std::views::zip(std::as_const(math_topology_->branch_bus_idx), + std::as_const(math_model_param_->branch_param)) | + std::views::transform([&u](auto const& branch_idx_params) -> T { + auto const& [branch_idx, param] = branch_idx_params; + + auto const [f, t] = branch_idx; + // if one side is disconnected, use zero voltage at that side + ComplexValue const uf = f != -1 ? u[f] : ComplexValue{0.0}; + ComplexValue const ut = t != -1 ? u[t] : ComplexValue{0.0}; + T output; + + // See "Branch Flow Calculation" in "State Estimation Alliander" + output.i_f = dot(param.yff(), uf) + dot(param.yft(), ut); + output.i_t = dot(param.ytf(), uf) + dot(param.ytt(), ut); + + if constexpr (std::same_as>) { + // See "Shunt Injection Flow Calculation" in "State Estimation Alliander" + output.s_f = uf * conj(output.i_f); + output.s_t = ut * conj(output.i_t); + } + + return output; + }) | + std::ranges::to>(); } // calculate shunt flow based on voltage, injection direction @@ -477,6 +483,8 @@ template class YBus { requires std::same_as> || std::same_as> std::vector calculate_shunt_flow(ComplexValueVector const& u) const { + assert(math_topology_ != nullptr); + std::vector shunt_flow(math_topology_->n_shunt()); for (auto const [bus, shunts] : enumerated_zip_sequence(math_topology_->shunts_per_bus)) { for (Idx const shunt : shunts) { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 367792666a..817d9342fd 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -353,8 +353,9 @@ class Topology { }; // k as branch number for 2-way branch for (auto const& [idx, branch_node_idx, branch_connected] : - std::views::zip(std::views::iota(0), comp_topo_.branch_node_idx, comp_conn_.branch_connected)) { - assert(std::ssize(branch_connected) == 2); // NOSONAR(R354) + std::views::zip(std::views::iota(0), std::as_const(comp_topo_.branch_node_idx), + std::as_const(comp_conn_.branch_connected))) { + assert(std::ssize(branch_connected) == 2); auto const [i, j] = branch_node_idx; IntS const i_status = branch_connected[0]; @@ -387,8 +388,9 @@ class Topology { } // k as branch number for 3-way branch for (auto const& [idx, i, i_status, j_math] : - std::views::zip(std::views::iota(0), comp_topo_.branch3_node_idx, comp_conn_.branch3_connected, - std::views::drop(comp_coup_.node, comp_topo_.n_node))) { + std::views::zip(std::views::iota(0), std::as_const(comp_topo_.branch3_node_idx), + std::as_const(comp_conn_.branch3_connected), + std::views::drop(std::as_const(comp_coup_.node), comp_topo_.n_node))) { std::array const i_math{ comp_coup_.node[i[0]], comp_coup_.node[i[1]], @@ -553,7 +555,8 @@ class Topology { std::ranges::for_each(math_topology_, [](MathModelTopology& topo) { topo.load_gen_type.resize(topo.n_load_gen()); }); // assign load type - for (auto const& [idx_math, load_gen_type] : std::views::zip(comp_coup_.load_gen, comp_topo_.load_gen_type)) { + for (auto const& [idx_math, load_gen_type] : + std::views::zip(std::as_const(comp_coup_.load_gen), std::as_const(comp_topo_.load_gen_type))) { if (idx_math.group == -1) { continue; } diff --git a/power_grid_model_c/power_grid_model_c/CMakeLists.txt b/power_grid_model_c/power_grid_model_c/CMakeLists.txt index 14a8ad9868..644e0b1ecc 100644 --- a/power_grid_model_c/power_grid_model_c/CMakeLists.txt +++ b/power_grid_model_c/power_grid_model_c/CMakeLists.txt @@ -49,6 +49,28 @@ set_target_properties( INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE ) +target_compile_options( + power_grid_model_c + BEFORE + PUBLIC + # "$<$,$>:-fstack-protector;-fsanitize=undefined>" + "$<$:-fstack-protector;-fsanitize=undefined;-static-libubsan>" + # "$<$:-fsanitize=undefined>" + # "$<$,$>:-fsanitize-minimal-runtime>" + "$<$:/RTC1>" +) + +target_link_options( + power_grid_model_c + BEFORE + PUBLIC + # "$<$,$>:-fstack-protector;-fsanitize=undefined>" + "$<$:-fstack-protector;-fsanitize=undefined;-static-libubsan>" + # "$<$:-fsanitize=undefined>" + # "$<$,$>:-fsanitize-minimal-runtime>" + "$<$:/RTC1>" +) + install( TARGETS power_grid_model_c EXPORT power_grid_modelTargets diff --git a/pyproject.toml b/pyproject.toml index 4da16335b8..91023ba771 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,6 +76,7 @@ Discussion = "https://github.com/orgs/PowerGridModel/discussions" power_grid_model = "power_grid_model._core.power_grid_model_c" [tool.scikit-build] +build.verbose = true logging.level = "INFO" cmake.version = ">=3.23" From 2c7c08529df9579ba3f7e88158afb2d5753780b6 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 17 Dec 2025 16:03:56 +0100 Subject: [PATCH 2/6] enable hardening for clang Signed-off-by: Martijn Govers --- CMakePresets.json | 2 +- .../power_grid_model_c/CMakeLists.txt | 23 +++++++++++-------- pyproject.toml | 1 - tests/native_api_tests/CMakeLists.txt | 5 ++++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 4052c63de0..4f6c91f2b6 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -109,7 +109,7 @@ { "name": "unix-sanitizer", "environment": { - "SANITIZER_FLAGS": "-fsanitize=address,pointer-compare,undefined" + "SANITIZER_FLAGS": "-fstack-protector;-fsanitize=address,pointer-compare,undefined" }, "inherits": "unix-base", "hidden": true diff --git a/power_grid_model_c/power_grid_model_c/CMakeLists.txt b/power_grid_model_c/power_grid_model_c/CMakeLists.txt index 644e0b1ecc..cef497aafe 100644 --- a/power_grid_model_c/power_grid_model_c/CMakeLists.txt +++ b/power_grid_model_c/power_grid_model_c/CMakeLists.txt @@ -49,25 +49,30 @@ set_target_properties( INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE ) +# Always-on hardening +target_compile_definitions( + power_grid_model_c + PUBLIC + "$<$,$>:_FORTIFY_SOURCE=2>" +) target_compile_options( power_grid_model_c BEFORE PUBLIC - # "$<$,$>:-fstack-protector;-fsanitize=undefined>" - "$<$:-fstack-protector;-fsanitize=undefined;-static-libubsan>" - # "$<$:-fsanitize=undefined>" - # "$<$,$>:-fsanitize-minimal-runtime>" + "$<$,$>:-fstack-protector;-fsanitize=undefined>" + "$<$:-static-libubsan>" + "$<$:-lubsan>" + "$<$,$,$>>>:-fsanitize-minimal-runtime>" "$<$:/RTC1>" ) - target_link_options( power_grid_model_c BEFORE PUBLIC - # "$<$,$>:-fstack-protector;-fsanitize=undefined>" - "$<$:-fstack-protector;-fsanitize=undefined;-static-libubsan>" - # "$<$:-fsanitize=undefined>" - # "$<$,$>:-fsanitize-minimal-runtime>" + "$<$,$>:-fstack-protector;-fsanitize=undefined>" + "$<$:-static-libubsan>" + "$<$:-lubsan>" + "$<$,$>>:-fsanitize-minimal-runtime>" "$<$:/RTC1>" ) diff --git a/pyproject.toml b/pyproject.toml index 91023ba771..4da16335b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,7 +76,6 @@ Discussion = "https://github.com/orgs/PowerGridModel/discussions" power_grid_model = "power_grid_model._core.power_grid_model_c" [tool.scikit-build] -build.verbose = true logging.level = "INFO" cmake.version = ">=3.23" diff --git a/tests/native_api_tests/CMakeLists.txt b/tests/native_api_tests/CMakeLists.txt index e58c80b726..c8f998db99 100644 --- a/tests/native_api_tests/CMakeLists.txt +++ b/tests/native_api_tests/CMakeLists.txt @@ -25,4 +25,9 @@ target_compile_definitions( PRIVATE PGM_ENABLE_EXPERIMENTAL ) +set_target_properties( + power_grid_model_api_tests + PROPERTIES BUILD_RPATH $ +) + doctest_discover_tests(power_grid_model_api_tests) From a482a73c7ec4b2016c1fc8657c624f9c54df483c Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Thu, 18 Dec 2025 06:57:50 +0100 Subject: [PATCH 3/6] fix typo Signed-off-by: Martijn Govers --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 4f6c91f2b6..caeb0c41e3 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -109,7 +109,7 @@ { "name": "unix-sanitizer", "environment": { - "SANITIZER_FLAGS": "-fstack-protector;-fsanitize=address,pointer-compare,undefined" + "SANITIZER_FLAGS": "-fstack-protector -fsanitize=address,pointer-compare,undefined" }, "inherits": "unix-base", "hidden": true From 43b2aa6a72296f95d925607496ba7f8552120ac6 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Thu, 18 Dec 2025 07:46:42 +0100 Subject: [PATCH 4/6] windows hardening Signed-off-by: Martijn Govers --- CMakePresets.json | 5 ++++- power_grid_model_c/power_grid_model/CMakeLists.txt | 9 --------- power_grid_model_c/power_grid_model_c/CMakeLists.txt | 9 ++++----- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index caeb0c41e3..a4e01a49e0 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -61,7 +61,7 @@ "hidden": true, "environment": { "PreferredToolArchitecture": "x64", - "PLATFORM_C_FLAGS": "/DWIN32 /D_WINDOWS /W4 /WX /GR /EHsc /utf-8 /bigobj /FC /RTC1" + "PLATFORM_C_FLAGS": "/DWIN32 /D_WINDOWS /W4 /WX /GR /EHsc /utf-8 /bigobj /FC" }, "condition": { "type": "equals", @@ -137,6 +137,9 @@ { "name": "msvc-debug", "displayName": "Debug (MSVC)", + "environment": { + "SANITIZER_FLAGS": "/RTC1" + }, "inherits": [ "msvc-base", "debug" diff --git a/power_grid_model_c/power_grid_model/CMakeLists.txt b/power_grid_model_c/power_grid_model/CMakeLists.txt index a2ec3f3b57..ff1c4f3eb7 100644 --- a/power_grid_model_c/power_grid_model/CMakeLists.txt +++ b/power_grid_model_c/power_grid_model/CMakeLists.txt @@ -24,12 +24,3 @@ target_include_directories( # only use MPL version of eigen target_compile_definitions(power_grid_model INTERFACE "EIGEN_MPL2_ONLY=1") - -target_compile_options( - power_grid_model - BEFORE - INTERFACE - "$<$:-fstack-protector>" - "$<$:-Wno-unknown-attributes>" - "$<$:/bigobj /RTC1>" -) diff --git a/power_grid_model_c/power_grid_model_c/CMakeLists.txt b/power_grid_model_c/power_grid_model_c/CMakeLists.txt index cef497aafe..e74c5d5b58 100644 --- a/power_grid_model_c/power_grid_model_c/CMakeLists.txt +++ b/power_grid_model_c/power_grid_model_c/CMakeLists.txt @@ -52,28 +52,27 @@ set_target_properties( # Always-on hardening target_compile_definitions( power_grid_model_c - PUBLIC + PRIVATE "$<$,$>:_FORTIFY_SOURCE=2>" + "$<$:_ITERATOR_DEBUG_LEVEL=$,2,1>>" ) target_compile_options( power_grid_model_c BEFORE - PUBLIC + PRIVATE "$<$,$>:-fstack-protector;-fsanitize=undefined>" "$<$:-static-libubsan>" "$<$:-lubsan>" "$<$,$,$>>>:-fsanitize-minimal-runtime>" - "$<$:/RTC1>" ) target_link_options( power_grid_model_c BEFORE - PUBLIC + PRIVATE "$<$,$>:-fstack-protector;-fsanitize=undefined>" "$<$:-static-libubsan>" "$<$:-lubsan>" "$<$,$>>:-fsanitize-minimal-runtime>" - "$<$:/RTC1>" ) install( From 0a6a25eaf00ce1bac918dd64ff3f8607d22c51b7 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Thu, 18 Dec 2025 15:54:56 +0100 Subject: [PATCH 5/6] revert Signed-off-by: Martijn Govers --- power_grid_model_c/power_grid_model/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/power_grid_model_c/power_grid_model/CMakeLists.txt b/power_grid_model_c/power_grid_model/CMakeLists.txt index ff1c4f3eb7..53519648f9 100644 --- a/power_grid_model_c/power_grid_model/CMakeLists.txt +++ b/power_grid_model_c/power_grid_model/CMakeLists.txt @@ -24,3 +24,11 @@ target_include_directories( # only use MPL version of eigen target_compile_definitions(power_grid_model INTERFACE "EIGEN_MPL2_ONLY=1") + +target_compile_options( + power_grid_model + BEFORE + INTERFACE + "$<$:-Wno-unknown-attributes>" + "$<$:/bigobj /RTC1>" +) From d95c9d33716d367cd938ac9ac724b564b5a28ad9 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Thu, 18 Dec 2025 15:55:33 +0100 Subject: [PATCH 6/6] remove rtc1 Signed-off-by: Martijn Govers --- power_grid_model_c/power_grid_model/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/CMakeLists.txt b/power_grid_model_c/power_grid_model/CMakeLists.txt index 53519648f9..6584a571fa 100644 --- a/power_grid_model_c/power_grid_model/CMakeLists.txt +++ b/power_grid_model_c/power_grid_model/CMakeLists.txt @@ -30,5 +30,5 @@ target_compile_options( BEFORE INTERFACE "$<$:-Wno-unknown-attributes>" - "$<$:/bigobj /RTC1>" + "$<$:/bigobj>" )