From 12e3c37d6a618866afbb03b029800329be3baad8 Mon Sep 17 00:00:00 2001 From: JafarAbdi Date: Mon, 25 Nov 2024 13:51:43 +0000 Subject: [PATCH 1/3] Fix ReinterpretAsInt causing undefind behavior + segfaulting on release mode --- mjpc/utilities.cc | 12 ++++++++---- mjpc/utilities.h | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/mjpc/utilities.cc b/mjpc/utilities.cc index 5c87cbf62..247c0748e 100644 --- a/mjpc/utilities.cc +++ b/mjpc/utilities.cc @@ -115,12 +115,16 @@ void Clamp(double* x, const double* bounds, int n) { } } -int ReinterpretAsInt(double value) { - return *std::launder(reinterpret_cast(&value)); +int64_t ReinterpretAsInt(double value) { + static_assert(sizeof(double) == sizeof(int64_t), + "double and int64_t must have same size"); + return std::bit_cast(value); } double ReinterpretAsDouble(int64_t value) { - return *std::launder(reinterpret_cast(&value)); + static_assert(sizeof(double) == sizeof(int64_t), + "double and int64_t must have same size"); + return std::bit_cast(value); } absl::flat_hash_map> @@ -225,7 +229,7 @@ int ParameterIndex(const mjModel* model, std::string_view name) { double DefaultResidualSelection(const mjModel* m, int numeric_index) { // list selections are stored as ints, but numeric values are doubles. int64_t value = m->numeric_data[m->numeric_adr[numeric_index]]; - return *std::launder(reinterpret_cast(&value)); + return ReinterpretAsDouble(value); } int CostTermByName(const mjModel* m, const std::string& name) { diff --git a/mjpc/utilities.h b/mjpc/utilities.h index f3eb5c8a0..f5c88cd54 100644 --- a/mjpc/utilities.h +++ b/mjpc/utilities.h @@ -66,8 +66,8 @@ T GetNumberOrDefault(T default_value, const mjModel* m, std::string_view name) { return GetNumber(m, name).value_or(default_value); } -// reinterpret double as int -int ReinterpretAsInt(double value); +// reinterpret double as int64_t +int64_t ReinterpretAsInt(double value); // reinterpret int64_t as double double ReinterpretAsDouble(int64_t value); From 5385f368107b7a7ddba6f283d3f85cd54eeb2fa3 Mon Sep 17 00:00:00 2001 From: JafarAbdi Date: Mon, 25 Nov 2024 14:45:13 +0000 Subject: [PATCH 2/3] Include bit header file --- mjpc/utilities.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/mjpc/utilities.cc b/mjpc/utilities.cc index 247c0748e..0d9cbe1b0 100644 --- a/mjpc/utilities.cc +++ b/mjpc/utilities.cc @@ -15,6 +15,7 @@ #include "mjpc/utilities.h" #include +#include #include #include #include From d8a7ff776db351cef453520fdf63355634b8ffb2 Mon Sep 17 00:00:00 2001 From: JafarAbdi Date: Mon, 25 Nov 2024 19:45:25 +0000 Subject: [PATCH 3/3] Make all compilers happy --- mjpc/utilities.cc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/mjpc/utilities.cc b/mjpc/utilities.cc index 0d9cbe1b0..6f67c27e5 100644 --- a/mjpc/utilities.cc +++ b/mjpc/utilities.cc @@ -118,14 +118,26 @@ void Clamp(double* x, const double* bounds, int n) { int64_t ReinterpretAsInt(double value) { static_assert(sizeof(double) == sizeof(int64_t), - "double and int64_t must have same size"); + "double and int64_t must have same size"); +#if defined(__cpp_lib_bit_cast) return std::bit_cast(value); +#else + int64_t dst; + std::memcpy(&dst, &value, sizeof(int64_t)); + return dst; +#endif } double ReinterpretAsDouble(int64_t value) { static_assert(sizeof(double) == sizeof(int64_t), - "double and int64_t must have same size"); + "double and int64_t must have same size"); +#if defined(__cpp_lib_bit_cast) return std::bit_cast(value); +#else + double dst; + std::memcpy(&dst, &value, sizeof(double)); + return dst; +#endif } absl::flat_hash_map>