Resolve N2: bound align annotations at 4096 (review #006)
align: 2^62 compiled and reported total_size = 2^63 — meaningless layout output the consumer may act on, and the reachable path to the MAX_ARRAY_BYTES cap used exactly this knob. - MAX_ALIGN = 4096 (page granularity) in schema.rs, documented with the probe arithmetic - parse_align returns Result and rejects over-cap values with a clean Schema error naming path/value/maximum — a silent clamp was rejected (it would change layout semantics without telling the consumer); both call sites thread the path, so standalone BastDoc::new (which never runs the meta-schema) is covered - Meta-schema: "maximum": 4096 on StructDef.align and FieldDef.align — the published alk.dev/bast/v1/schema contract now matches the parser - H1's byte-cap test retuned to align 4096 x count 2^16 = 2^28 > 2^26 (the byte cap stays reachable under the new align cap) Tests: 3 new (struct align above cap, field align above cap, align at cap accepted). 511 tests green, clippy -D warnings clean, wasm32 build green, cargo doc zero warnings.
This commit is contained in:
1 parent
8739d29550
commit
0bc5a541ac
5 files changed
+139
-21
No files matched your search
+29
-8
@@ -36,7 +36,7 @@
|
||||
|
||||
use crate::error::AlkTypeError;
|
||||
use crate::schema::{
|
||||
AlkTypeKind, Endian, VariableEncoding, MAX_ARRAY_ELEMENTS,
|
||||
AlkTypeKind, Endian, VariableEncoding, MAX_ALIGN, MAX_ARRAY_ELEMENTS,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -308,7 +308,7 @@ impl BastStruct {
|
||||
|
||||
fn parse(node: &Value, path: &str, doc_root: &Value) -> Result<Self, AlkTypeError> {
|
||||
let endian = parse_endian_opt(node).unwrap_or(Endian::Little);
|
||||
let align = parse_align(node);
|
||||
let align = parse_align(node, path)?;
|
||||
let raw_fields = node
|
||||
.get("fields")
|
||||
.and_then(Value::as_array)
|
||||
@@ -427,7 +427,7 @@ impl BastField {
|
||||
})?;
|
||||
let ty = BastType::parse(raw_kind, path, doc_root)?;
|
||||
let endian = parse_endian_opt(node);
|
||||
let align = parse_align(node);
|
||||
let align = parse_align(node, path)?;
|
||||
let encoding = parse_encoding(node);
|
||||
let max_length = parse_max_length(node);
|
||||
Ok(Self {
|
||||
@@ -993,11 +993,32 @@ fn parse_endian_opt(node: &Value) -> Option<Endian> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_align(node: &Value) -> Option<usize> {
|
||||
node.as_object()
|
||||
.and_then(|o| o.get("align"))
|
||||
.and_then(Value::as_u64)
|
||||
.and_then(|n| usize::try_from(n).ok())
|
||||
/// Parse a struct- or field-level `align` annotation. Over-sized values
|
||||
/// are a clean `Schema` error (review #006 N2: an unbounded align let a
|
||||
/// one-field schema declare an exabyte-scale layout — `align_up` rounds
|
||||
/// the running offset by the full annotation).
|
||||
fn parse_align(node: &Value, path: &str) -> Result<Option<usize>, AlkTypeError> {
|
||||
let raw = match node.as_object().and_then(|o| o.get("align")) {
|
||||
None | Some(Value::Null) => return Ok(None),
|
||||
Some(v) => v,
|
||||
};
|
||||
let n = raw.as_u64().ok_or_else(|| {
|
||||
AlkTypeError::Schema(format!(
|
||||
"bast: align at {path} is not a non-negative integer"
|
||||
))
|
||||
})?;
|
||||
let n = usize::try_from(n).map_err(|_| {
|
||||
AlkTypeError::Schema(format!(
|
||||
"bast: align at {path} (= {n}) overflows usize"
|
||||
))
|
||||
})?;
|
||||
if n > MAX_ALIGN {
|
||||
return Err(AlkTypeError::Schema(format!(
|
||||
"bast: align at {path} (= {n}) exceeds the maximum of {MAX_ALIGN} \
|
||||
(review #006 N2: honest layouts never need more than page granularity)"
|
||||
)));
|
||||
}
|
||||
Ok(Some(n))
|
||||
}
|
||||
|
||||
fn parse_max_length(node: &Value) -> Option<usize> {
|
||||
|
||||
Reference in new issue
Block a user