Skip to content

Commit 7e4e350

Browse files
committed
Fixing embedding script
1 parent 1c594f1 commit 7e4e350

8 files changed

Lines changed: 78 additions & 13 deletions

File tree

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"fsanitize",
2525
"ifndef",
2626
"invertibility",
27+
"iwyu",
2728
"kirienko",
2829
"libudpard",
2930
"llms",

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ Behaviour worth knowing:
430430
- The image is built if it is missing, so `build` is only needed to pick up a dependency change.
431431
- `serve` mounts read-only and live-reloads on edit, exactly like a host `mkdocs serve`; the same
432432
`/llvm-dsdl/` base path applies.
433-
- `check` needs a writable mount because it renders into `site/`, and runs the container as your own
433+
- `check` needs a writeable mount because it renders into `site/`, and runs the container as your own
434434
UID/GID so the output is not left root-owned.
435435
- Overrides: `LLVMDSDL_DOCS_PORT` (default 8000), `LLVMDSDL_DOCS_IMAGE`, and `DOCKER` (set it to
436436
`podman` if that is what you run).

include/llvmdsdl/CodeGen/UavcanEmbeddedCatalog.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ struct UavcanEmbeddedCatalog final
6666
/// @return True when the embedded MLIR text matches its recorded SHA-256.
6767
[[nodiscard]] bool embeddedUavcanCatalogIntegrityOk();
6868

69+
/// @brief Returns the SHA-256 recorded next to the catalog blob, as lowercase hex.
70+
[[nodiscard]] llvm::StringRef embeddedUavcanCatalogRecordedSha256();
71+
72+
/// @brief Hashes the catalog blob compiled into this binary, as lowercase hex.
73+
///
74+
/// Computed from the text rather than read from the recorded constant, so a failing integrity check
75+
/// can name both halves of the mismatch.
76+
[[nodiscard]] std::string embeddedUavcanCatalogComputedSha256();
77+
78+
/// @brief Repository-relative path of the generated file carrying the catalog text and its hash.
79+
///
80+
/// Named in the integrity-failure diagnostic: both values live in this one generated file, so a
81+
/// mismatch is always a defect in it rather than in the two sources disagreeing.
82+
inline constexpr const char* kEmbeddedUavcanCatalogSourceFile = "lib/CodeGen/UavcanEmbeddedMlir.inc";
83+
6984
/// @brief Loads and parses embedded UAVCAN catalog artifacts.
7085
///
7186
/// Fails (without parsing) when the embedded MLIR blob does not match its recorded SHA-256.

lib/CodeGen/UavcanEmbeddedCatalog.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -677,15 +677,42 @@ bool embeddedUavcanCatalogIntegrityOk()
677677
uavcan_embedded_mlir::kEmbeddedUavcanMlirSha256);
678678
}
679679

