pub struct Context {
    marker_to_ids: HashMap<Marker, MarkerTargets>,
    desc: ProgramDescription,
    flows_to: Option<HashMap<Endpoint, CtrlFlowsTo>>,
    pub(crate) diagnostics: DiagnosticsRecorder,
    name_map: HashMap<Identifier, Vec<DefId>>,
    pub(crate) config: Arc<Config>,
    pub(crate) stats: ContextStats,
}
Expand description

Interface for defining policies.

Holds a PDG (Self::desc) and defines basic queries like Self::all_nodes_for_ctrl and combinators such as Self::always_happens_before. These should be composed into more complex policies.

To communicate the results of your policies with the user you can emit diagnostic messages. To communicate a policy failure use error or the crate::assert_error macro. To communicate suspicious circumstances that are not outright cause for failure use warning or assert_warning. For all types of errors, including those with span information for a particular node, see the crate::Diagnostics trait.

Note that these methods just queue the diagnostics messages. To emit them (and potentially terminate the program if the policy does not hold) use Self::emit_diagnostics. If you used super::GraphLocation::with_context this will be done automatically for you.

Fields§

§marker_to_ids: HashMap<Marker, MarkerTargets>§desc: ProgramDescription§flows_to: Option<HashMap<Endpoint, CtrlFlowsTo>>§diagnostics: DiagnosticsRecorder§name_map: HashMap<Identifier, Vec<DefId>>§config: Arc<Config>§stats: ContextStats

Implementations§

source§

impl Context

source

pub fn always_happens_before( &self, starting_points: impl IntoIterator<Item = GlobalNode>, is_checkpoint: impl FnMut(GlobalNode) -> bool, is_terminal: impl FnMut(GlobalNode) -> bool ) -> Result<AlwaysHappensBefore>

Enforce that on every data flow path from the starting_points to is_terminal a node satisfying is_checkpoint is passed.

Fails if ctrl_id on a provided starting point is not found.

The return value contains some statistics information about the traversal. The property holds if AlwaysHappensBefore::holds is true.

Note that is_checkpoint and is_terminal will be called many times and should thus be efficient computations. In addition they should always return the same result for the same input.

source§

impl Context

source

pub fn new(desc: ProgramDescription, config: Config) -> Self

Construct a Context from a ProgramDescription.

This also precomputes some data structures like an index over markers.

source

pub fn associated_call_site(&self, node: GlobalNode) -> CallString

👎Deprecated: Use NodeExt::associated_call_site instead

Find the call string for the statement or function that produced this node.

source

pub fn consuming_call_sites( &self, node: GlobalNode ) -> impl Iterator<Item = CallString> + '_

👎Deprecated: Use NodeQueries::consuming_call_sites instead

Call sites that consume this node directly. E.g. the outgoing edges.

source

pub fn controllers_by_name( &self, name: Identifier ) -> impl Iterator<Item = Endpoint> + '_

Find all controllers that bare this name.

This function is intended for use in writing test cases. Actual policies should generally refrain from working with controller names, other than printing them in error messages or for debugging. Policies contingent on controller names are likely unsound.

source

pub fn controller_by_name(&self, name: Identifier) -> Result<Endpoint>

Find a singular controller with this name.

This function should only be used in tests as the same caveats apply as in Self::controllers_by_name.

Returns Err

If there is not exactly one controller of this name.

source

pub fn find_by_name(&self, name: impl AsRef<str>) -> Result<DefId>

Find a type, controller or function id by its name.

Since many often share the same name this can fail with too many candidates. To handle such cases use Self::find_by_path or Self::find_all_by_name.

source

pub fn find_all_by_name(&self, name: impl AsRef<str>) -> Result<&[DefId]>

Find all types, controllers and functions with this name.

source

pub fn find_by_path(&self, path: impl AsRef<[Identifier]>) -> Result<DefId>

Find a type, controller or function with this path.

source

pub fn emit_diagnostics_may_exit(&self, w: impl Write) -> Result<()>

