#This script is designed to run with Understand - CodeCheck use base qw(Understand::Codecheck); use strict; use constant ERR1 => 'Violation: function "%1" is directly recursive, which is unsafe.'; use constant ERR2 => 'Violation: function "%1" is indirectly recursive through "%2", which is unsafe.'; sub register_tr_text { my $check = shift; $check->add_tr_text(ERR1); $check->add_tr_text(ERR2); } sub name { '16.2 No direct or indirect recursion allowed.' } sub description { '16.2 (Required) Functions shall not call themselves, either directly or indirectly.' } sub detailed_description { <<'END_DESC' This means that recursive function calls cannot be used in safety-related systems. Recursion carries with it the danger of exceeding available stack space, which can be a serious error. Unless recursion is very tightly controlled, it is not possible to determine before execution what the worst-case stack usage could be. END_DESC } sub test_language { my $language = shift; return $language eq 'C++'; } sub test_entity { 1 } sub test_global { 0 } sub define_options { } sub discoverRecursion { my $check = shift; my $ent = shift; my $firstTime = do { @_ ? shift : 1 }; # to detect "directly recursive" my $seen = do { @_ ? shift : {} }; my $originalEnt = do { @_ ? shift : $ent }; return unless $ent->kind->check('function'); foreach my $callRef ($ent->refs('call', 'function', 1)) { my $callEnt = $callRef->ent; ++$seen->{$callEnt->uniquename}; next if $seen->{$callEnt->uniquename} > 1; if ($callEnt->uniquename eq $originalEnt->uniquename) { my $ref = $callRef->ent->ref; if ($firstTime){ $check->violation($originalEnt, $ref->file, $ref->line, $ref->column, ERR1, $originalEnt->longname); }else{ $check->violation($originalEnt, $ref->file, $ref->line, $ref->column, ERR2, $originalEnt->longname, $ent->longname); } return; } discoverRecursion($check, $callEnt, 0, $seen, $originalEnt); } return; } sub check { my $check = shift; my $file = shift; return unless $file->kind->check('file'); foreach my $ref ($file->filerefs('define', 'function', 1)) { my $ent = $ref->ent; discoverRecursion($check, $ent); } return; }