680+
llvm::StringRef embeddedUavcanCatalogRecordedSha256()
681+
{
682+
return uavcan_embedded_mlir::kEmbeddedUavcanMlirSha256;
683+
}
684+
685+
std::string embeddedUavcanCatalogComputedSha256()
686+
{
687+
const llvm::StringRef text = uavcan_embedded_mlir::kEmbeddedUavcanMlirText;
688+
const std::array<uint8_t, 32> digest =
689+
llvm::SHA256::hash(llvm::ArrayRef<uint8_t>(reinterpret_cast<const uint8_t*>(text.data()), text.size()));
690+
return llvm::toHex(digest, /*LowerCase=*/true);
691+
}
692+
680693
llvm::Expected<UavcanEmbeddedCatalog> loadUavcanEmbeddedCatalog(mlir::MLIRContext& context,
681694
DiagnosticEngine& diagnostics)
682695
{
683696
// Integrity gate: refuse to parse a blob that does not match its recorded SHA-256 (corruption,
684697
// tampering, or a text/hash mismatch introduced during the build).
685698
if (!embeddedUavcanCatalogIntegrityOk())
686699
{
687-
diagnostics.error({"<embedded-uavcan>", 1, 1},
688-
"embedded UAVCAN catalog failed SHA-256 integrity verification");
700+
const SourceLocation here{"<embedded-uavcan>", 1, 1};
701+
diagnostics.error(here, "embedded UAVCAN catalog failed SHA-256 integrity verification");
702+
diagnostics.note(here,
703+
"recorded " + embeddedUavcanCatalogRecordedSha256().str() + ", computed " +
704+
embeddedUavcanCatalogComputedSha256());
705+
diagnostics.note(here,
706+
std::string("both values are generated into ") + kEmbeddedUavcanCatalogSourceFile +
707+
", so they disagree only when that file was hand-edited, partially regenerated, "
708+
"or merged badly");
709+
diagnostics.note(here,
710+
std::string("restore it with 'git checkout -- ") + kEmbeddedUavcanCatalogSourceFile +
711+
"', or regenerate it with 'python3 tools/dsdlc/generate_embedded_uavcan_mlir.py "
712+
"--dsdlc <path-to-dsdlc>', then rebuild");
713+
diagnostics.note(here,
714+
"to build without the compiled-in catalog, pass --no-embedded-uavcan and add "
715+
"--lookup-dir <checkout>/public_regulated_data_types/uavcan");
689716
return llvm::createStringError(llvm::inconvertibleErrorCode(),
690717
"embedded UAVCAN catalog failed SHA-256 integrity verification");
691718
}

lib/CodeGen/UavcanEmbeddedMlir.inc

Lines changed: 7 additions & 7 deletions
Large diffs are not rendered by default.

test/unit/UavcanEmbeddedCatalogTests.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ bool runUavcanEmbeddedCatalogTests()
6666
std::cerr << "verifyEmbeddedCatalogIntegrity accepted a mismatched hash\n";
6767
return false;
6868
}
69+
// (4) The two accessors the integrity-failure diagnostic quotes must agree on a healthy binary,
70+
// and must be the same pair the check itself compares.
71+
if (llvmdsdl::embeddedUavcanCatalogComputedSha256() != llvmdsdl::embeddedUavcanCatalogRecordedSha256())
72+
{
73+
std::cerr << "embedded UAVCAN catalog hash accessors disagree: computed "
74+
<< llvmdsdl::embeddedUavcanCatalogComputedSha256() << ", recorded "
75+
<< llvmdsdl::embeddedUavcanCatalogRecordedSha256().str() << "\n";
76+
return false;
77+
}
6978

7079
mlir::DialectRegistry registry;
7180
registry.insert<mlir::dsdl::DSDLDialect,

tools/dsdlc/generate_embedded_uavcan_mlir.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ def _find_default_dsdlc(repo_root: Path) -> str:
7171

7272

7373
def _run_dsdlc(dsdlc: str, uavcan_root: Path) -> str:
74-
command = [dsdlc, "--target-language", "mlir", str(uavcan_root)]
74+
# --no-embedded-uavcan keeps this hermetic: the catalog is derived from uavcan_root alone, never
75+
# from the copy compiled into the dsdlc doing the deriving. It also means a dsdlc whose embedded
76+
# catalog is corrupt -- the one case where regeneration is the fix -- can still run this.
77+
command = [dsdlc, "--target-language", "mlir", "--no-embedded-uavcan", str(uavcan_root)]
7578
process = subprocess.run(command, capture_output=True, text=True, check=False)
7679
if process.returncode != 0:
7780
sys.stderr.write(process.stderr)
@@ -88,7 +91,7 @@ def _run_dsdlc(dsdlc: str, uavcan_root: Path) -> str:
8891

8992

9093
def _render(mlir_text: str) -> str:
91-
schema_count = len(re.findall(r"\\bdsdl\\.schema\\b", mlir_text))
94+
schema_count = len(re.findall(r"\bdsdl\.schema\b", mlir_text))
9295
# The raw-string literal embeds this exact content (a leading newline keeps the generated file
9396
# readable). Hash the same bytes so the runtime SHA-256 check verifies what is actually embedded,
9497
# not a differently-normalized copy.

tools/dsdlc/main.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,17 @@ int main(int argc, char** argv)
14031403
auto loadedCatalog = llvmdsdl::loadUavcanEmbeddedCatalog(context, diagnostics);
14041404
if (!loadedCatalog)
14051405
{
1406-
llvm::errs() << llvm::toString(loadedCatalog.takeError()) << "\n";
1406+
// Every failure path in the loader files a diagnostic first, and that one carries the
1407+
// remediation notes. Printing the Error's text too would only repeat its first line.
1408+
auto loadError = loadedCatalog.takeError();
1409+
if (diagnostics.hasErrors())
1410+
{
1411+
llvm::consumeError(std::move(loadError));
1412+
}
1413+
else
1414+
{
1415+
llvm::errs() << llvm::toString(std::move(loadError)) << "\n";
1416+
}
14071417
printDiagnostics(diagnostics);
14081418
return 1;
14091419
}

0 commit comments

Comments
 (0)