1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
use crate::{abstract_domain::AbstractDomain, prelude::*};
use std::fmt::Display;
/// Access flags to track different kind of access/usage patterns of a variable.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct AccessPattern {
/// The variable was used in the computation of a pointer that was dereferenced for reading a value.
dereferenced: bool,
/// The variable was accessed to compute some nontrivial value
/// or the value was stored in some location.
read: bool,
/// The variable was used in the computation of a pointer that was dereferenced for writing a value.
mutably_dereferenced: bool,
}
impl AccessPattern {
/// Generate a new `AccessPattern` object with none of the access flags set.
pub fn new() -> Self {
Self {
dereferenced: false,
read: false,
mutably_dereferenced: false,
}
}
/// Generate a new `AccessPattern` object with all access flags set to true (to model unknown access).
pub fn new_unknown_access() -> Self {
Self {
dereferenced: true,
read: true,
mutably_dereferenced: true,
}
}
/// Set the access flag for read access and return `self`.
pub fn with_read_flag(mut self) -> Self {
self.read = true;
self
}
/// Set the access flag for immutable pointer dereference and return `self`.
pub fn with_dereference_flag(mut self) -> Self {
self.dereferenced = true;
self
}
/// Set the access flag for pointer dereference with write access to the pointer target and return `self`.
pub fn with_mutably_dereferenced_flag(mut self) -> Self {
self.mutably_dereferenced = true;
self
}
/// Set the access flag for immutable pointer dereference.
pub fn set_dereference_flag(&mut self) {
self.dereferenced = true;
}
/// Set the access flag for read access.
pub fn set_read_flag(&mut self) {
self.read = true;
}
/// Set the access flag for pointer dereference (with write access to the target of the pointer).
pub fn set_mutably_dereferenced_flag(&mut self) {
self.mutably_dereferenced = true;
}
/// Set all access flags to indicate that any kind of access to the variable may have occured.
pub fn set_unknown_access_flags(&mut self) {
self.read = true;
self.dereferenced = true;
self.mutably_dereferenced = true;
}
/// Returns true if any of the access flags is set.
pub fn is_accessed(&self) -> bool {
self.read || self.dereferenced || self.mutably_dereferenced
}
/// Returns true if the dereferenced or mutably dereferenced access flag is set.
pub fn is_dereferenced(&self) -> bool {
self.dereferenced || self.mutably_dereferenced
}
/// Returns true if the mutably dereferenced access flag is set.
pub fn is_mutably_dereferenced(&self) -> bool {
self.mutably_dereferenced
}
}
impl Default for AccessPattern {
fn default() -> Self {
Self::new()
}
}
impl AbstractDomain for AccessPattern {
/// An access flag in the merged `AccessPattern` object is set
/// if it is set in at least one of the input objects.
fn merge(&self, other: &Self) -> Self {
AccessPattern {
dereferenced: self.dereferenced || other.dereferenced,
read: self.read || other.read,
mutably_dereferenced: self.mutably_dereferenced || other.mutably_dereferenced,
}
}
/// Returns true if all of the access flags are set.
fn is_top(&self) -> bool {
self.read && self.dereferenced && self.mutably_dereferenced
}
}
impl Display for AccessPattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.read {
write!(f, "r")?;
} else {
write!(f, "-")?;
}
if self.dereferenced {
write!(f, "d")?;
} else {
write!(f, "-")?;
}
if self.mutably_dereferenced {
write!(f, "w")?;
} else {
write!(f, "-")?;
}
Ok(())
}
}