mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
* 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>
255 lines
7.1 KiB
C#
255 lines
7.1 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
|
#nullable enable
|
|
namespace Regorus
|
|
{
|
|
internal sealed class RegorusEngineHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private RegorusEngineHandle() : base(ownsHandle: true)
|
|
{
|
|
}
|
|
|
|
internal static RegorusEngineHandle Create()
|
|
{
|
|
unsafe
|
|
{
|
|
var raw = Internal.API.regorus_engine_new();
|
|
if (raw is null)
|
|
{
|
|
throw new InvalidOperationException("Failed to create Regorus engine.");
|
|
}
|
|
|
|
var handle = new RegorusEngineHandle();
|
|
handle.SetHandle((IntPtr)raw);
|
|
return handle;
|
|
}
|
|
}
|
|
|
|
internal static RegorusEngineHandle FromPointer(IntPtr pointer)
|
|
{
|
|
if (pointer == IntPtr.Zero)
|
|
{
|
|
throw new ArgumentException("Pointer cannot be zero.", nameof(pointer));
|
|
}
|
|
|
|
var handle = new RegorusEngineHandle();
|
|
handle.SetHandle(pointer);
|
|
return handle;
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
if (!IsInvalid)
|
|
{
|
|
unsafe
|
|
{
|
|
Internal.API.regorus_engine_drop((Internal.RegorusEngine*)handle);
|
|
}
|
|
SetHandle(IntPtr.Zero);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal sealed class RegorusCompiledPolicyHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private RegorusCompiledPolicyHandle() : base(ownsHandle: true)
|
|
{
|
|
}
|
|
|
|
internal static RegorusCompiledPolicyHandle FromPointer(IntPtr pointer)
|
|
{
|
|
if (pointer == IntPtr.Zero)
|
|
{
|
|
throw new ArgumentException("Pointer cannot be zero.", nameof(pointer));
|
|
}
|
|
|
|
var handle = new RegorusCompiledPolicyHandle();
|
|
handle.SetHandle(pointer);
|
|
return handle;
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
if (!IsInvalid)
|
|
{
|
|
unsafe
|
|
{
|
|
Internal.API.regorus_compiled_policy_drop((Internal.RegorusCompiledPolicy*)handle);
|
|
}
|
|
SetHandle(IntPtr.Zero);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal sealed class RegorusProgramHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private RegorusProgramHandle() : base(ownsHandle: true)
|
|
{
|
|
}
|
|
|
|
internal static RegorusProgramHandle Create()
|
|
{
|
|
unsafe
|
|
{
|
|
var raw = Internal.API.regorus_program_new();
|
|
if (raw is null)
|
|
{
|
|
throw new InvalidOperationException("Failed to create Regorus program.");
|
|
}
|
|
|
|
var handle = new RegorusProgramHandle();
|
|
handle.SetHandle((IntPtr)raw);
|
|
return handle;
|
|
}
|
|
}
|
|
|
|
internal static RegorusProgramHandle FromPointer(IntPtr pointer)
|
|
{
|
|
if (pointer == IntPtr.Zero)
|
|
{
|
|
throw new ArgumentException("Pointer cannot be zero.", nameof(pointer));
|
|
}
|
|
|
|
var handle = new RegorusProgramHandle();
|
|
handle.SetHandle(pointer);
|
|
return handle;
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
if (!IsInvalid)
|
|
{
|
|
unsafe
|
|
{
|
|
Internal.API.regorus_program_drop((Internal.RegorusProgram*)handle);
|
|
}
|
|
SetHandle(IntPtr.Zero);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal sealed class RegorusRvmHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private RegorusRvmHandle() : base(ownsHandle: true)
|
|
{
|
|
}
|
|
|
|
internal static RegorusRvmHandle Create()
|
|
{
|
|
unsafe
|
|
{
|
|
var raw = Internal.API.regorus_rvm_new();
|
|
if (raw is null)
|
|
{
|
|
throw new InvalidOperationException("Failed to create Regorus RVM.");
|
|
}
|
|
|
|
var handle = new RegorusRvmHandle();
|
|
handle.SetHandle((IntPtr)raw);
|
|
return handle;
|
|
}
|
|
}
|
|
|
|
internal static RegorusRvmHandle FromPointer(IntPtr pointer)
|
|
{
|
|
if (pointer == IntPtr.Zero)
|
|
{
|
|
throw new ArgumentException("Pointer cannot be zero.", nameof(pointer));
|
|
}
|
|
|
|
var handle = new RegorusRvmHandle();
|
|
handle.SetHandle(pointer);
|
|
return handle;
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
if (!IsInvalid)
|
|
{
|
|
unsafe
|
|
{
|
|
Internal.API.regorus_rvm_drop((Internal.RegorusRvm*)handle);
|
|
}
|
|
SetHandle(IntPtr.Zero);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal sealed class RegorusAliasRegistryBuilderHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private RegorusAliasRegistryBuilderHandle() : base(ownsHandle: true)
|
|
{
|
|
}
|
|
|
|
internal static RegorusAliasRegistryBuilderHandle Create()
|
|
{
|
|
unsafe
|
|
{
|
|
var raw = Internal.API.regorus_alias_registry_builder_new();
|
|
if (raw is null)
|
|
{
|
|
throw new InvalidOperationException("Failed to create Regorus alias registry builder.");
|
|
}
|
|
|
|
var handle = new RegorusAliasRegistryBuilderHandle();
|
|
handle.SetHandle((IntPtr)raw);
|
|
return handle;
|
|
}
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
if (!IsInvalid)
|
|
{
|
|
unsafe
|
|
{
|
|
Internal.API.regorus_alias_registry_builder_drop((Internal.RegorusAliasRegistryBuilder*)handle);
|
|
}
|
|
SetHandle(IntPtr.Zero);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal sealed class RegorusAliasRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
private RegorusAliasRegistryHandle() : base(ownsHandle: true)
|
|
{
|
|
}
|
|
|
|
internal static RegorusAliasRegistryHandle FromPointer(IntPtr pointer)
|
|
{
|
|
if (pointer == IntPtr.Zero)
|
|
{
|
|
throw new ArgumentException("Pointer cannot be zero.", nameof(pointer));
|
|
}
|
|
|
|
var handle = new RegorusAliasRegistryHandle();
|
|
handle.SetHandle(pointer);
|
|
return handle;
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
if (!IsInvalid)
|
|
{
|
|
unsafe
|
|
{
|
|
Internal.API.regorus_alias_registry_drop((Internal.RegorusAliasRegistry*)handle);
|
|
}
|
|
SetHandle(IntPtr.Zero);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|