From d700693a5fba90f09c3d853867a965ea4741feb0 Mon Sep 17 00:00:00 2001 From: Jan Schlosser Date: Thu, 18 Jun 2026 16:57:39 +0200 Subject: [PATCH] RULE-8-2-10: Avoid callers of recursive functions being flagged The rule forbids only recursive functions. It can be fair to have a recursive function and justify this within one. With the behavior before this change, also every caller would need to be argued. This is additonal burden that is not required and intended by the MISRA standard. Fixes #935 --- c/misra/test/rules/RULE-17-2/test.c | 2 +- change_notes/2026-06-18-fix-fp-recursive-functions.md | 2 ++ .../FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll | 2 +- ...tionsCallThemselvesEitherDirectlyOrIndirectly.expected | 7 +++---- .../test.cpp | 8 +++++++- 5 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 change_notes/2026-06-18-fix-fp-recursive-functions.md diff --git a/c/misra/test/rules/RULE-17-2/test.c b/c/misra/test/rules/RULE-17-2/test.c index 800921c1e2..649fb34cfa 100644 --- a/c/misra/test/rules/RULE-17-2/test.c +++ b/c/misra/test/rules/RULE-17-2/test.c @@ -8,7 +8,7 @@ void f3() { f3(); // NON_COMPLIANT } void f6() { - f3(); // NON_COMPLIANT + f3(); // COMPLIANT - merely calls a recursive function } void f5() { diff --git a/change_notes/2026-06-18-fix-fp-recursive-functions.md b/change_notes/2026-06-18-fix-fp-recursive-functions.md new file mode 100644 index 0000000000..07a12f8602 --- /dev/null +++ b/change_notes/2026-06-18-fix-fp-recursive-functions.md @@ -0,0 +1,2 @@ +`A7-5-2`, `RULE-8-2-10`: `FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql`: + - Fix false positives where callers of recursive functions were incorrectly reported as recursive. Only calls that participate in a recursive cycle are now reported. diff --git a/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll b/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll index e54e4378e9..33c16ceb70 100644 --- a/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll +++ b/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll @@ -23,7 +23,7 @@ class RecursiveFunction extends Function { RecursiveFunction() { exists(RecursiveCall fc | fc.getEnclosingFunction() = this) } } -query predicate problems(FunctionCall fc, string message, RecursiveFunction f, string functionName) { +query predicate problems(RecursiveCall fc, string message, Function f, string functionName) { not isExcluded(fc, getQuery()) and f = fc.getTarget() and functionName = f.getName() and diff --git a/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.expected b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.expected index 5dbc78c6f6..63542dac08 100644 --- a/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.expected +++ b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.expected @@ -1,5 +1,4 @@ | test.cpp:7:13:7:35 | call to test_recursive_function | This call directly invokes its containing function $@. | test.cpp:5:5:5:27 | test_recursive_function | test_recursive_function | -| test.cpp:21:9:21:31 | call to test_recursive_function | The function test_indirect_recursive_function is indirectly recursive via this call to $@. | test.cpp:5:5:5:27 | test_recursive_function | test_recursive_function | -| test.cpp:27:5:27:30 | call to test_indirect_recursive_f2 | The function test_indirect_recursive_f1 is indirectly recursive via this call to $@. | test.cpp:36:5:36:30 | test_indirect_recursive_f2 | test_indirect_recursive_f2 | -| test.cpp:38:9:38:34 | call to test_indirect_recursive_f1 | The function test_indirect_recursive_f2 is indirectly recursive via this call to $@. | test.cpp:25:5:25:30 | test_indirect_recursive_f1 | test_indirect_recursive_f1 | -| test.cpp:75:10:75:19 | call to operator== | This call directly invokes its containing function $@. | test.cpp:74:6:74:15 | operator== | operator== | +| test.cpp:33:5:33:30 | call to test_indirect_recursive_f2 | The function test_indirect_recursive_f1 is indirectly recursive via this call to $@. | test.cpp:42:5:42:30 | test_indirect_recursive_f2 | test_indirect_recursive_f2 | +| test.cpp:44:9:44:34 | call to test_indirect_recursive_f1 | The function test_indirect_recursive_f2 is indirectly recursive via this call to $@. | test.cpp:31:5:31:30 | test_indirect_recursive_f1 | test_indirect_recursive_f1 | +| test.cpp:81:10:81:19 | call to operator== | This call directly invokes its containing function $@. | test.cpp:80:6:80:15 | operator== | operator== | diff --git a/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/test.cpp b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/test.cpp index b51b8fa991..c22dac0980 100644 --- a/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/test.cpp +++ b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/test.cpp @@ -18,10 +18,16 @@ int test_nonrecursive_function(int i) { // COMPLIANT int test_indirect_recursive_function(int i) { if (i > 10) { - i = test_recursive_function(i * i); // NON_COMPLIANT + i = test_recursive_function( + i * i); // COMPLIANT - merely calls a recursive function } } +int test_calls_recursive_function(int i) { + return test_recursive_function( + i); // COMPLIANT - not part of a recursive cycle +} + int test_indirect_recursive_f1(int i) { if (i > 10) { test_indirect_recursive_f2(i + i); // NON_COMPLIANT