What would a monitor for rust look like? #2
Replies: 2 comments 12 replies
-
A couple of existing runtime verification tools for RustI did a quick look into the literature to see what other runtime verification frameworks have Rust monitor generation implemented. One of the tools is TeSSLa which can compile runtime monitors to Rust (and Scala). Another one is RTLola which had a publication a few years ago on generating Rust monitors and there is a repo for the artefacts of the paper though I could not find the Rust monitor generation code. But there is an interpreter that could take a monitoring specification and run a monitor as part of a Rust application. What does TeSSLa monitor look like?A description of the generated Rust monitor interface can be found here. In brief: There is a generated The user initializes the state struct by providing references to output callbacks (or specifying callback functions in terms of lambdas). Afterwards, the main loop (implemented by the user) looks as follows:
What does RTLola interpreter monitor look like?Documentation on RTLola monitor interface can be found here. In brief: It seems that a monitor struct is created at runtime by providing a specification string (which is then parsed and translated to some internal representation). The monitor struct has functions to accept events or accept time.
Both functions for accepting an event and time return a vector of verdicts (because they both advance monitor time). There are different choices on how verdicts can be reported, e.g. totally by giving the full statuses of verdicts or incrementally by only providing the changes in verdicts during the most recent timestamp advance. As opposed to Copilot and TeSSLa, there is no mechanism for triggering the user provided functions based on monitor verdicts. Note: Generated RTLola Rust monitors as described in the paper might have a different interface than RTLola interpreter. But looking at the code in the repo for the artefacts of the paper, it seems that the interface there is not really fleshed out: e.g. inputs are taken from inside of What could a (Rust) monitor look likeI thought about the questions, here are some ideas that I had on implementing a monitor after observing the ways it was implemented in other Rust runtime monitoring tools. Feel free to correct me or comment, I have little experience with Rust. Providing inputsThere could be different ways of providing inputs to monitors:
My subjective preference would be the number 2. as in this way the step function is more explicit and about values it depends on. Communicating outputs
For a Rust backend prototype, I would say 3. might be the easiest to implement. Perhaps it might initially suffice to provide all verdicts as a struct/array of bools. For a longer term solution, some variant of 1. or 2. or something else might be chosen. Executing an iteration and handling the internal stateIn Copilot C backend, the internal state of monitors is stored as many static variables, which again might be not a good idea in Rust, as one needs to use If we decide to use callbacks either for getting inputs or triggers, it might be a good idea to separate those references from the internal monitor state (the one that stores e.g. buffers of past signal values, or some intermediate stream values). For testability (and perhaps replayability) it might be good to have some pure function for performing core stream logic and state updates, in Haskell terms, having a signature like this |
Beta Was this translation helpful? Give feedback.
-
Galois has a C2Rust converter. If I paste one of our Copilot modules with https://c2rust.com/, here's what comes out: #![allow(dead_code, mutable_transmutes, non_camel_case_types, non_snake_case, non_upper_case_globals, unused_assignments, unused_mut)]
#![register_tool(c2rust)]
#![feature(register_tool)]
extern "C" {
static mut temperature: uint8_t;
fn heaton(heaton_arg0_0: float_t);
fn heatoff(heatoff_arg0_0: float_t);
}
pub type uint8_t = libc::c_uchar;
pub type float_t = libc::c_float;
static mut temperature_cpy: uint8_t = 0;
unsafe extern "C" fn heaton_guard() -> bool {
return temperature_cpy as float_t * (150.0f32 / 255.0f32) - 50.0f32 < 18.0f32;
}
unsafe extern "C" fn heaton_arg0() -> float_t {
return temperature_cpy as float_t * (150.0f32 / 255.0f32) - 50.0f32;
}
unsafe extern "C" fn heatoff_guard() -> bool {
return temperature_cpy as float_t * (150.0f32 / 255.0f32) - 50.0f32 > 21.0f32;
}
unsafe extern "C" fn heatoff_arg0() -> float_t {
return temperature_cpy as float_t * (150.0f32 / 255.0f32) - 50.0f32;
}
#[no_mangle]
pub unsafe extern "C" fn step() {
let mut heaton_arg_temp0: float_t = 0.;
let mut heatoff_arg_temp0: float_t = 0.;
temperature_cpy = temperature;
if heaton_guard() {
heaton_arg_temp0 = heaton_arg0();
heaton(heaton_arg_temp0);
}
if heatoff_guard() {
heatoff_arg_temp0 = heatoff_arg0();
heatoff(heatoff_arg_temp0);
}
} I would not suggest we approach it this way, but I thought, for completeness, it could be useful info. |
Beta Was this translation helpful? Give feedback.
-
Copilot-generated C code connects to C systems in a very specific way:
step
by default).These ideas may not translate well into Rust. A first topic to discuss, then, would be what a Rust monitor would look like in general (even without Copilot anywhere in the mix). That is, if there is a program written in rust, and you wanted to create a module that checks if some property holds over the execution of the program, what would such a monitor look like?
Beta Was this translation helpful? Give feedback.
All reactions