fix(ffi): eliminate aliasing UB + add Azure Policy JSON compilation FFI (#727)

* fix(ffi): eliminate aliasing UB via to_shared_ref migration

Add to_shared_ref() helper that creates &T (shared reference) from raw
pointers instead of &mut T. This eliminates undefined behavior caused by
violating Rust's aliasing invariant when C# SafeHandle permits concurrent
FFI calls on the same handle.

With &mut T, the compiler may assume exclusive (noalias) access and
reorder or elide reads/writes — a miscompilation risk when another thread
holds a reference to the same object. Switching to &T removes that
assumption; actual mutation is mediated by the interior RwLock inside
Handle<T>, which is the sole synchronization mechanism.

Migrated sites:
- rvm.rs: 20 non-drop call sites
- engine.rs: 30 non-drop call sites + with_unwind_guard for timer fns
- compiled_policy.rs: 2 call sites
- Fix null-data UB in regorus_program_deserialize_binary

Drop paths retain to_ref() where exclusive access is guaranteed by the
caller contract (preventing use-after-free).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(ffi): add Azure Policy JSON compilation FFI and C# bindings

- AliasRegistry builder pattern: RegorusAliasRegistryBuilder (mutable,
  single-threaded) + RegorusAliasRegistry (immutable, Arc-wrapped)
- Azure Policy JSON compilation: regorus_compile_azure_policy_rule and
  regorus_compile_azure_policy_definition with alias registry support
- regorus_rvm_set_context for host-supplied ambient data
- C# AliasRegistryBuilder and AliasRegistry classes with convenience
  factories (FromJson, FromManifest, Empty)
- C# AzurePolicyCompiler static class for policy rule/definition compilation
- Compile functions take *const RegorusAliasRegistry (read-only via
  to_shared_ref for concurrent compilation safety)
- Fix pre-existing clippy warnings across multiple crates

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anand Krishnamoorthi
2026-05-22 12:50:16 -05:00
committed by GitHub
parent 5467cd9e69
commit 86b4a279fa
26 changed files with 1986 additions and 315 deletions
@@ -314,7 +314,7 @@ fn order_element_pairs<T: VariableBindingContext>(
if ready {
let (value_expr, plan, _deps, binds) = remaining.remove(idx);
scheduled.extend(binds.into_iter());
scheduled.extend(binds);
ordered.push((value_expr, plan));
progress = true;
break;
@@ -264,18 +264,17 @@ impl<'source> Parser<'source> {
"metadata" => {
*metadata = Some(self.parse_json_value()?);
}
"parameters" => {
"parameters" if self.token_text() == "{" => {
// Parameters must be a JSON object; if not, push to extra.
if self.token_text() == "{" {
*parameters = self.parse_parameter_definitions()?;
} else {
let value = self.parse_json_value()?;
extra.push(ObjectEntry {
key_span,
key: key.into(),
value,
});
}
*parameters = self.parse_parameter_definitions()?;
}
"parameters" => {
let value = self.parse_json_value()?;
extra.push(ObjectEntry {
key_span,
key: key.into(),
value,
});
}
"policyrule" => {
// Parse the policyRule directly from the token stream!
+1 -1
View File
@@ -88,7 +88,7 @@ fn analyze_file(regos: &[String], expected_scopes: &[Scope]) -> Result<()> {
}
}
scopes.sort_by(|a, b| a.0.span.line.cmp(&b.0.span.line));
scopes.sort_by_key(|a| a.0.span.line);
for (idx, (_, scope)) in scopes.iter().enumerate() {
if idx > expected_scopes.len() {
bail!("extra scope generated.")