博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
pvs-stdio ue4_使用PVS-Studio检查GCC 10编译器
阅读量:2516 次
发布时间:2019-05-11

本文共 18926 字,大约阅读时间需要 63 分钟。

pvs-stdio ue4

PVS-Studo vs GCC 10

The GCC compiler is written with copious use of macros. Another check of the GCC code using PVS-Studio once again confirms the opinion of our team that macros are evil in the flesh. Not only does the static analyzer struggle with reviewing such code, but also a developer. GCC developers are certainly used to the project and are well versed in it. Nonetheless, it is very difficult to understand something on the third hand. Actually, due to macros, it was not possible to fully perform code checking. However, the PVS-Studio analyzer, as always, showed that it can find errors even in compilers.

GCC编译器是使用大量宏编写的。 使用PVS-Studio对GCC代码进行的另一次检查再次证实了我们团队的观点,即宏在肉体中是邪恶的。 静态分析器不仅要审查此类代码,而且还要让开发人员费劲。 GCC开发人员当然已经习惯了该项目,并且非常熟悉该项目。 但是,很难从第三手理解某些东西。 实际上,由于宏,无法完全执行代码检查。 但是,PVS-Studio分析仪一如既往地表明,即使在编译器中,它也可以发现错误。

是时候再次检查GCC编译器代码 (Time to Double-Check the GCC Compiler Code)

The last time I the GCC compiler four years ago. Time flies quickly and imperceptibly, and somehow I completely forgot to return to this project and recheck it. The post "" pushed me back to this idea.

四年前,我上次 GCC编译器。 时间过得很快而且潜移默化,以某种方式,我完全忘记了返回这个项目并重新检查它。 文章“ ”使我回到了这个想法。

Actually, it is no secret that compilers have their own built-in static code analyzers and they are also developing. Therefore, from time to time we write articles that the PVS-Studio static analyzer can find errors even inside compilers and that we are worth our salt :).

实际上,编译器具有自己的内置静态代码分析器,并且还在开发中,这已经不是什么秘密了。 因此,我们不时撰写文章,说PVS-Studio静态分析器甚至在编译器内部也可以发现错误,我们值得我们付出很多努力:)。

In fact, one can't compare classic static analyzers with compilers. Static analyzer is not only a search for errors in the code, but also a developed infrastructure. For example, it is also integration with such systems as SonarQube, PlatformIO, Azure DevOps, Travis CI, CircleCI, GitLab CI/CD, Jenkins, Visual Studio. In addition, it is mechanisms of mass warnings suppression, which allows you to quickly start using PVS-Studio even in a large old project. It is a notification mailing list. And it's just to name a few. However, anyway, the first question is: «Can PVS-Studio find something that compilers can't?» Which means that we will write articles over and over again about checking these compilers themselves.

实际上,无法将经典的静态分析器与编译器进行比较。 静态分析器不仅可以搜索代码中的错误,而且还可以开发出基础架构。 例如,它还与SonarQube,PlatformIO,Azure DevOps,Travis CI,CircleCI,GitLab CI / CD,Jenkins,Visual Studio等系统集成。 此外,它是批量警告抑制的机制,它使您即使在大型旧项目中也可以快速开始使用PVS-Studio。 这是一个通知邮件列表。 仅举几例。 但是,无论如何,第一个问题是:“ PVS-Studio可以找到编译器无法找到的东西吗?” 这意味着我们将一再地撰写有关检查这些编译器本身的文章。

Let's get back to the GCC project check. There is no need to dwell on this project and tell what it is. Let's better talk what's inside of this project.

让我们回到GCC项目检查中。 无需深入研究该项目并告诉它是什么。 让我们更好地谈谈该项目的内容。

Inside there is a huge number of macros that interfere with the check. Firstly, the PVS-Studio analyzer generates a large number of false positives. There is nothing wrong about that, but it's not easy to take and start reviewing the resulting report. In a good way, one has to take the effort to suppress false warnings in macros. Otherwise, useful warnings are drowning in a flood of noise. This setup goes beyond the scope of this article. Frankly speaking, I was just too lazy to do this, even though . Due to the noise, viewing the report was quite superficial.

内部有大量的宏会干扰检查。 首先,PVS-Studio分析仪会产生大量误报。 这没有什么错,但是要开始查看结果报告并不容易。 以一种好的方式,必须努力抑制宏中的错误警告。 否则,有用的警告会淹没在大量的噪音中。 此设置超出了本文的范围。 坦率地说,即使这样做事,我还是懒得做。 由于噪音,查看报告是很肤浅的。

Secondly, it is very challenging for me, a person who is not familiar with the project, to understand the code. Macros, macros… I have to check out what they are expanding into in order to understand why the analyzer generates warnings. Very hard. . Someone might say that you can't do without macros in C. But GCC has not been written in C for a while. For historical reasons, files do have the extension .c. At the same time, if we look inside we'll see the following:

其次,对于我(一个不熟悉该项目的人)来说,理解代码非常具有挑战性。 宏,宏……我必须检查它们的扩展内容,以了解分析仪为何生成警告。 很难。 。 有人可能会说您不能在C中没有宏。但是GCC已有一段时间没有用C编写了。 由于历史原因,文件确实具有扩展名.c。 同时,如果我们查看内部,将会看到以下内容:

// File alias.c....struct alias_set_hash : int_hash 
{};struct GTY(()) alias_set_entry { alias_set_type alias_set; bool has_zero_child; bool is_pointer; bool has_pointer; hash_map
*children;};....

This is clearly not C, but C++.

显然这不是C,而是C ++。

In short, macros and coding style make it very tricky to deal with the analyzer report. So this time I will not please the reader with a long list of various errors. Thanks to a few cups of coffee I highlighted 10 interesting fragments right by the skin of my teeth. At that point, I grew weary of that :).

简而言之,宏和编码风格使处理分析器报告变得非常棘手。 因此,这次我将不为读者提供各种错误的清单。 多亏了几杯咖啡,我在牙齿的皮肤上突出显示了10个有趣的碎片。 那时,我对此感到厌倦:)。

10个可疑代码片段 (10 Suspicious Code Fragments)

片段N1,似乎复制粘贴失败 (Fragment N1, Seems like failed Copy-Paste)

static booltry_crossjump_to_edge (int mode, edge e1, edge e2,                       enum replace_direction dir){  ....  if (FORWARDER_BLOCK_P (s->dest))    s->dest->count += s->count ();  if (FORWARDER_BLOCK_P (s2->dest))    s2->dest->count -= s->count ();  ....}

PVS-Studio warning: V778 Two similar code fragments were found. Perhaps, this is a typo and 's2' variable should be used instead of 's'. cfgcleanup.c 2126

PVS-Studio警告:V778找到两个相似的代码片段。 也许这是一个错字,应该使用“ s2”变量代替“ s”。 cfgcleanup.c 2126

If I am honest, I'm not sure that this is an error. However, I have a strong suspicion that this code was written using Copy-Paste, and in the second block in one place they forgot to replace

老实说,我不确定这是一个错误。 但是,我强烈怀疑此代码是使用Copy-Paste编写的,在第二个块中的一个地方,他们忘记了替换

s (s)

with

s2 (s2)

. That is, it seems to me the second block of code should be like this:

。 也就是说,在我看来,第二段代码应该是这样的:

if (FORWARDER_BLOCK_P (s2->dest))  s2->dest->count -= s2->count ();

片段N2,错字 (Fragment N2, Typo)

treevn_reference_lookup_pieces (....){  struct vn_reference_s vr1;  ....  vr1.set = set;  vr1.set = base_set;  ....}

PVS-Studio warning: V519 The 'vr1.set' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 3448, 3449. tree-ssa-sccvn.c 3449

PVS-Studio警告:V519“ vr1.set”变量已连续两次分配值。 也许这是一个错误。 检查行:3448、3449。tree-ssa-sccvn.c 3449

It is very strange that different values are written into the same variable twice in a row. This is an obvious typo. Right in this file, next to the above there is the following code:

