-
Notifications
You must be signed in to change notification settings - Fork 85
question: propagation through closure containing tagged values #1225
Comments
This seems like an oversight to me. I would expect SuperComponent to tag a closure that captures a tagged value. To get the ball rolling, why don't you construct a test case that can be used to drive an implementation of the feature. |
I'm trying to make the following work, but I've been failing to do so: #![cfg_attr(mirai, allow(incomplete_features), feature(generic_const_exprs))]
#[cfg(mirai)]
use mirai_annotations::{TagPropagationSet, TAG_PROPAGATION_ALL};
use std::borrow::Borrow;
#[macro_use]
extern crate mirai_annotations;
#[macro_use]
extern crate contracts;
/// Our tag for detecting out-of-circuit values that are reinserted into the circuit.
// TODO: OOC value doesn't quite describe it, here we're looking specifically for OOC values that were previously in the circuit. So perhaps boomerang values?
#[cfg(mirai)]
struct OOCTaintKind<const MASK: TagPropagationSet> {}
/// our tag with all propagation set
#[cfg(mirai)]
type OOCTaint = OOCTaintKind<TAG_PROPAGATION_ALL>;
#[cfg(not(mirai))]
type OOCTaint = ();
trait R1CS {
type Value;
fn value(&self) -> Self::Value;
}
trait Var<V>
where
Self: Sized,
V: ?Sized,
{
fn new_variable<T: Borrow<V>>(f: impl FnOnce() -> Result<T, String>) -> Result<Self, String>;
}
#[derive(Debug)]
pub struct FieldVar {
value: u8,
}
impl R1CS for FieldVar {
type Value = u8;
fn value(&self) -> Self::Value {
add_tag!(&self.value, OOCTaint);
let result = self.value;
postcondition!(has_tag!(&result, OOCTaint));
return result;
}
}
impl Var<u8> for FieldVar {
#[requires(does_not_have_tag!(&f, OOCTaint))]
fn new_variable<T: Borrow<u8>>(f: impl FnOnce() -> Result<T, String>) -> Result<Self, String> {
let value = f()?.borrow().clone();
Ok(FieldVar { value })
}
}
impl FieldVar {
#[requires(does_not_have_tag!(&value, OOCTaint))]
fn without_closure(value: u8) -> Result<Self, String> {
Ok(FieldVar { value })
}
fn try_2(value: u8) -> Result<Self, String> {
precondition!(does_not_have_tag!(&value, OOCTaint));
verify!(does_not_have_tag!(&value, OOCTaint));
Ok(FieldVar { value })
}
}
fn main() {
// create a new field var
let x = FieldVar::new_variable(|| Ok(1)).unwrap();
// move it to OOC
let ooc = x.value();
verify!(has_tag!(&ooc, OOCTaint));
// REINSERT IT! OMG!
let y = FieldVar::new_variable(|| Ok(ooc)).unwrap();
verify!(has_tag!(&ooc, OOCTaint));
let y2 = FieldVar::without_closure(ooc).unwrap();
verify!(has_tag!(&ooc, OOCTaint));
let y3 = FieldVar::try_2(ooc).unwrap();
dbg!(&y, &y2, &y3);
} running
which doesn't seem correct to me |
note that |
OK I think I figured out what went wrong:
|
In addition, MIRAI does not seem to propagate on closures containing a tagged value. In the modified code that now works, only y2 (and if I comment y2, then y3) get detected by MIRAI. Even in paranoid mode. impl Var<Val> for FieldVar {
// #[requires(does_not_have_tag!(&f, OOCTaint))]
fn new_variable<T: Borrow<Val>>(f: impl FnOnce() -> Result<T, String>) -> Result<Self, String> {
precondition!(does_not_have_tag!(&f, OOCTaint));
let value = f()?.borrow().clone();
Ok(FieldVar { value })
}
}
impl FieldVar {
// #[requires(does_not_have_tag!(&value, OOCTaint))]
fn without_closure(value: Val) -> Result<Self, String> {
precondition!(does_not_have_tag!(&value, OOCTaint));
Ok(FieldVar { value })
}
fn try_2(value: Val) -> Result<Self, String> {
precondition!(does_not_have_tag!(&value, OOCTaint));
verify!(does_not_have_tag!(&value, OOCTaint));
Ok(FieldVar { value })
}
} EDIT: if I use |
At this point I think it'd be good to have a "gotchas" document for MIRAI with mistakes or surprising behaviors that people run into when playing with MIRAI :) when I run mirai on a library (with no another question I'm wondering about now is, does mirai work across crates? (I remember that |
BTW, I'm also trying the |
MIRAI_LOG=info will log the name of all functions being analyzed. To format output in the log is the format to use in single_func. The name of the option is now a bit misleading and should rather be -root=name_of_function. I.e. it will start with the given function and analyze it AS WELL AS all the functions it calls and all the functions they call and so on. The reason being that you cannot accurately summarize the root without first summarizing all the other functions that can be reached from the root. |
I think I remember that I have to |
touch or just cargo clean. While MIRAI still works the ways it did way back when you last used it, it is now integrated into Cargo and |
I tried:
EDIT: oh I think you meant it should be called This works now : ) as long as I call I'm now going to try to see if this works across crates. Thanks for the help @hermanventer ! Hopefuly this thread is also useful to other people trying to do similar things : ) |
OK it does not seem to work across crates as I expected. Are you aware of this problem? Unless I'm missing something it's the same issue as with Would it make sense to change any |
If you use cargo mirai, it should compile all crates with the MIRAI configuration and things should work across crates. |
yeah I see the |
Looking at the propagation options, it doesn't seem like a tagged values => a tagged closure containing that value. The problem is that I want a method to detect when one of its argument contains a closure, which is tagged
(unless that's the
UninterpretedCall
?)The text was updated successfully, but these errors were encountered: