Warn about UB in argument evaluation order

落花浮王杯 提交于 2021-02-05 07:55:08

问题


I recently faced a bug in a code like this

class C
{
public:
    // foo return value depends on C's state
    // AND each call to foo changes the state.
    int foo(int arg) /*foo is not const-qualified.*/ {}

private:
    // Some mutable state
};

C c;

bar(c.foo(42), c.foo(43))

The last call behaved differently on different platforms (which is perfectly legal due to undefined order of argument evaluation), and I fixed the bug.

But the rest codebase is large and I would like to spot all other UB of this type.

Is there a special compiler warning in GCC, Clang or MSVS for such cases?

And what is the ideomatic and lightweight way to prevent such bugs?


回答1:


Argument order evaluation is unspecified rather than undefined.

Order of evaluation of the operands of almost all C++ operators (including the order of evaluation of function arguments in a function-call expression and the order of evaluation of the subexpressions within any expression) is unspecified. The compiler can evaluate operands in any order, and may choose another order when the same expression is evaluated again.

Since it is unspecified rather than undefined behavior, compilers are not required to issue diagnostics for it.

GCC and Clang do not have any general compiler option to issue diagnostics for unspecified behavior.

In GCC there is the option fstrong-eval-order which does this:

Evaluate member access, array subscripting, and shift expressions in left-to-right order, and evaluate assignment in right-to-left order, as adopted for C++17. Enabled by default with -std=c++17. -fstrong-eval-order=some enables just the ordering of member access and shift expressions, and is the default without -std=c++17.

There is also the option -Wreorder (C++ and Objective-C++ only) which does this:

Warn when the order of member initializers given in the code does not match the order in which they must be executed

But I do not think these options will be helpful in your particular case.

In the below statement, if you want the first argument to be evaluated before the second:

bar(c.foo(42), c.foo(43))

The simple way is to store the results of c.foo(42) and c.foo(43) in intermediate variables first and then call bar(). (Turn off compiler optimizations to avoid any reordering of statements by the compiler !!)

auto var1 = c.foo(42);
auto var2 = c.foo(43);
bar(var1, var2);

I guess that is how you must have fixed the bug.



来源:https://stackoverflow.com/questions/53493041/warn-about-ub-in-argument-evaluation-order

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!