Dispatch and drain all queued diagnostics, aborts the program if any of them demand failure.

source

pub fn emit_diagnostics(&self, w: impl Write) -> Result<bool>

Dispatch and drain all queued diagnostics without aborting the program.

source

pub fn all_nodes(&self) -> impl Iterator<Item = GlobalNode> + '_

Returns all nodes that are in any of the PDGs

source

pub fn roots_where<'a>( &'a self, f: impl Fn(GlobalNode) -> bool + 'a ) -> impl Iterator<Item = GlobalNode> + 'a

Return nodes that satisfy the predicate and which have no ancestors that satisfy the same predicate.

source

pub fn report_marker_if_absent(&self, marker: Marker)

Emit a warning if this marker was not found in the source code.

source

fn build_index_on_markers( desc: &ProgramDescription ) -> HashMap<Marker, MarkerTargets>

source

fn build_flows_to(desc: &ProgramDescription) -> HashMap<Endpoint, CtrlFlowsTo>

source

pub fn flows_to( &self, src: impl IntoIterGlobalNodes, sink: impl IntoIterGlobalNodes, edge_type: EdgeSelection ) -> bool

👎Deprecated: Use NodeQueries::flows_to instead

Returns whether a node flows to a node through the configured edge type.

Nodes do not flow to themselves. CallArgument nodes do flow to their respective CallSites.

If you use flows_to with EdgeSelection::Control, you might want to consider using Context::has_ctrl_influence, which additionally considers intermediate nodes which the src node has data flow to and has ctrl influence on the sink.

source

pub fn nodes_marked_via_type( &self, marker: Marker ) -> impl Iterator<Item = GlobalNode> + '_

All nodes that have this marker through a type

source

pub fn nodes_marked_any_way( &self, marker: Marker ) -> impl Iterator<Item = GlobalNode> + '_

All nodes with this marker, be that via type or directly

source

pub fn controller_argument( &self, ctrl_id: Endpoint, index: u32 ) -> Option<GlobalNode>

Find the node that represents the indexth argument of the controller ctrl_id.

Returns None

If the controller with this id does not exist or the controller has fewer than index arguments.

source

pub fn has_ctrl_influence( &self, influencer: impl IntoIterGlobalNodes + Sized + Copy, target: impl IntoIterGlobalNodes + Sized + Copy ) -> bool

Returns whether there is direct control flow influence from influencer to sink, or there is some node which is data-flow influenced by influencer and has direct control flow influence on target. Or as expressed in code:

some n where self.flows_to(influencer, n, EdgeSelection::Data) && self.flows_to(n, target, EdgeSelection::Control).

source

pub fn influencers( &self, sink: impl IntoIterGlobalNodes + Sized, edge_type: EdgeSelection ) -> impl Iterator<Item = GlobalNode> + '_

Returns iterator over all Nodes that influence the given sink Node.

Does not return the input node. A CallSite sink will return all of the associated CallArgument nodes.

source

pub fn influencees( &self, src: impl IntoIterGlobalNodes + Sized, edge_type: EdgeSelection ) -> impl Iterator<Item = GlobalNode> + '_

Returns iterator over all Nodes that are influenced by the given src Node.

Does not return the input node. A CallArgument src will return the associated CallSite.

source

pub fn marked_nodes( &self, marker: Marker ) -> impl Iterator<Item = GlobalNode> + '_

Returns an iterator over all objects marked with marker.

source

pub fn get_node_types(&self, node: GlobalNode) -> &[DefId]

👎Deprecated: Use NodeExt::types instead

Get the type(s) of a Node.

source

pub fn has_marker(&self, marker: Marker, node: GlobalNode) -> bool

👎Deprecated: Use NodeExt::has_marker instead

Returns whether the given Node has the marker applied to it directly or via its type.

source

pub fn all_nodes_for_ctrl( &self, ctrl_id: Endpoint ) -> impl Iterator<Item = GlobalNode> + '_

Returns all DataSources, DataSinks, and CallSites for a Controller as Nodes.

source

pub fn srcs_with_type( &self, ctrl_id: Endpoint, t: DefId ) -> impl Iterator<Item = GlobalNode> + '_

Returns an iterator over the data sources within controller c that have type t.

source

pub fn roots( &self, ctrl_id: Endpoint, edge_type: EdgeSelection ) -> impl Iterator<Item = GlobalNode> + '_

Returns an iterator over all nodes that do not have any influencers of the given edge_type.

source

pub fn desc(&self) -> &ProgramDescription

Returns the input ProgramDescription.

source

pub fn otypes(&self, id: TypeId) -> &[TypeId]

Returns all the type alias annotation for a given type

source

pub fn marked_type(&self, marker: Marker) -> &[DefId]

Return all types that are marked with marker

source

pub fn any_flows( &self, from: &[GlobalNode], to: &[GlobalNode], edge_type: EdgeSelection ) -> Option<(GlobalNode, GlobalNode)>

Return an example pair for a flow from an source from from to a sink in to if any exist.

source

pub fn all_controllers(&self) -> impl Iterator<Item = (Endpoint, &SPDG)>

Iterate over all defined controllers

source

pub fn describe_def(&self, def_id: DefId) -> DisplayDef<'_>

Returns a DisplayDef for the given def_id

source

pub fn describe_node(&self, node: GlobalNode) -> DisplayNode<'_>

👎Deprecated: Use NodeExt::describe instead

Returns a DisplayNode for the given Node

source

pub fn inputs_of(&self, call_string: CallString) -> NodeCluster

Return which data is being read from for the modification performed at this location

source

pub fn outputs_of(&self, call_string: CallString) -> NodeCluster

Return which data is being written to at this location

source

pub fn node_info(&self, node: GlobalNode) -> &NodeInfo

👎Deprecated: Use NodeExt::info instead

Retrieve metadata about a node.

source

pub fn instruction_at_node(&self, node: GlobalNode) -> &InstructionInfo

Retrieve metadata about the instruction executed by a specific node.

source

pub fn successors( &self, node: GlobalNode ) -> impl Iterator<Item = GlobalNode> + '_

👎Deprecated: Use NodeExt::successors instead

Return the immediate successors of this node

source

pub fn predecessors( &self, node: GlobalNode ) -> impl Iterator<Item = GlobalNode> + '_

👎Deprecated: Use NodeExt::predecessors instead

Return the immediate predecessors of this node

source

pub fn get_location(&self, node: GlobalNode) -> &Span

👎Deprecated: Use NodeExt::get_location instead

Get the span of a node

source§

impl Context

source

pub fn named_policy<A>( self: Arc<Self>, name: impl Into<Identifier>, policy: impl FnOnce(Arc<PolicyContext>) -> A ) -> A

Add a policy to the diagnostic context.

See the module level documentation for more information on diagnostic context management.

source

pub fn named_controller<A>( self: Arc<Self>, id: Endpoint, policy: impl FnOnce(Arc<ControllerContext>) -> A ) -> A

Run the computation in the diagnostic context of this controller

See the module level documentation for more information on diagnostic context management.

source

pub fn named_combinator<A>( self: Arc<Self>, name: impl Into<Identifier>, computation: impl FnOnce(Arc<CombinatorContext>) -> A ) -> A

Nest another named combinator into the diagnostic context.

See the module level documentation for more information on diagnostic context management.

source

pub fn controller_contexts( self: &Arc<Self> ) -> impl Iterator<Item = Arc<ControllerContext>>

Iterate over all defined controllers as contexts

Trait Implementations§

source§

impl Debug for Context

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl HasDiagnosticsBase for Context

source§

fn record(&self, diagnostic: Diagnostic)

Record a diagnostic message.

source§

fn as_ctx(&self) -> &Context

Access to Context, usually also available via std::ops::Deref.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> Conv for T

