Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is it safe to rely on evaluation order for this C++ function call with -O3 optimizations?

I am having a problem with some C++20 code that is crashing when compiled in release (-O3, clang 15), and it’s very tricky to debug due to a number of obfuscation techniques being applied on the final executable which makes it extremely difficult to see the actual x86_64 ASM being executed.

Still, I have managed to narrow the crash down to the following pseudo code…

for (std::wstring& data : datas)
{
    auto id = std::format(L"foo_{0}", data);

    do_something(id, std::move(data));
}

…where the signature for do_something looks like this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

void do_something(const std::wstring&, std::wstring);

Basically, the move constructor of the std::wstring for the second argument should be invoked already when setting up the call, I assume.

Now, this code works fine with -O2, but when enabling -O3 it breaks, and I have a hunch.

Reading through the C++ standard, we can see the following…

Order of evaluation of any part of any expression, including order of evaluation of function arguments is unspecified (with some exceptions listed below). The compiler can evaluate operands and other subexpressions in any order, and may choose another order when the same expression is evaluated again.

I have also read that C++ compilers are free to optimize away locals when they have no side effects (but have not located this specific rule in the standards).

Could it be that, since std::format in itself has no side effect in the above code, the compiler "inlines" it into the function call when using -O3? And when it does, the order of evaluation is undefined, so that the move actually happens before the call to std::format is called?

Basically what I am asking is: would the optimization I describe be permitted by the C++ standard?

>Solution :

Could it be that, since std::format in itself has no side effect in the above code, the compiler "inlines" it into the function call when using -O3?

No. Or if it does, it will keep the order of instructions such that std::format is called before the move (the second parameter’s move constructor, not the std::move which is not an instruction). Otherwise, what is well-defined behavior would turn into undefined behavior, and that is not something a compiler is allowed to do in normal situations.

A compiler can provide options that break standard compliance. This is the case with -Ofast for example. However, -O3 does not break standard compliance, and as far as I know, there is no GCC option that would result in what you describe.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading