@@ -520,6 +520,102 @@ pub fn determine_castable(functions: &mut FunctionMap, types: &TypeMap) -> u64 {
520
520
num_changed
521
521
}
522
522
523
+ pub fn initialize_terminated < ' a > (
524
+ functions : & ' a FunctionMap < ' a > ,
525
+ ) -> ( Vec < String > , Vec < FunctionInfo < ' a > > ) {
526
+ let mut term_ret_vec: Vec < String > = Vec :: new ( ) ;
527
+ let mut nonterm_ret_vec: Vec < FunctionInfo > = Vec :: new ( ) ;
528
+
529
+ for func in functions. values ( ) {
530
+ let mut is_term = true ;
531
+
532
+ for call in func. original_body {
533
+ if let Statement :: Call ( call) = call {
534
+ match call. check_builtin ( ) {
535
+ Some ( _) => {
536
+ continue ;
537
+ }
538
+ None => {
539
+ is_term = false ;
540
+ break ;
541
+ }
542
+ }
543
+ }
544
+ }
545
+ if is_term {
546
+ term_ret_vec. push ( func. get_cil_name ( ) . clone ( ) ) ;
547
+ } else {
548
+ nonterm_ret_vec. push ( func. clone ( ) ) ;
549
+ }
550
+ }
551
+
552
+ ( term_ret_vec, nonterm_ret_vec)
553
+ }
554
+
555
+ pub fn search_for_recursion (
556
+ terminated_list : & mut Vec < String > ,
557
+ functions : & mut Vec < FunctionInfo > ,
558
+ ) -> Result < ( ) , CascadeErrors > {
559
+ let mut removed: u64 = 1 ;
560
+ while removed > 0 {
561
+ removed = 0 ;
562
+ for func in functions. clone ( ) . iter_mut ( ) {
563
+ let mut is_term = true ;
564
+ for call in func. original_body {
565
+ if let Statement :: Call ( call) = call {
566
+ let mut call_cil_name = call. get_cil_name ( ) ;
567
+ // If we are calling something with this it must be in the same class
568
+ // so hand place the class name
569
+ if call_cil_name. contains ( "this-" ) {
570
+ if let Some ( class) = func. class {
571
+ call_cil_name =
572
+ call_cil_name. replace ( "this-" , & ( class. name . to_string ( ) + "-" ) )
573
+ } else {
574
+ return Err ( CascadeErrors :: from ( ErrorItem :: make_compile_or_internal_error (
575
+ "Could not determine class for 'this.' function call" ,
576
+ Some ( func. declaration_file ) ,
577
+ call. get_name_range ( ) ,
578
+ "Perhaps you meant to place the function in a resource or domain?" ) ) ) ;
579
+ }
580
+ }
581
+
582
+ if terminated_list. contains ( & call_cil_name) {
583
+ continue ;
584
+ }
585
+ is_term = false ;
586
+ }
587
+ }
588
+ if is_term {
589
+ terminated_list. push ( func. get_cil_name ( ) ) ;
590
+ removed += 1 ;
591
+ let index = functions
592
+ . iter ( )
593
+ . position ( |x| * x. get_cil_name ( ) == func. get_cil_name ( ) )
594
+ . unwrap ( ) ;
595
+ functions. remove ( index) ;
596
+ }
597
+ }
598
+ }
599
+
600
+ if !functions. is_empty ( ) {
601
+ let mut error: Option < CompileError > = None ;
602
+
603
+ for func in functions {
604
+ error = Some ( add_or_create_compile_error (
605
+ error,
606
+ "Recursive Function call found" ,
607
+ func. declaration_file ,
608
+ func. get_declaration_range ( ) . unwrap_or_default ( ) ,
609
+ "Calls cannot recursively call each other" ,
610
+ ) ) ;
611
+ }
612
+ // Unwrap is safe since we need to go through the loop above at least once
613
+ return Err ( CascadeErrors :: from ( error. unwrap ( ) ) ) ;
614
+ }
615
+
616
+ Ok ( ( ) )
617
+ }
618
+
523
619
pub fn prevalidate_functions (
524
620
functions : & mut FunctionMap ,
525
621
types : & TypeMap ,
@@ -531,6 +627,26 @@ pub fn prevalidate_functions(
531
627
num_changed = determine_castable ( functions, types) ;
532
628
}
533
629
630
+ let ( mut terminated_functions, mut nonterm_functions) = initialize_terminated ( functions) ;
631
+
632
+ if terminated_functions. is_empty ( ) && !nonterm_functions. is_empty ( ) {
633
+ let mut error: Option < CompileError > = None ;
634
+
635
+ for func in functions. values ( ) {
636
+ error = Some ( add_or_create_compile_error (
637
+ error,
638
+ "No terminating call found" ,
639
+ func. declaration_file ,
640
+ func. get_declaration_range ( ) . unwrap_or_default ( ) ,
641
+ "All function calls found in possible recursive loop" ,
642
+ ) ) ;
643
+ }
644
+ // Unwrap is safe since we need to go through the loop above at least once
645
+ return Err ( CascadeErrors :: from ( error. unwrap ( ) ) ) ;
646
+ }
647
+
648
+ search_for_recursion ( & mut terminated_functions, & mut nonterm_functions) ?;
649
+
534
650
Ok ( ( ) )
535
651
}
536
652
0 commit comments