fix(core): avoid race condition when collecting qstrs
What changed, and why it matters
This commit fixes a build-time race condition in the script that generates a list of internal string identifiers (called 'qstrs') used by the Trezor firmware. Previously, the generator could read a generated translation file while it was being updated, potentially producing an inconsistent list. The fix makes the generator read translation string names directly from the source translation file instead of from a generated file, and also excludes generated files from the grep search. This is a build-system reliability fix, not a runtime security vulnerability in the device itself.
Treat as a build hygiene fix. Verify that the generated `librust_qstr.h` remains deterministic and complete after clean and incremental builds, especially when translations are modified. No device runtime security response is indicated by this diff alone.
Security signals we found
Race condition in code generation/build process
Generated file dependency in build script
Build reproducibility/determinism concern
No runtime cryptographic or memory-safety signal present in diff
Evidence from the diff
The change is in core/embed/rust/librust_qstr.h.mako, a Mako template that generates librust_qstr.h. The old code grepped Rust source files for MP_QSTR_* patterns, including generated files under src/. This created a race condition: when translations were updated, translated_string.rs.mako could regenerate translated_string.rs concurrently with this template, and the grep could see an older or partially-written version. The fix (1) adds --exclude-dir=generated to the grep so it no longer scans generated files, and (2) introduces find_qstrs_from_translations() which reads core/translations/en.json directly to collect translation IDs and synthesizes the corresponding MP_QSTR_* names. The generated header is updated to remove MP_QSTR_; because the underscore-only identifier is no longer produced. This is a build determinism/race fix, not a memory-safety or cryptographic bug.
Changed components
core/embed/rust/librust_qstr.h.makocore/embed/rust/librust_qstr.hBuild-time qstr generation for MicroPython/Rust interopInspect captured patch +16 / −8
### core/embed/rust/librust_qstr.h
@@ -15,7 +15,6 @@ static void _librust_qstrs(void) {
MP_QSTR_7;
MP_QSTR_8;
MP_QSTR_9;
- MP_QSTR_;
MP_QSTR_ACK;
MP_QSTR_ALERT;
MP_QSTR_APP_HEADER_LEN;
### core/embed/rust/librust_qstr.h.mako
@@ -6,21 +6,30 @@
static void _librust_qstrs(void) {
<%
+import json
import subprocess
import sys
from pathlib import Path
from typing import Union, Set
RUST_SRC = THIS_FILE.parent / "src"
-def find_unique_patterns_in_dir(directory: Union[str, Path], pattern: str) -> Set[str]:
- command = f"grep -ro '{pattern}' {directory}"
- result = subprocess.run(command, stdout=subprocess.PIPE, text=True, shell=True)
- output_lines = result.stdout.strip().split("\n")
- return set([line.split(":", 1)[1] for line in output_lines if line])
+def find_qstrs_in_dir() -> set[str]:
+ pattern = r"\bMP_QSTR_\w*"
+ # Avoid processing generated files here, to avoid the following race condition:
+ # * If translations are updated, `translated_string.rs` is updated via `translated_string.rs.mako`.
+ # * This template may be processed concurrently, and use an older version of `translated_string.rs`.
+ # (see https://github.com/trezor/trezor-firmware/issues/7338)
+ args = ["grep", "-ro", "--exclude-dir=generated", pattern, RUST_SRC]
+ output_lines = subprocess.check_output(args, text=True).strip().split("\n")
+ return {line.split(":", 1)[1] for line in output_lines if line}
-pattern = r"\bMP_QSTR_\w*"
-qstrings = find_unique_patterns_in_dir(RUST_SRC, pattern)
+def find_qstrs_from_translations() -> set[str]:
+ # Add qstrs for translation IDs (see `translated_string.rs.mako`)
+ en_data = json.loads((ROOT / "core" / "translations" / "en.json").read_text())
+ return {f"MP_QSTR_{name}" for name in en_data["translations"]}
+
+qstrings = find_qstrs_in_dir() | find_qstrs_from_translations()
qstrings_universal = set()
for prefix in ALTCOIN_PREFIXES:Why this scored 21/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.