Distinguish annotation validation from content read dependencies
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
| 文件 | 职责 |
|
||||
| --- | --- |
|
||||
| [lib.rs](lib.rs) | VM 类型导出、objects 类型兼容重导出、宿主调用与字节码 rustdoc 示例 |
|
||||
| [lib.rs](lib.rs) | VM 类型导出、objects 类型兼容重导出(含 ReadAccess)、宿主调用与字节码 rustdoc 示例 |
|
||||
| [vm.rs](vm.rs) | Vm 拥有 ObjectStore 与错误位置记录;对象操作和宿主 new_class 和显式Trait注册/关系查询显式委托给 objects;函数/字段检查统一开关、统一参数区间查询与函数类型配置 |
|
||||
| [frame.rs](frame.rs) | EndorFrame、栈条目、返回类型执行根、执行位置元数据、ExecutionLimits |
|
||||
| [eval.rs](eval.rs) | execute/call、只读调用与依赖结果、参数绑定、原生实现前数量检查、可选注解检查、源码类字段环境绑定、帧切换、取指分派、MakeFunction、结果根转移与失败清理 |
|
||||
|
||||
@@ -56,6 +56,6 @@ pub use objects::{
|
||||
EndorNativeFunctionObject, EndorNumber, EndorNumberObject, EndorObject, EndorRational,
|
||||
EndorReal, EndorStringObject, EndorTracebackEntry, Instruction, NativeCall, NativeCallable,
|
||||
NativeContext, NativeFunction, NativeResult, ObjectChange, ObjectHeader, ObjectPayload,
|
||||
ObjectRef, Opcode, Record, SourceSignature, Value, VmError, WeakObjectRef,
|
||||
ObjectRef, Opcode, ReadAccess, Record, SourceSignature, Value, VmError, WeakObjectRef,
|
||||
};
|
||||
pub use vm::Vm;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
| [builtins.rs](builtins.rs) | 无损 Number、Unicode 字符串、Dict 顺序与键、Cell、函数环境/共享代码、异常数据 |
|
||||
| [execution.rs](execution.rs) | wordcode 与校验、控制流、参数/默认值、嵌套帧、字节码函数创建/默认值/环境捕获、闭包、返回值存活、失败清理、限额 |
|
||||
| [types.rs](types.rs) | 名义身份、继承与实例关系、类型边保活/循环回收、只读类型元数据与外来句柄、显式Trait身份/继承/参数约束及后代更新原子性;统一函数分类、原生数量元数据/副作用前拒绝/能力更新/默认参数与返回类型错误根清理;仅远端执行 |
|
||||
| [native_context.rs](native_context.rs) | 原生作用域根、分配失败清理、委托、只读结果分配/写入拒绝/依赖与失败恢复、弱引用过期及有界变更;仅远端执行 |
|
||||
| [native_context.rs](native_context.rs) | 原生作用域根、分配失败清理、委托、只读结果分配/写入拒绝/依赖/校验与普通读取区分及失败恢复、弱引用过期及有界变更;仅远端执行 |
|
||||
|
||||
核心对象现由 objects 定义,本目录保留既有 endor_core 导入与 Vm 方法的兼容性检查。独立对象存储检查见 [objects/tests](../../objects/tests/README.md)。堆内部伪造句柄与计数溢出检查在 objects 的 src/heap.rs,公开示例由 src/lib.rs rustdoc 提供。文件职责见 [src](../src/README.md),检查方式和结果边界见 [验证](../../../docs/operations/validation.md)。本地不执行测试;存在测试文件不代表某次提交已通过。返回 [core](../README.md)。
|
||||
|
||||
|
||||
@@ -222,3 +222,49 @@ fn read_only_calls_track_borrowed_dependencies_allow_results_and_restore_after_e
|
||||
vm.release(source).unwrap();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn annotation_reads_remain_dependencies_without_becoming_program_content_reads() {
|
||||
use endor_core::AnnotationType;
|
||||
let mut store = objects::ObjectStore::new().unwrap();
|
||||
let object = store.new_object().unwrap();
|
||||
store
|
||||
.set_attr(object, "value", Value::Number(1.into()))
|
||||
.unwrap();
|
||||
let scope = store.begin_read_only();
|
||||
let token = store.begin_read_tracking().unwrap();
|
||||
assert!(
|
||||
store
|
||||
.matches_annotation(&Value::Object(object), AnnotationType::Any)
|
||||
.unwrap()
|
||||
);
|
||||
let reads = store.end_read_tracking_details(token).unwrap();
|
||||
assert!(
|
||||
reads
|
||||
.iter()
|
||||
.any(|read| read.object == object && !read.content_read)
|
||||
);
|
||||
let token = store.begin_read_tracking().unwrap();
|
||||
assert!(
|
||||
!store
|
||||
.matches_annotation(&Value::Object(object), AnnotationType::Number)
|
||||
.unwrap()
|
||||
);
|
||||
let mut foreign = objects::ObjectStore::new().unwrap();
|
||||
let alien = foreign.new_object().unwrap();
|
||||
assert!(matches!(
|
||||
store.matches_annotation(&Value::Object(alien), AnnotationType::Any),
|
||||
Err(VmError::ForeignHandle)
|
||||
));
|
||||
foreign.release(alien).unwrap();
|
||||
store.get_attr(object, "value").unwrap();
|
||||
let reads = store.end_read_tracking_details(token).unwrap();
|
||||
assert!(
|
||||
reads
|
||||
.iter()
|
||||
.any(|read| read.object == object && read.content_read)
|
||||
);
|
||||
assert!(store.end_read_only(scope).unwrap().contains(&object));
|
||||
store.release(object).unwrap();
|
||||
assert_eq!(store.object_count(), 0);
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
| 文件 | 职责 |
|
||||
| --- | --- |
|
||||
| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/SourceSignature/AnnotationType/CallArity)与独立存储 rustdoc 示例 |
|
||||
| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/SourceSignature/AnnotationType/CallArity/ReadAccess)与独立存储 rustdoc 示例 |
|
||||
| [object.rs](object.rs) | Value、CompareOp、ObjectPayload(含显式函数标记)、ObjectHeader、EndorObject、Record、可发布数量元数据的 NativeFunction |
|
||||
| [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段、显式Trait定义/声明/方法参数约束、原生构造委托、统一源码/原生/绑定方法参数区间查询与能力验证、声明环境托管边、字段构造/写入检查与注解解析/匹配 |
|
||||
| [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段、显式Trait定义/声明/方法参数约束、原生构造委托、统一源码/原生/绑定方法参数区间查询与能力验证、声明环境托管边、字段构造/写入检查与标记为校验读取的注解解析/匹配 |
|
||||
| [native.rs](native.rs) | NativeContext、CallArity 元数据与调用前数量检查、上下文原生函数、作用域语言函数工厂、显式能力声明入口、函数标记、根与非递归委托调用 |
|
||||
| [changes.rs](changes.rs) | 合并变更批次、变更键与有界通知额度 |
|
||||
| [number.rs](number.rs) | Integer/Decimal/Rational/BinaryFloat/Complex 的无损表示和装箱载荷 |
|
||||
| [builtins.rs](builtins.rs) | String、Dict、Cell、Function、BaseException 载荷与 trace 边、语言函数标记 |
|
||||
| [heap.rs](heap.rs) | 私有 Heap、不可伪造 ObjectRef、稳定 Box、引用事务、迭代释放、循环回收、后代契约更新的私有借用枚举、同类型附加幂等、只读变更屏障/全调用及嵌套子调用读取跟踪及私有边界测试 |
|
||||
| [store.rs](store.rs) | ObjectStore、空堆创建、字段检查配置/属性写入屏障、对象操作、retain/release 和回收入口、弱 Function 类型配置与分配分类 |
|
||||
| [heap.rs](heap.rs) | 私有 Heap、不可伪造 ObjectRef、稳定 Box、引用事务、迭代释放、循环回收、后代契约更新的私有借用枚举、同类型附加幂等、只读变更屏障/全调用及嵌套子调用读取跟踪(区分注解校验与内容读取)及私有边界测试 |
|
||||
| [store.rs](store.rs) | ObjectStore、空堆创建、字段检查配置/属性写入屏障、详细读取区域结果、对象操作、retain/release 和回收入口、弱 Function 类型配置与分配分类 |
|
||||
| [store_builtins.rs](store_builtins.rs) | 载荷校验、代码/函数工厂、Dict/Cell 操作及键语义 |
|
||||
| [instruction.rs](instruction.rs) | Opcode、Instruction、wordcode 编解码、MakeFunction/比较参数与跳转读取接口 |
|
||||
| [code.rs](code.rs) | CodeLayout、EndorCode/EndorCodeObject、可选源码签名、共享不可变代码和操作数/控制流/栈验证 |
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
use std::fmt;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::thread::ThreadId;
|
||||
|
||||
use crate::changes::MAX_PENDING_CHANGES;
|
||||
use crate::{ChangeBatch, ChangeKey, ObjectChange};
|
||||
@@ -39,7 +40,7 @@ struct Slot {
|
||||
struct ReadOnly {
|
||||
protected: BTreeSet<ObjectRef>,
|
||||
reads: Mutex<BTreeSet<ObjectRef>>,
|
||||
regions: Mutex<Vec<BTreeSet<ObjectRef>>>,
|
||||
regions: Mutex<Vec<BTreeMap<ObjectRef, bool>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -51,6 +52,36 @@ pub(crate) struct Heap {
|
||||
changes: BTreeMap<(ObjectRef, ChangeKey), u64>,
|
||||
changes_overflow: bool,
|
||||
read_only: Vec<ReadOnly>,
|
||||
validation_reads: Mutex<HashMap<ThreadId, usize>>,
|
||||
}
|
||||
|
||||
/// Borrowed read identity; content_read distinguishes ordinary reads from
|
||||
/// annotation validation alone. Neither form retains the object.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ReadAccess {
|
||||
pub object: ObjectRef,
|
||||
pub content_read: bool,
|
||||
}
|
||||
|
||||
struct ValidationScope<'a> {
|
||||
heap: &'a Heap,
|
||||
thread: ThreadId,
|
||||
}
|
||||
impl Drop for ValidationScope<'_> {
|
||||
fn drop(&mut self) {
|
||||
let mut active = self
|
||||
.heap
|
||||
.validation_reads
|
||||
.lock()
|
||||
.expect("read tracker poisoned");
|
||||
let depth = active
|
||||
.get_mut(&self.thread)
|
||||
.expect("active validation scope");
|
||||
*depth -= 1;
|
||||
if *depth == 0 {
|
||||
active.remove(&self.thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Heap {
|
||||
@@ -66,6 +97,7 @@ impl Heap {
|
||||
changes: BTreeMap::new(),
|
||||
changes_overflow: false,
|
||||
read_only: vec![],
|
||||
validation_reads: Mutex::new(HashMap::new()),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -120,11 +152,22 @@ impl Heap {
|
||||
"read tracking requires a read-only scope",
|
||||
))?;
|
||||
let mut regions = scope.regions.lock().expect("read tracker poisoned");
|
||||
regions.push(BTreeSet::new());
|
||||
regions.push(BTreeMap::new());
|
||||
Ok(regions.len())
|
||||
}
|
||||
|
||||
pub(crate) fn end_read_tracking(&self, token: usize) -> Result<Vec<ObjectRef>, VmError> {
|
||||
Ok(self
|
||||
.end_read_tracking_details(token)?
|
||||
.into_iter()
|
||||
.map(|read| read.object)
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub(crate) fn end_read_tracking_details(
|
||||
&self,
|
||||
token: usize,
|
||||
) -> Result<Vec<ReadAccess>, VmError> {
|
||||
let scope = self.read_only.last().ok_or(VmError::InvalidArgument(
|
||||
"read tracking requires a read-only scope",
|
||||
))?;
|
||||
@@ -132,14 +175,49 @@ impl Heap {
|
||||
if token == 0 || token != regions.len() {
|
||||
return Err(VmError::InvalidArgument("read tracking nesting mismatch"));
|
||||
}
|
||||
Ok(regions.pop().unwrap().into_iter().collect())
|
||||
Ok(regions
|
||||
.pop()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(object, content_read)| ReadAccess {
|
||||
object,
|
||||
content_read,
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub(crate) fn is_read_only(&self) -> bool {
|
||||
!self.read_only.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn with_validation_reads<T>(
|
||||
&self,
|
||||
compute: impl FnOnce() -> Result<T, VmError>,
|
||||
) -> Result<T, VmError> {
|
||||
if self.read_only.is_empty() {
|
||||
return compute();
|
||||
}
|
||||
let thread = std::thread::current().id();
|
||||
{
|
||||
let mut active = self.validation_reads.lock().expect("read tracker poisoned");
|
||||
let depth = active.entry(thread).or_default();
|
||||
*depth = depth
|
||||
.checked_add(1)
|
||||
.ok_or(VmError::ExecutionLimit("validation scopes"))?;
|
||||
}
|
||||
let _scope = ValidationScope { heap: self, thread };
|
||||
compute()
|
||||
}
|
||||
|
||||
pub(crate) fn record_read(&self, reference: ObjectRef) {
|
||||
if self.read_only.is_empty() {
|
||||
return;
|
||||
}
|
||||
let content = !self
|
||||
.validation_reads
|
||||
.lock()
|
||||
.expect("read tracker poisoned")
|
||||
.contains_key(&std::thread::current().id());
|
||||
for scope in &self.read_only {
|
||||
if scope.protected.contains(&reference) {
|
||||
scope
|
||||
@@ -153,7 +231,10 @@ impl Heap {
|
||||
.expect("read tracker poisoned")
|
||||
.iter_mut()
|
||||
{
|
||||
region.insert(reference);
|
||||
region
|
||||
.entry(reference)
|
||||
.and_modify(|ordinary| *ordinary |= content)
|
||||
.or_insert(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ pub use builtins::{
|
||||
pub use changes::{ChangeBatch, ChangeKey, ObjectChange};
|
||||
pub use code::{CodeLayout, EndorCode, EndorCodeObject, SourceSignature};
|
||||
pub use error::VmError;
|
||||
pub use heap::{ObjectRef, WeakObjectRef};
|
||||
pub use heap::{ObjectRef, ReadAccess, WeakObjectRef};
|
||||
pub use instruction::{DecodedInstruction, Instruction, Opcode};
|
||||
pub use native::{CallArity, ContextNativeFunction, NativeCallable, NativeContext, NativeResult};
|
||||
pub use number::{
|
||||
|
||||
@@ -44,6 +44,15 @@ impl ObjectStore {
|
||||
self.heap.end_read_tracking(token)
|
||||
}
|
||||
|
||||
/// Like end_read_tracking, retaining the distinction between program reads
|
||||
/// and VM annotation validation. Ordinary reads always dominate.
|
||||
pub fn end_read_tracking_details(
|
||||
&self,
|
||||
token: usize,
|
||||
) -> Result<Vec<crate::ReadAccess>, VmError> {
|
||||
self.heap.end_read_tracking_details(token)
|
||||
}
|
||||
|
||||
pub fn is_read_only(&self) -> bool {
|
||||
self.heap.is_read_only()
|
||||
}
|
||||
|
||||
@@ -996,6 +996,15 @@ impl ObjectStore {
|
||||
&self,
|
||||
value: &Value,
|
||||
expected: AnnotationType,
|
||||
) -> Result<bool, VmError> {
|
||||
self.heap
|
||||
.with_validation_reads(|| self.matches_annotation_value(value, expected))
|
||||
}
|
||||
|
||||
fn matches_annotation_value(
|
||||
&self,
|
||||
value: &Value,
|
||||
expected: AnnotationType,
|
||||
) -> Result<bool, VmError> {
|
||||
if let Value::Object(object) = value {
|
||||
self.object(*object)?;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
| 引擎与宿主边界 | [架构](architecture/README.md) | [crates](../crates/README.md) |
|
||||
| 解释执行、资源修订与引擎升级 | [执行与版本](architecture/execution-and-versions.md) | frontend/compiler/core |
|
||||
| EndorObject、句柄、默认操作 | [对象模型](runtime/objects.md) | objects/src |
|
||||
| 原生上下文、只读调用、子调用读取依赖、统一参数数量、委托与变更通知 | [原生调用](runtime/native-calls.md) | objects/src/native.rs、changes.rs、core/src/eval.rs |
|
||||
| 原生上下文、只读调用、子调用读取依赖及校验分类、统一参数数量、委托与变更通知 | [原生调用](runtime/native-calls.md) | objects/src/native.rs、changes.rs、core/src/eval.rs |
|
||||
| 托管类型、宿主类注册、原生分配继承、字段存储、显式能力、函数分类、声明字段与可选源码注解检查 | [名义类型](runtime/types.md) | objects/src/types.rs |
|
||||
| Number、String、Dict、Cell、Function | [基本对象](runtime/builtins.md) | objects/src |
|
||||
| 源码读取与来源 | [Reader](runtime/reader.md) | frontend/src/reader.rs |
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
| --- | --- |
|
||||
| [types.md](types.md) | 托管 Object/Type、名义继承、声明字段/函数注解检查、构造与类型边生命周期 |
|
||||
| [objects.md](objects.md) | 对象、句柄与默认操作 |
|
||||
| [native-calls.md](native-calls.md) | 原生上下文、统一参数数量、非递归委托、弱引用、托管赋值与变更批次 |
|
||||
| [native-calls.md](native-calls.md) | 原生上下文、读取分类、统一参数数量、非递归委托、弱引用、托管赋值与变更批次 |
|
||||
| [builtins.md](builtins.md) | Number、String、Dict、Cell、Function、异常数据 |
|
||||
| [reader.md](reader.md) | 输入、来源和修订标签 |
|
||||
| [frontend.md](frontend.md) | 词法、语法和诊断 |
|
||||
|
||||
@@ -79,3 +79,10 @@ take_changes 按对象与变更键合并同一批写入,返回最终版本。
|
||||
显式 Trait 声明、源码派生及方法表更新使用统一区间检查“规范参数数量加 self”是否被接受;缺少元数据的原生方法不能再登记为能力实现。可选参数允许实现接受规范调用数量之外的额外形式。更新仍先检查后代再修改,无隐藏类型根。类型注解兼容性、方差、参数名称及效果检查尚未接入此结构。
|
||||
|
||||
Tessera 为原生方法、回调和内部视觉 continuation 发布数量元数据,事件监听要求接受零参数或一个 Event;两者都接受时优先传 Event。绑定计算和 Task 回调要求接受零参数,登记前拒绝无元数据/不兼容函数;普通旧原生调用的兼容性不等于允许其参加这些严格回调契约。
|
||||
|
||||
|
||||
## 校验读取与程序内容读取
|
||||
|
||||
只读子区域新增 `ObjectStore::end_read_tracking_details(token) -> Vec<ReadAccess>`,每项仍是借用 ObjectRef,content_read 表示是否存在普通内容读取。matches_annotation 内部的名义/基础值检查标为校验读取;同一区域随后发生普通读取时,content_read 合并为 true。嵌套区域均保留两类读取,不增加对象根。原 end_read_tracking 与完整 end_read_only 仍返回两类读取的完整并集,没有删除依赖或放宽只读写屏障。
|
||||
|
||||
校验分类按线程记录嵌套深度,作用域退出、错误和展开时通过 RAII 恢复,不让另一线程继承标签。公开 ReadAccess 仅提供信息,不保证调用者可忽略任何对象;动态类型/能力/全局定义等校验依赖仍须参与失效。Tessera 独立验证每次活动 Mount/归属/方法后,仅跳过该 Mount 的纯参数类型校验读取;程序实际读取 Mount 内容仍禁止复用测量缓存。其他读取继续记录版本。详见 core/tests/native_context.rs 的合并、完整依赖并集与错误恢复回归源码,仅编译未本地执行。
|
||||
|
||||
Reference in New Issue
Block a user