【问题标题】:Monitoring variable accesses in C/C++在 C/C++ 中监视变量访问
【发布时间】:2013-03-06 16:00:02
【问题描述】:

我正在研究多线程代码的覆盖率标准,作为其中的一部分,我想记录对变量的访问。例如,在下面的代码中,我想记录变量 x 被写入,y, z, a[i], 和 i 被读取。

x = y * (int)z + a[i]

我一直在考虑使用 Clang 的 RecursiveASTVisitor 并修改源以包含录制功能。但是,我不确定这是否是一种明智的方法,因为我对 Clang 工作原理的理解非常不完整。

目前,当我找到一个语句时,我会检查它是否是 BinaryOperator, UnaryOperator, Cast, or DeclRefExpr。 (一旦我掌握了基础知识,我将扩展它的功能。)如果它是BinaryOperator, UnaryOperator, or Cast,我会检查表达式的子表达式。如果它是 DeclRefExpr,我可以检查表达式是左值还是右值(再次,现在简化),但是一旦我找到 DeclRefExpr,它们总是左值。为了确定它们是否被用作lvalues or rvalues,我必须检查它的父级,如果它是左值或值转换,它被用作右值。

我觉得我对这个问题采取了错误的方法,因为我只能看到它变得更加复杂,因为我必须考虑更复杂的代码。

有没有更好的方法来解决这个问题?

谢谢

编辑

我不打算静态记录这些信息。我打算找到变量的用途并插入代码,这些代码将在代码运行时记录对这些变量的访问。

例如,给定上面的代码 (x = y * (int)z + a[i];),我想生成类似

x = y * (int)z + a[i];
recordAccess(<file>, <line>, "x",    &x,    WRITE);
recordAccess(<file>, <line>, "y",    &y,    READ);
recordAccess(<file>, <line>, "z",    &z,    READ);
recordAccess(<file>, <line>, "a[i]", &a[i], READ);
recordAccess(<file>, <line>, "i",    &i,    READ);

【问题讨论】:

  • 你想生产什么:*p=0; ?您希望如何找出被修改的变量名?
  • recordAccess(, , "*p", p, WRITE) 我想。
  • 这不会做你声称你想做的事。首先,它是对变量p访问。其次,它没有列出 p 指向的变量(或分配的堆块)。您将如何获得正确的变量覆盖?指针在 C 和 C++ 中都很常见。
  • 我不完全确定你的意思。我会记录正在读取 p 并且正在写入 *p 以及从其他访问 p 指向的地址我会知道哪些其他变量访问该内存。你能提供一个你所描述的例子吗?

标签: c++ c clang code-coverage


【解决方案1】:

正如其他人所指出的,别名使这成为不可能。不可能对代码进行静态分析来回答您感兴趣的问题。如果有可能获取源代码文件并仅通过分析语法来确定输出,那么编译器将生成结果程序的输出,而不是编译程序的输出。简而言之,您正在尝试回答halting problem

动态分析是您真正需要回答的最可能感兴趣的问题。多线程软件的动态分析已经有很大的市场。

【讨论】:

  • 为此实施动态分析也很困难(并非不可能,但也很困难)。本质上,您必须用数据访问收集机制替换每个编译单元中的每个指针访问,该机制可以以某种方式捕获引用实体的源代码位置。 (我们使用我们的 CheckPointer 工具来做到这一点 [唉,目前仅限于 C)。
  • 我同意!我想向 OP 指出的是,虽然他或她已经形成了一个理性且经过深思熟虑的问题状态,但要找到解决方案并不是那么简单。想要分析对内存区域的多线程访问是完全合乎逻辑的。然而,它并不像听起来那么简单。上次我看时,波特兰集团已经为这类事情开发了产品。然而,我从未有过与他们合作的乐趣。
【解决方案2】:

这里的主要问题是您没有考虑别名。您将只能记录简单、直接的访问。

但在这种情况下,一个简单的表达式 AST 访问者是主要的方法。但是 Clang 的 RecursiveASTVisitor 应该能够从记忆中为您减少废话并允许您直接访问最终的变量节点。毕竟,它应该访问每个 AST 节点。

【讨论】:

  • 您的第一条评论肯定是我需要解决的问题,但我从更基本的东西开始。虽然访问了每个 AST 节点,但我仍然不确定如何确定它是如何被使用的。例如,简单地检查其父节点是否为左值到右值转换就足够了吗?
  • @tgt:我不这么认为。考虑一个函数调用 foo(x),其中 x 定义为引用参数。 x 是读的还是写的?如果不检查 foo 的主体,您将无法判断(即使这样可能还不够,因为 foo 可能(图灵复杂)调用其他东西。为了增加您的复杂性, foo 的主体的定义可能不同编译单元;那你将如何检查它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
  • 2013-04-14
  • 2010-10-12
  • 1970-01-01
  • 2010-10-19
相关资源
最近更新 更多