奇怪的是,不同的值连续两次写入同一变量。 这是一个明显的错别字。 在此文件中,紧挨着上面的是以下代码:

vr1.set = set;vr1.base_set = base_set;

Most likely, the suspicious code fragment should also look like this one.

可疑代码片段很可能也应该像这样。

片段N3,为其分配变量 (Fragment N3, Assigning a variable to itself)

static omp_context *new_omp_context (gimple *stmt, omp_context *outer_ctx){  omp_context *ctx = XCNEW (omp_context);  splay_tree_insert (all_contexts, (splay_tree_key) stmt,         (splay_tree_value) ctx);  ctx->stmt = stmt;  if (outer_ctx)    {      ctx->outer = outer_ctx;      ctx->cb = outer_ctx->cb;      ctx->cb.block = NULL;      ctx->local_reduction_clauses = NULL;      ctx->outer_reduction_clauses = ctx->outer_reduction_clauses;  // <=      ctx->depth = outer_ctx->depth + 1;    }  ....}

PVS-Studio warning: V570 The 'ctx->outer_reduction_clauses' variable is assigned to itself. omp-low.c 935

PVS-Studio警告:V570为其自身分配了'ctx-> outer_reduction_clauses'变量。 omp-low.c 935

It is very strange to assign a variable to itself.

给自己分配一个变量很奇怪。

片段N4。 0,1,2,弗雷迪(Freddy)为您而来。 (Fragment N4. 0,1,2, Freddy is coming for you.)

I recently posted an article "". It seems to me that the following code fragment enlarges the collection of errors discussed in that article.

我最近发表了一篇文章“ ”。 在我看来,以下代码片段扩大了该文章中讨论的错误的集合。

#define GET_MODE(RTX)    ((machine_mode) (RTX)->mode)....static intadd_equal_note (rtx_insn *insns, rtx target, enum rtx_code code, rtx op0,                rtx op1, machine_mode op0_mode){  ....  if (commutative_p      && GET_MODE (xop0) != xmode0 && GET_MODE (xop1) != xmode1      && GET_MODE (xop0) == xmode1 && GET_MODE (xop1) == xmode1)    std::swap (xop0, xop1);  ....}

PVS-Studio warning: V560 A part of conditional expression is always false: ((machine_mode)(xop1)->mode) == xmode1. optabs.c 1053

PVS-Studio警告:V560条件表达式的一部分始终为false:((machine_mode)(xop1)-> mode)== xmode1。 optabs.c 1053

Pay attention to these two subexpressions:

请注意以下两个子表达式:

  • GET_MODE (xop1) != xmode1

    GET_MODE(xop1)!= xmode1
  • GET_MODE (xop1) == xmode1

    GET_MODE(xop1)== xmode1

The AND operation is performed on the results of these subexpressions, which obviously has no practical meaning. Actually, if the second subexpression gets executed, then we know in advance that it will result in false.

对这些子表达式的结果执行“与”运算,这显然没有任何实际意义。 实际上,如果执行了第二个子表达式,则我们预先知道它将导致false

Most likely, there is a typo here in zeros and ones, and in fact the condition should have been like this:

最有可能的是,这里的错字是零和一,实际上情况应该是这样的:

&& GET_MODE (xop0) != xmode0 && GET_MODE (xop1) != xmode1&& GET_MODE (xop0) == xmode1 && GET_MODE (xop1) == xmode0

Of course, I'm not sure that I changed the code correctly, since I have not taken the project apart.

当然,我不确定是否正确更改了代码,因为我没有拆分项目。

片段N5。 参数值可疑更改 (Fragment N5. Suspicious change in the argument value)

boolipa_polymorphic_call_context::set_by_invariant (tree cst,                                                tree otr_type,                                                HOST_WIDE_INT off){  poly_int64 offset2, size, max_size;  bool reverse;  tree base;  invalid = false;  off = 0;                // <=  ....  if (otr_type && !contains_type_p (TREE_TYPE (base), off, otr_type))    return false;  set_by_decl (base, off);  return true;}

PVS-Studio warning: V763 Parameter 'off' is always rewritten in function body before being used. ipa-polymorphic-call.c 766

PVS-Studio警告:V763使用之前,始终在功能体内重写参数“ off”。 ipa-polymorphic-call.c 766

The value of the off argument is immediately replaced by 0. Moreover, there is no explanatory comment. All this is very suspicious. Sometimes this code appears during debugging. The programmer wanted to see how the function was behaving in a certain mode, and temporarily changed the value of the argument, and then forgot to delete that line. This is how the error appeared in the code. Of course, everything may be correct here, but this code clearly needs to be checked and clarified in comments in order to avoid similar concerns in the future.

off参数的值将立即替换为0。此外,没有解释性注释。 这一切都是非常可疑的。 有时,此代码在调试过程中出现。 程序员希望了解函数在特定模式下的行为,并临时更改参数的值,然后忘记删除该行。 这是错误在代码中出现的方式。 当然,这里的一切都可能是正确的,但是显然需要对此代码进行检查和澄清,以免将来出现类似的问题。

片段N6。 小东西 (Fragment N6. Little thing)

cgraph_node *cgraph_node::create_clone (....){  ....  new_node->icf_merged = icf_merged;  new_node->merged_comdat = merged_comdat;   // <=  new_node->thunk = thunk;  new_node->unit_id = unit_id;  new_node->merged_comdat = merged_comdat;   // <=  new_node->merged_extern_inline = merged_extern_inline;  ....}

PVS-Studio warning: V519 The 'new_node->merged_comdat' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 406, 409. cgraphclones.c 409

PVS-Studio警告:V519连续两次为'new_node-> merged_comdat'变量分配值。 也许这是一个错误。 检查行:406、409。cgraphclones.c 409

The assignment is accidently duplicated. Most likely, nothing crucial here. However, there is always a risk that in reality the author forgot to perform another assignment.

分配被意外重复。 最有可能的是,这里没有关键。 但是,实际上始终存在作者忘记执行其他任务的风险。

片段N7。 看起来很危险的代码 (Fragment N7. Code that looks dangerous)

static voidcomplete_mode (struct mode_data *m){  ....  if (m->cl == MODE_COMPLEX_INT || m->cl == MODE_COMPLEX_FLOAT)    alignment = m->component->bytesize;  else    alignment = m->bytesize;  m->alignment = alignment & (~alignment + 1);  if (m->component)  ....}

PVS-Studio warning: V595 The 'm->component' pointer was utilized before it was verified against nullptr. Check lines: 407, 415. genmodes.c 407

PVS-Studio警告:V595在针对nullptr进行验证之前,已使用了'm-> component'指针。 检查行:407、415。genmodes.c 407

First the pointer m->component is dereferenced in one of the branches of the if statement. I mean this expression: m->component->bytesize.

首先,在if语句的一个分支中取消对指针m-> component的引用。 我的意思是这个表达式: m-> component-> bytesize

It further turns out that this pointer may be null. This follows from the check: if (m->component).

进一步证明该指针可以为空。 这来自检查: if(m-> component)

This code is not necessarily wrong. It is well possible that the dereferencing branch is only executed if the pointer is not null. That is, there is an indirect relationship between the value of the variable m->cl and m->component. But this code looks very dangerous in any case. Besides, there are no explanatory comments.

此代码不一定是错误的。 仅当指针不为null时才执行取消引用分支。 也就是说,变量m-> cl的值和m-> component的值之间存在间接关系。 但是无论如何,这段代码看起来非常危险。 此外,没有解释性注释。

片段N8。 再检查一遍 (Fragment N8. Double check)

voidpointer_and_operator::wi_fold (value_range &r, tree type,                               const wide_int &lh_lb,                               const wide_int &lh_ub,                               const wide_int &rh_lb ATTRIBUTE_UNUSED,                               const wide_int &rh_ub ATTRIBUTE_UNUSED) const{  // For pointer types, we are really only interested in asserting  // whether the expression evaluates to non-NULL.  if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub))    r = range_zero (type);  else     r = value_range (type);}

PVS-Studio warning: V501 There are identical sub-expressions 'wi_zero_p(type, lh_lb, lh_ub)' to the left and to the right of the '||' operator. range-op.cc 2657

PVS-Studio警告:V501在“ ||”的左侧和右侧有相同的子表达式“ wi​​_zero_p(type,lh_lb,lh_ub)” 操作员。 range-op.cc 2657

Some kind of a strange check. The wi_zero_p function is called twice with the same set of actual arguments. One may suspect that in fact, the second call should use the arguments received from the outside: rh_lb, rh_ub. But no, these arguments are marked as unused (ATTRIBUTE_UNUSED).

某种奇怪的检查。 wi_zero_p函数使用相同的一组实际参数调用两次。 可能有人怀疑,实际上,第二个调用应该使用从外部收到的参数: rh_lbrh_ub 。 但是不,这些参数被标记为未使用( ATTRIBUTE_UNUSED )。

Therefore, it is not clear to me why not write the check in a simpler way:

因此,我不清楚为什么不以更简单的方式写支票:

if (wi_zero_p (type, lh_lb, lh_ub))  r = range_zero (type);else   r = value_range (type);

Or is there a typo here? Or a logical mistake? I don't know, but the code is weird.

还是这里有错字? 还是逻辑错误? 我不知道,但是代码很奇怪。

片段N9。 危险的阵列访问 (Fragment N9. Dangerous array access)

struct algorithm{  struct mult_cost cost;  short ops;  enum alg_code op[MAX_BITS_PER_WORD];  char log[MAX_BITS_PER_WORD];};static voidsynth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,            const struct mult_cost *cost_limit, machine_mode mode){  int m;  struct algorithm *alg_in, *best_alg;  ....  /* Cache the result.  */  if (!cache_hit)  {    entry_ptr->t = t;    entry_ptr->mode = mode;    entry_ptr->speed = speed;    entry_ptr->alg = best_alg->op[best_alg->ops];    entry_ptr->cost.cost = best_cost.cost;    entry_ptr->cost.latency = best_cost.latency;  }  /* If we are getting a too long sequence for `struct algorithm'     to record, make this search fail.  */  if (best_alg->ops == MAX_BITS_PER_WORD)    return;  ....}

PVS-Studio warning: V781 The value of the 'best_alg->ops' variable is checked after it was used. Perhaps there is a mistake in program logic. Check lines: 3157, 3164. expmed.c 3157

PVS-Studio警告:V781使用“ best_alg-> ops”变量后,将对其进行检查。 程序逻辑中可能有一个错误。 检查行:3157、3164。expmed.c 3157

Let's shorten the code to make it clear what the analyzer does not like here:

让我们缩短代码以明确分析器在这里不喜欢什么:

if (!cache_hit){  entry_ptr->alg = best_alg->op[best_alg->ops];}if (best_alg->ops == MAX_BITS_PER_WORD)

At the beginning, the variable best_alg->ops is used to index the array. Only afterwards this variable is checked for a boundary value. An array index out of bounds might potentially happen (a classic type of of the error ).

开始时,变量best_alg-> ops用于索引数组。 之后才检查此变量的边界值。 可能超出范围的发生数组索引(错误的经典类型 )。

Is this a legit error? And as this is constantly happening in this article, I'm not sure :). Perhaps there is a relationship between the value of this index and the cache_hit variable. Perhaps nothing is cached if the index has the maximum value MAX_BITS_PER_WORD). The function code is large, and I did not figure it out.

这是合法错误吗? 而且由于本文中这种情况一直在发生,所以我不确定:)。 该索引的值和cache_hit变量之间可能存在关系。 如果索引的最大值为MAX_BITS_PER_WORD,则可能不会缓存任何内容。 功能代码很大,我没有弄清楚。

In any case, this code is best to be checked. Even if it turns out to be correct, I would recommend leaving a comment for the considered section of the program. It can confuse not only me or PVS-Studio, but also someone else.

无论如何,最好检查此代码。 即使事实证明是正确的,我还是建议您为程序中考虑的部分发表评论。 它不仅会使我或PVS-Studio困惑,还会使其他人感到困惑。

片段N10。 四年未定的代码 (Fragment N10. Code that has not been fixed for 4 years)

Even in the last , I drew attention to this code:

即使在上 ,我也提请注意以下代码:

static booldw_val_equal_p (dw_val_node *a, dw_val_node *b){  ....  case dw_val_class_vms_delta:    return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)            && !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));  ....}

