chore(core): add conversion.h for float bit-equivalent conversions
What changed, and why it matters
This commit is a routine code cleanup. It introduces a small helper file that provides a standard, safe way to convert between float numbers and their raw 32-bit representations. It then replaces a few existing hand-written conversions in the battery telemetry code with these helpers. There is no functional change and no security issue.
No action required. This is a benign refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change adds core/embed/rtl/inc/rtl/conversion.h, which defines two static inline functions, float_to_u32() and u32_to_float(), using memcpy for bit-equivalent type punning. This avoids undefined behavior from union-based type punning and strict-aliasing violations. The commit updates smcall_dispatch.c and smcall_stubs.c to use these helpers instead of local union conversions. The behavior is identical; the patch is purely refactoring.
Changed components
core/embed/rtl/inc/rtl/conversion.hcore/embed/rtl/inc/trezor_types.hcore/embed/sys/smcall/stm32/smcall_dispatch.ccore/embed/sys/smcall/stm32/smcall_stubs.cInspect captured patch +61 / −26
diff --git a/core/embed/rtl/inc/rtl/conversion.h b/core/embed/rtl/inc/rtl/conversion.h
new file mode 100644
index 000000000..a582901dc
--- /dev/null
+++ b/core/embed/rtl/inc/rtl/conversion.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h>
+
+/**
+ * @brief Converts a float to a uint32_t using safe type-punning.
+ *
+ * This function uses memcpy to avoid violating strict-aliasing rules.
+ * Modern compilers optimize this into a single register move.
+ *
+ * @param f The float value to convert.
+ * @return The bit-equivalent uint32_t value.
+ */
+static inline uint32_t float_to_u32(float f) {
+ uint32_t u;
+ memcpy(&u, &f, sizeof(u));
+ return u;
+}
+
+/**
+ * @brief Converts a uint32_t to a float using safe type-punning.
+ *
+ * This function uses memcpy to avoid violating strict-aliasing rules.
+ * Modern compilers optimize this into a single register move.
+ *
+ * @param u The uint32_t value to convert.
+ * @return The bit-equivalent float value.
+ */
+static inline float u32_to_float(uint32_t u) {
+ float f;
+ memcpy(&f, &u, sizeof(f));
+ return f;
+}
diff --git a/core/embed/rtl/inc/trezor_types.h b/core/embed/rtl/inc/trezor_types.h
index 6ba42ec5b..09087f366 100644
--- a/core/embed/rtl/inc/trezor_types.h
+++ b/core/embed/rtl/inc/trezor_types.h
@@ -31,5 +31,6 @@
#include <stdint.h>
#include <sys/types.h>
+#include "rtl/conversion.h"
#include "rtl/error_handling.h"
#include "rtl/secbool.h"
diff --git a/core/embed/sys/smcall/stm32/smcall_dispatch.c b/core/embed/sys/smcall/stm32/smcall_dispatch.c
index 21b1d7607..97e5042e5 100644
--- a/core/embed/sys/smcall/stm32/smcall_dispatch.c
+++ b/core/embed/sys/smcall/stm32/smcall_dispatch.c
@@ -407,13 +407,7 @@ __attribute((no_stack_protector)) void smcall_handler(uint32_t *args,
// ------------------------------------------------------------------
// Telemetry
case SMCALL_TELEMETRY_UPDATE_BATT_TEMP: {
- union {
- float f;
- uint32_t u;
- } u32_to_float = {.u = args[0]};
-
- float temp = u32_to_float.f;
- telemetry_update_battery_temp(temp);
+ telemetry_update_battery_temp(u32_to_float(args[0]));
} break;
case SMCALL_TELEMETRY_UPDATE_BATT_ERRORS: {
@@ -422,13 +416,7 @@ __attribute((no_stack_protector)) void smcall_handler(uint32_t *args,
} break;
case SMCALL_TELEMETRY_UPDATE_BATT_CYCLES: {
- union {
- float f;
- uint32_t u;
- } u32_to_float = {.u = args[0]};
-
- float battery_cycles_inc = u32_to_float.f;
- telemetry_update_battery_cycles(battery_cycles_inc);
+ telemetry_update_battery_cycles(u32_to_float(args[0]));
} break;
case SMCALL_TELEMETRY_GET: {
diff --git a/core/embed/sys/smcall/stm32/smcall_stubs.c b/core/embed/sys/smcall/stm32/smcall_stubs.c
index 562f8f6c1..96da37855 100644
--- a/core/embed/sys/smcall/stm32/smcall_stubs.c
+++ b/core/embed/sys/smcall/stm32/smcall_stubs.c
@@ -19,6 +19,8 @@
#if defined(KERNEL) && defined(USE_SECMON_LAYOUT)
+#include <trezor_rtl.h>
+
#include "smcall_invoke.h"
#include "smcall_numbers.h"
@@ -416,12 +418,7 @@ secbool secret_validate_nrf_pairing(const uint8_t *message, size_t msg_len,
#include <sec/telemetry.h>
void telemetry_update_battery_temp(float temp_c) {
- union {
- float f;
- uint32_t u;
- } float_to_u32 = {.f = temp_c};
-
- smcall_invoke1(float_to_u32.u, SMCALL_TELEMETRY_UPDATE_BATT_TEMP);
+ smcall_invoke1(float_to_u32(temp_c), SMCALL_TELEMETRY_UPDATE_BATT_TEMP);
}
void telemetry_update_battery_errors(telemetry_batt_errors_t errors) {
@@ -429,12 +426,8 @@ void telemetry_update_battery_errors(telemetry_batt_errors_t errors) {
}
void telemetry_update_battery_cycles(float battery_cycles_inc) {
- union {
- float f;
- uint32_t u;
- } float_to_u32 = {.f = battery_cycles_inc};
-
- smcall_invoke1(float_to_u32.u, SMCALL_TELEMETRY_UPDATE_BATT_CYCLES);
+ smcall_invoke1(float_to_u32(battery_cycles_inc),
+ SMCALL_TELEMETRY_UPDATE_BATT_CYCLES);
}
bool telemetry_get(telemetry_data_t *out) {
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.