Skip to content

Commit

Permalink
Review comments
Browse files Browse the repository at this point in the history
* Renaming parent call cas files
* Fixing recursive loops
  • Loading branch information
matt-sheets committed Feb 28, 2023
1 parent 2df9c24 commit a1de2f4
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 4 deletions.
File renamed without changes.
20 changes: 20 additions & 0 deletions data/error_policies/functions_no_term.cas
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
resource my_file {
fn read(domain source) {
allow(source, this, file, [ read open getattr ]);
other_read(source);
}

fn other_read(domain source) {
allow(source, this, file, [ read open getattr ]);
third_read(source);
}

fn third_read(domain source) {
allow(source, this, file, [ read open getattr ]);
read(source);
}
}

domain my_domain {
my_file.read(this); // TODO: support 'this' as default argument
}
24 changes: 24 additions & 0 deletions data/error_policies/functions_recursion.cas
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
resource my_file {
fn read(domain source) {
allow(source, this, file, [ read open getattr ]);
other_read(source);
}

fn other_read(domain source) {
allow(source, this, file, [ read open getattr ]);
third_read(source);
}

fn third_read(domain source) {
allow(source, this, file, [ read open getattr ]);
read(source);
}

fn term_read(domain source) {
allow(source, this, file, [ read open getattr ]);
}
}

domain my_domain {
my_file.read(this); // TODO: support 'this' as default argument
}
File renamed without changes.
File renamed without changes.
116 changes: 116 additions & 0 deletions src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,102 @@ pub fn determine_castable(functions: &mut FunctionMap, types: &TypeMap) -> u64 {
num_changed
}

pub fn initialize_terminated<'a>(
functions: &'a FunctionMap<'a>,
) -> (Vec<String>, Vec<FunctionInfo<'a>>) {
let mut term_ret_vec: Vec<String> = Vec::new();
let mut nonterm_ret_vec: Vec<FunctionInfo> = Vec::new();

for func in functions.values() {
let mut is_term = true;

for call in func.original_body {
if let Statement::Call(call) = call {
match call.check_builtin() {
Some(_) => {
continue;
}
None => {
is_term = false;
break;
}
}
}
}
if is_term {
term_ret_vec.push(func.get_cil_name().clone());
} else {
nonterm_ret_vec.push(func.clone());
}
}

(term_ret_vec, nonterm_ret_vec)
}

pub fn search_for_recursion(
terminated_list: &mut Vec<String>,
functions: &mut Vec<FunctionInfo>,
) -> Result<(), CascadeErrors> {
let mut removed: u64 = 1;
while removed > 0 {
removed = 0;
for func in functions.clone().iter_mut() {
let mut is_term = true;
for call in func.original_body {
if let Statement::Call(call) = call {
let mut call_cil_name = call.get_cil_name();
// If we are calling something with this it must be in the same class
// so hand place the class name
if call_cil_name.contains("this-") {
if let Some(class) = func.class {
call_cil_name =
call_cil_name.replace("this-", &(class.name.to_string() + "-"))
} else {
return Err(CascadeErrors::from(ErrorItem::make_compile_or_internal_error(
"Could not determine class for 'this.' function call",
Some(func.declaration_file),
call.get_name_range(),
"Perhaps you meant to place the function in a resource or domain?")));
}
}

if terminated_list.contains(&call_cil_name) {
continue;
}
is_term = false;
}
}
if is_term {
terminated_list.push(func.get_cil_name());
removed += 1;
let index = functions
.iter()
.position(|x| *x.get_cil_name() == func.get_cil_name())
.unwrap();
functions.remove(index);
}
}
}

if !functions.is_empty() {
let mut error: Option<CompileError> = None;

for func in functions {
error = Some(add_or_create_compile_error(
error,
"Recursive Function call found",
func.declaration_file,
func.get_declaration_range().unwrap_or_default(),
"Calls cannot recursively call each other",
));
}
// Unwrap is safe since we need to go through the loop above at least once
return Err(CascadeErrors::from(error.unwrap()));
}

Ok(())
}

pub fn prevalidate_functions(
functions: &mut FunctionMap,
types: &TypeMap,
Expand All @@ -531,6 +627,26 @@ pub fn prevalidate_functions(
num_changed = determine_castable(functions, types);
}

let (mut terminated_functions, mut nonterm_functions) = initialize_terminated(functions);

if terminated_functions.is_empty() && !nonterm_functions.is_empty() {
let mut error: Option<CompileError> = None;

for func in functions.values() {
error = Some(add_or_create_compile_error(
error,
"No terminating call found",
func.declaration_file,
func.get_declaration_range().unwrap_or_default(),
"All function calls found in possible recursive loop",
));
}
// Unwrap is safe since we need to go through the loop above at least once
return Err(CascadeErrors::from(error.unwrap()));
}

search_for_recursion(&mut terminated_functions, &mut nonterm_functions)?;

Ok(())
}

Expand Down
18 changes: 14 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1376,8 +1376,8 @@ mod tests {
}

#[test]
fn invalid_parent_call() {
error_policy_test!("parent_call.cas", 6, ErrorItem::Compile(_));
fn invalid_call_casting() {
error_policy_test!("call_casting.cas", 6, ErrorItem::Compile(_));
}

#[test]
Expand All @@ -1386,9 +1386,9 @@ mod tests {
}

#[test]
fn valid_parent_call() {
fn valid_call_casting() {
valid_policy_test(
"parent_call.cas",
"call_casting.cas",
&[
"call bar-read (foo dom)",
"call bar-foobar (foo dom)",
Expand All @@ -1401,4 +1401,14 @@ mod tests {
0,
);
}

#[test]
fn invalid_function_recursion_test() {
error_policy_test!("functions_recursion.cas", 1, ErrorItem::Compile(_));
}

#[test]
fn invalid_function_noterm_test() {
error_policy_test!("functions_no_term.cas", 1, ErrorItem::Compile(_));
}
}

0 comments on commit a1de2f4

Please sign in to comment.