PVS-Studio warning: V501 There are identical sub-expressions '!strcmp(a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)' to the left and to the right of the '&&' operator. dwarf2out.c 1481

PVS-Studio警告:V501'&&'运算符的左侧和右侧有相同的子表达式'!strcmp(a-> v.val_vms_delta.lbl1,b-> v.val_vms_delta.lbl1)'。 dwarf2out.c 1481

Two strcmp functions compare the same pointers. That is, a clearly redundant check is performed. In a previous article, I assumed that it was a typo, and the following should actually have been written:

两个strcmp函数比较相同的指针。 即,执行明显多余的检查。 在上一篇文章中,我认为这是一个错字,实际上应该写出以下内容:

return (   !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)        && !strcmp (a->v.val_vms_delta.lbl2, b->v.val_vms_delta.lbl2));

However, it's already 4 years since this code has not been fixed. By the way, we informed the authors about the suspicious sections of code that we described in the article. Now I'm not so sure that this is a bug. Perhaps this is just redundant code. In this case, the expression can be simplified:

但是,距离该代码尚未修复已经有4年了。 顺便说一下,我们向作者介绍了本文中描述的可疑代码部分。 现在我不太确定这是一个错误。 也许这只是多余的代码。 在这种情况下,可以简化表达式:

return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));

