如何获得使用递归的警告?

时间:2017-07-19 15:08:03

标签: c gcc recursion clang

嵌入式软件开发的一些规则集和指南完全禁止递归。我将arm-none-eabi-gcc与基于ARM Cortex-M4的微控制器一起使用。

我正在寻找一个静态分析工具,它会警告我在代码中使用递归。我对这些工具的经验不多。是否可以使用clang-tidy或clang静态分析仪?如果是,我如何配置它们以警告递归?

(快速查看gcc option summary告诉我,单凭gcc无法做到这一点。)

注:

  • 请不要告诉我"只是不要递归" 。代码库很大而不是我自己。我希望能够证明其中没有递归 (这就像说"只是没有取消引用空指针" 。虽然没有人故意这样做,但工具存在的原因是为了验证它没有发生。)

3 个答案:

答案 0 :(得分:3)

这可以使用Clang生成的调用图数据来解决。

步骤1.使用clang:

生成调用图信息
clang -S -emit-llvm SourceFile.c -o - | opt -analyze -print-callgraph 

(来自Generate calling graph for C++ code,将-dot-callgraph替换为-print-callgraph。)

输入如下:

void a(){}
void b(){a();}
void c(){a(); b();}
void d(){a(); c();}
void e(){e();}

这会产生:

CallGraph Root is: <<null function: 0x0x7fdef25036c0>>
Call graph node <<null function>><<0x7fdef25036c0>>  #uses=0
  CS<0x0> calls function 'a'
  CS<0x0> calls function 'b'
  CS<0x0> calls function 'c'
  CS<0x0> calls function 'd'

Call graph node for function: 'a'<<0x7fdef2503750>>  #uses=4

Call graph node for function: 'b'<<0x7fdef25037d0>>  #uses=2
  CS<0x7fdef2500a38> calls function 'a'

Call graph node for function: 'c'<<0x7fdef2503870>>  #uses=2
  CS<0x7fdef2500cb8> calls function 'a'
  CS<0x7fdef2500d28> calls function 'b'

Call graph node for function: 'd'<<0x7fdef2503970>>  #uses=1
  CS<0x7fdef2500fe8> calls function 'a'
  CS<0x7fdef2501058> calls function 'c'

Call graph node for function: 'e'<<0x7f8912d03c10>>  #uses=2
  CS<0x7f8912d01318> calls function 'e'

(在C ++中,可以使用c++filt清除损坏的函数名称;模板变得丑陋但是可行。)使用该数据,可以勾画出如何检测递归:

步骤2.将调用图数据解析为喜欢的脚本语言,以形成调用图的表示。

class Graph(object):

  _callees = []

  def add_callee(self, f):
    self._callees.append(f)
    # etc

步骤3.对于每个函数,步行图寻找对该函数的调用。有点像这样:

def walkGraph(node,f,stack):
  for callee in node._callees:
    if f == callee:
      print('Recursion!')
      dumpStack(stack,f)
    else:
      walkGraph(callee,f,stack.append(node))

答案 1 :(得分:1)

//@version=4 var maxBarsBack = 2000 study("zones", overlay=true, max_bars_back=maxBarsBack) // define a basing and explosive candles basing_candle = ((abs(close - open)/abs(high - low)) < 0.5) explosive_candle = (abs(close-open) / abs(high - low)) >= 0.5 and tr>tr[1] // functions bc_r = basing_candle and close < open ex_g = explosive_candle and close > open // demand zone demand_zone = bc_r[1] and ex_g and low>=low[1] and close>open[1] line l1 = na line l2 = na dz = if demand_zone and barstate.isconfirmed l1 := line.new(x1 = bar_index[1] ,y1=open[1], x2=bar_index, y2= open[1], style=line.style_solid, extend=extend.right, color=color.green, width=2) l2 := line.new(x1 = bar_index[1] ,y1=low[1], x2=bar_index, y2= low[1], style=line.style_solid, extend=extend.right, color=color.green, width= 2) for i = 1 to maxBarsBack if not na(l1[i]) and close < low[i] // We have identified a bar where a line was created. line.delete(l1[i]) line.delete(l2[i]) 在版本11中学会了检测。

https://clang.llvm.org/extra/clang-tidy/checks/misc-no-recursion.html

答案 2 :(得分:0)

您可以调查生成调用树的工具。他们可能有一个检测递归的选项,包括相互递归,否则你可以修补一个以获得你想要的功能。

See this reponse

来自Roguewave软件的这个商业工具:TotalView