source§

fn conv<T>(self) -> Twhere Self: Into<T>,

Converts self into T using Into<T>. Read more
source§

impl<T> Diagnostics for Twhere T: HasDiagnosticsBase,

source§

fn struct_error(&self, msg: impl Into<String>) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for an error. Read more
source§

fn struct_span_error( &self, span: impl Into<HighlightedSpan>, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for an error with a source code span. Read more
source§

fn struct_warning(&self, msg: impl Into<String>) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for a warning. Read more
source§

fn struct_span_warning( &self, span: impl Into<HighlightedSpan>, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for a warning with a source code span Read more
source§

fn struct_help(&self, msg: impl Into<String>) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for a help message.
source§

fn struct_span_help( &self, span: impl Into<HighlightedSpan>, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for a help message with a source code span
source§

fn struct_note(&self, msg: impl Into<String>) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for a note
source§

fn struct_span_note( &self, span: impl Into<HighlightedSpan>, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for a note with a source code span
source§

fn error(&self, msg: impl Into<String>)

Emit a message that is severe enough that it causes the policy to fail.
source§

fn warning(&self, msg: impl Into<String>)

Emit a message that indicates to the user that the policy might be fraudulent but could be correct.
source§

fn note(&self, msg: impl Into<String>)

Emit a message that provides additional information to the user.
source§

fn help(&self, msg: impl Into<String>)

Emit a message that suggests something to the user.
source§

fn span_error(&self, msg: impl Into<String>, span: Span)

Emit a message that is severe enough that it causes the policy to fail with a source code span.
source§

fn span_warning(&self, msg: impl Into<String>, span: Span)

Emit a message that indicates to the user that the policy might be fraudulent but could be correct. Includes a source code span.
source§

fn span_note(&self, msg: impl Into<String>, span: Span)

Emit a message that provides additional information to the user.
source§

fn span_help(&self, msg: impl Into<String>, span: Span)

Emit a message that suggests something to the user.
source§

fn struct_node_error( &self, node: GlobalNode, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for an error with the span of a graph node. Read more
source§

fn struct_node_warning( &self, node: GlobalNode, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for an error with the span of a graph node. Read more
source§

fn struct_node_note( &self, node: GlobalNode, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for an note with the span of a graph node.
source§

fn struct_node_help( &self, node: GlobalNode, msg: impl Into<String> ) -> DiagnosticBuilder<'_, Self>

Initialize a diagnostic builder for an help message with the span of a graph node.
source§

fn node_error(&self, node: GlobalNode, msg: impl Into<String>)

Emit an error, failing the policy, with the span of a graph node.
source§

fn node_warning(&self, node: GlobalNode, msg: impl Into<String>)

Emit an warning, that does not fail the policy, with the span of a graph node.
source§

fn node_note(&self, node: GlobalNode, msg: impl Into<String>)

Emit a note with the span of a graph node.
source§

fn node_help(&self, node: GlobalNode, msg: impl Into<String>)

Emit a help message with the span of a graph node.
source§

impl<T> FmtForward for T

source§

fn fmt_binary(self) -> FmtBinary<Self>where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
source§

fn fmt_display(self) -> FmtDisplay<Self>where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
source§

fn fmt_octal(self) -> FmtOctal<Self>where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
source§

fn fmt_pointer(self) -> FmtPointer<Self>where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
source§

fn fmt_list(self) -> FmtList<Self>where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Pipe for Twhere T: ?Sized,

source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> Rwhere Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R ) -> Rwhere Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> Rwhere Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> Rwhere Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> Rwhere Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R ) -> Rwhere Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
source§

impl<T> Tap for T

source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Selfwhere Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Selfwhere Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Selfwhere Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Selfwhere Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Selfwhere Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Selfwhere Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Selfwhere Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Selfwhere Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Selfwhere Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Selfwhere Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Selfwhere Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Selfwhere Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
source§

impl<T> TryConv for T

source§

fn try_conv<T>(self) -> Result<T, Self::Error>where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.