Skip to content

Commit f391a5f

Browse files
anakrishCopilot
andcommitted
Freeze objects at value boundaries
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1a89279 commit f391a5f

8 files changed

Lines changed: 47 additions & 27 deletions

File tree

src/builtins/azure_policy/template_functions_collection.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::builtins;
1010
use crate::lexer::Span;
1111
use crate::value::Object;
1212
use crate::value::Value;
13-
use crate::Rc;
1413

1514
use alloc::vec::Vec;
1615
use anyhow::Result;
@@ -79,7 +78,7 @@ fn fn_intersection(
7978
};
8079
result.retain(|k, v| other.get(k).is_some_and(|ov| *ov == *v));
8180
}
82-
Ok(Value::Object(Rc::new(result)))
81+
Ok(result.into_value())
8382
}
8483
_ => Ok(Value::Undefined),
8584
}
@@ -130,7 +129,7 @@ fn fn_union(_span: &Span, _params: &[Ref<Expr>], args: &[Value], _strict: bool)
130129
result.insert(k.clone(), merged);
131130
}
132131
}
133-
Ok(Value::Object(Rc::new(result)))
132+
Ok(result.into_value())
134133
}
135134
_ => Ok(Value::Undefined),
136135
}
@@ -273,7 +272,7 @@ fn fn_create_object(
273272
}
274273
}
275274

276-
Ok(Value::Object(Rc::new(map)))
275+
Ok(map.into_value())
277276
}
278277

279278
// ── Helpers ───────────────────────────────────────────────────────────
@@ -290,7 +289,7 @@ fn merge_objects(base: &Object, overlay: &Object) -> Value {
290289
};
291290
result.insert(k.clone(), merged);
292291
}
293-
Value::Object(Rc::new(result))
292+
result.into_value()
294293
}
295294

296295
fn extract_usize(v: &Value) -> Option<usize> {

src/builtins/azure_policy/template_functions_misc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn fn_items(_span: &Span, _params: &[Ref<Expr>], args: &[Value], _strict: bool)
8888
let mut entry = Object::new();
8989
entry.insert(Value::from("key"), k.clone());
9090
entry.insert(Value::from("value"), v.clone());
91-
result.push(Value::Object(Rc::new(entry)));
91+
result.push(entry.into_value());
9292
}
9393
Ok(Value::Array(Rc::new(result)))
9494
}

src/builtins/objects.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ fn filter(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> R
284284
_ => bail!(span.error(format!("`{name}` requires array/object/set argument").as_str())),
285285
};
286286

287-
Ok(Value::Object(obj))
287+
let mut value = Value::Object(obj);
288+
value.freeze_recursive();
289+
Ok(value)
288290
}
289291

290292
fn get(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
@@ -334,7 +336,9 @@ fn remove(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> R
334336
_ => bail!(span.error(format!("`{name}` requires array/object/set argument").as_str())),
335337
};
336338

337-
Ok(Value::Object(obj))
339+
let mut value = Value::Object(obj);
340+
value.freeze_recursive();
341+
Ok(value)
338342
}
339343