Let's see if GCC developers will change this piece of code after a new article.

让我们看看GCC开发人员是否会在撰写新文章后更改这段代码。

结论 (Conclusion)

I'd like to kindly remind you that you are welcome to use for checking open source projects. By the way, there are other options of free PVS-Studio licensing even for closed projects. They are listed here: "".

谨在此提醒您,欢迎您使用来检查开源项目。 顺便说一句,还有免费的PVS-Studio许可的其他选择,即使对于封闭的项目也是如此。 它们在此处列出:“ ”。

Thank you for your attention. Follow the link and read our . Lots of interesting stuff await.

感谢您的关注。 点击链接并阅读我们的 。 许多有趣的东西在等待。

我们有关检查编译器的其他文章 (Our other articles about checking compilers)

  1. (August 2011), (August 2012), (October 2016), (April 2019)

    (2011年8月), (2012年8月), (2016年10月), (2019年4月)

  2. (August 2016).

    (2016年8月)。

  3. (December 2019)

    (2019年12月)

  4. (December 2015), (April 2019)

    (2015年12月), (2019年4月)

  5. (August 2019)

    (2019年8月)

  6. (March 2017)

    (2017年3月)

翻译自:

pvs-stdio ue4

转载地址:http://mvdwd.baihongyu.com/

你可能感兴趣的文章
工程问题
查看>>
十二种获取Spring的上下文环境ApplicationContext的方法
查看>>
UVA 11346 Probability 概率 (连续概率)
查看>>
linux uniq 命令
查看>>
Openssl rand命令
查看>>
HDU2825 Wireless Password 【AC自动机】【状压DP】
查看>>
BZOJ1015: [JSOI2008]星球大战starwar【并查集】【傻逼题】
查看>>
HUT-XXXX Strange display 容斥定理,线性规划
查看>>
mac修改用户名
查看>>
一道关于员工与部门查询的SQL笔试题
查看>>
Python replace方法的使用
查看>>
Canvas基础
查看>>
java视频音频解码-封装xuggle-实现多种视频编码格式解码扩展
查看>>
160个CrackMe 027 Cosh.1
查看>>
[ActionScript 3.0] AS3动态改变注册点
查看>>
可视化小组作业——对上届学长的采访
查看>>
[Hive - LanguageManual] Alter Table/Partition/Column
查看>>
可持久化数组
查看>>
去除IDEA报黄色/灰色的重复代码的下划波浪线
查看>>
Linux发送qq、网易邮件服务配置
查看>>