Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
- Added `Package::content_digest()` to identify package contents without changing the MAST digest, including manifest data and semantic package metadata ([#2909](https://github.com/0xMiden/miden-vm/pull/2909)).
- Hardened MAST forest and package byte-slice deserialization against fuzzed length fields ([#3088](https://github.com/0xMiden/miden-vm/pull/3088)).
- [BREAKING] Bounded the live advice map by total field elements during execution; advice-provider setup now returns an error when initial advice exceeds this limit ([#3085](https://github.com/0xMiden/miden-vm/pull/3085)).
- Rejected empty kernel packages before linking so malformed dependency metadata returns a structured package error instead of reaching the linker's non-empty-kernel assertion ([#3082](https://github.com/0xMiden/miden-vm/pull/3082)).

#### Changes

Expand Down
37 changes: 37 additions & 0 deletions crates/assembly/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5187,6 +5187,43 @@ fn regression_empty_kernel_library_is_rejected() {
assert_diagnostic_lines!(err, "library must contain at least one exported procedure");
}

#[test]
fn regression_empty_kernel_package_is_rejected_without_panicking() {
use std::panic::{AssertUnwindSafe, catch_unwind};

let context = TestContext::default();
let source_manager = context.source_manager();
let kernel_lib = Assembler::new(source_manager.clone())
.assemble_kernel(
r#"
pub proc foo
add
end
"#,
)
.expect("kernel assembly should succeed");
let mut package = *Package::from_library(
PackageId::from("kernel"),
"1.0.0".parse().unwrap(),
TargetType::Kernel,
Arc::new(kernel_lib.as_ref().clone()),
[],
);
package.manifest = PackageManifest::new([]).expect("empty package manifest should be valid");

let linked = catch_unwind(AssertUnwindSafe(|| {
Assembler::new(source_manager)
.link_package(Arc::new(package), miden_project::Linkage::Dynamic)
}));
assert!(linked.is_ok(), "assembler panicked while linking an empty kernel package");

let error = linked.unwrap().expect_err("empty kernel packages should be rejected");
assert_diagnostic_lines!(
error,
"invalid kernel package: does not export any kernel procedures"
);
}

/// Reproduces issue #3035: a MAST with padded basic blocks grows when debug info is cleared and the
/// forest is compacted via self-merge.
#[test]
Expand Down
22 changes: 22 additions & 0 deletions crates/mast-package/src/package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ impl Package {
}
})
.collect::<Vec<_>>();
if exports.is_empty() {
return Err(Report::msg(
"invalid kernel package: does not export any kernel procedures",
));
}
Kernel::new(&exports).map_err(|err| Report::msg(format!("invalid kernel package: {err}")))
}

Expand Down Expand Up @@ -573,6 +578,23 @@ mod tests {
build_package(name, TargetType::Kernel, &format!("{name}::boot"), [], Vec::new())
}

#[test]
fn to_kernel_rejects_empty_kernel_exports() {
let mut package = build_package("kernel", TargetType::Kernel, "$kernel::boot", [], vec![]);
package.manifest =
PackageManifest::new([]).expect("empty package manifest should be valid");

let error = package
.to_kernel()
.expect_err("kernel packages without exported procedures should be rejected");

assert!(
error
.to_string()
.contains("invalid kernel package: does not export any kernel procedures")
);
}

fn kernel_dependency(package: &Package) -> Dependency {
Dependency {
name: package.name.clone(),
Expand Down
Loading