340344
fn is_subset(sup: &Value, sub: &Value) -> bool {
@@ -391,7 +395,9 @@ fn object_union(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool
391395
let _ = ensure_object(name, &params[0], args[0].clone())?;
392396
let _ = ensure_object(name, &params[1], args[1].clone())?;
393397

394-
union(&args[0], &args[1])
398+
let mut result = union(&args[0], &args[1])?;
399+
result.freeze_recursive();
400+
Ok(result)
395401
}
396402

397403
fn object_union_n(
@@ -418,6 +424,7 @@ fn object_union_n(
418424
u = union(&u, a)?;
419425
}
420426

427+
u.freeze_recursive();
421428
Ok(u)
422429
}
423430

src/engine.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,8 @@ impl Engine {
397397
/// # Ok(())
398398
/// # }
399399
/// ```
400-
pub fn set_input(&mut self, input: Value) {
400+
pub fn set_input(&mut self, mut input: Value) {
401+
input.freeze_recursive();
401402
self.interpreter.set_input(input);
402403
}
403404

@@ -465,7 +466,9 @@ impl Engine {
465466
bail!("data must be object");
466467
}
467468
self.prepared = false;
468-
self.interpreter.get_init_data_mut().merge(data)
469+
self.interpreter.get_init_data_mut().merge(data)?;
470+
self.interpreter.get_init_data_mut().freeze_recursive();
471+
Ok(())
469472
}
470473

471474
/// Get the data document.

src/interpreter.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,7 +2343,10 @@ impl Interpreter {
23432343
self.eval_query(query)?;
23442344

23452345
match self.contexts.pop() {
2346-
Some(ctx) => Ok(ctx.value),
2346+
Some(mut ctx) => {
2347+
ctx.value.freeze_recursive();
2348+
Ok(ctx.value)
2349+
}
23472350
None => bail!("internal error: context already popped"),
23482351
}
23492352
}
@@ -3337,7 +3340,11 @@ impl Interpreter {
33373340

33383341
Ok(match result {
33393342
true => match &popped_ctx.value {
3340-
Value::Object(_) => popped_ctx.value,
3343+
Value::Object(_) => {
3344+
let mut value = popped_ctx.value;
3345+
value.freeze_recursive();
3346+
value
3347+
}
33413348
Value::Array(a) if a.len() == 1 => a
33423349
.first()
33433350
.cloned()

src/rvm/program/serialization/value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ impl<'de> Visitor<'de> for BinaryValueVisitor {
266266
for (key, value) in entries {
267267
map.insert(key.into_value(), value.into_value());
268268
}
269-
Ok(BinaryValue(Value::Object(crate::Rc::new(map))))
269+
Ok(BinaryValue(map.into_value()))
270270
}
271271
(BinaryVariant::Undefined, variant) => {
272272
variant.unit_variant()?;

src/rvm/vm/comprehension.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
use crate::rvm::instructions::{ComprehensionBeginParams, ComprehensionMode};
55
use crate::value::Object;
66
use crate::value::Value;
7-
use crate::Rc;
87
use alloc::format;
98
use alloc::sync::Arc;
109
use alloc::vec::Vec;
@@ -34,7 +33,7 @@ impl RegoVM {
3433
let initial_result = match params.mode {
3534
ComprehensionMode::Set => Value::new_set(),
3635
ComprehensionMode::Array => Value::new_array(),
37-
ComprehensionMode::Object => Value::Object(Rc::new(Object::new())),
36+
ComprehensionMode::Object => Object::new().into_value(),
3837
};
3938
self.set_register(params.result_reg, initial_result.clone())?;
4039

@@ -121,7 +120,7 @@ impl RegoVM {
121120
let initial_result = match params.mode {
122121
ComprehensionMode::Set => Value::new_set(),
123122
ComprehensionMode::Array => Value::new_array(),
124-
ComprehensionMode::Object => Value::Object(Rc::new(Object::new())),
123+
ComprehensionMode::Object => Object::new().into_value(),
125124
};
126125
self.set_register(params.result_reg, initial_result.clone())?;
127126

@@ -589,15 +588,17 @@ impl RegoVM {
589588
// `ComprehensionEnd` is reached from a loaded program; an empty stack
590589
// here means malformed user-supplied bytecode, which must still surface
591590
// as a typed error rather than a panic — including in debug builds.
592-
self.comprehension_stack.pop().map_or_else(
593-
|| {
594-
Err(VmError::InvalidIteration {
595-
value: Value::String(Arc::from("No active comprehension context")),
596-
pc: self.pc,
597-
})
598-
},
599-
|_context| Ok(()),
600-
)
591+
let context = self
592+
.comprehension_stack
593+
.pop()
594+
.ok_or_else(|| VmError::InvalidIteration {
595+
value: Value::String(Arc::from("No active comprehension context")),
596+
pc: self.pc,
597+
})?;
598+
let mut value = self.take_register(context.result_reg)?;
599+
value.freeze_recursive();
600+
self.set_register(context.result_reg, value)?;
601+
Ok(())
601602
}
602603

603604
fn execute_comprehension_end_suspendable(&mut self) -> Result<()> {
@@ -628,6 +629,9 @@ impl RegoVM {
628629
return_pc: _,
629630
context,
630631
} => {
632+
let mut value = self.take_register(context.result_reg)?;
633+
value.freeze_recursive();
634+
self.set_register(context.result_reg, value)?;
631635
let raw_target = context.resume_pc;
632636
let resume_pc = if raw_target <= self.pc {
633637
self.pc.saturating_add(1)

src/value/object/serde.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'de> Visitor<'de> for ObjectVisitor {
4848
crate::utils::limits::check_memory_limit_if_needed()
4949
.map_err(|err| A::Error::custom(err.to_string()))?;
5050
}
51-
Ok(obj)
51+
Ok(obj.freeze())
5252
}
5353
}
5454

0 commit comments

Comments
 (0)