Why change UB that will always work as intended? [duplicate] - c++

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Undefined behavior and sequence points
(5 answers)
Closed 5 years ago.
In the legacy code base I'm working on, I discovered the line
n = ++n % size;
that is just a bad phrasing of the intended
n = (n+1) % size;
as deduced from the surrounding code and runtime-proved. (The latter now replaces the former.)
But since this code was marked as an error by Cppckeck, and caused a warning in GCC, without ever having caused any malfunction, I didn't stop thinking here. I reduced the line to
n = ++n;
still getting the original error/warning messages:
Cppcheck 1.80:
Id: unknownEvaluationOrder
Summary: Expression 'n=++n' depends on order of evaluation of side effects
Message: Expression 'n=++n' depends on order of evaluation of side effects
GCC (mingw32-g++.exe, version 4.9.2, C++98):
warning: operation on 'n' may be undefined [-Wsequence-point]|
I already learned that assignment expressions in C/C++ can be heavily affected by undefined evaluation order, but in this very case I just can't imagine how.
Can the undefined evaluation order of n = ++n; really be relevant for the resulting program, especially for intended value of n? That's what I imagine what may happen.
Scenario #1
++n;
n=n;
Scenario #2
n=n;
++n;
I know that the meaning and implications of relaying on undefined behaviour in C++, is hard to understand and hard to teach.
I know that the behaviour of n=++n; is undefined by C++ standards before C++11. But it has a defined behaviour from C++11 on, and this (now standard-defined behaviour) is exactly the same I'm observing with several compilers[1] for this small demo program
#include <iostream>
using namespace std;
int main()
{
int n = 0;
cout << "n before: " << n << endl;
n=++n;
cout << "n after: " << n << endl;
return 0;
}
that has the output
n before: 0
n after: 1
Is it reasonable to expect that the behaviour is actually the same for all compilers regardless of being defined or not by standards? Can you (a) show one counter example or (b) give an easy to understand explanation how this code could produce wrong results?
[1] the compilers a used
Borland-C++ 5.3.0 (pre-C++98)
Borland-C++ 5.6.4 (C++98)
C++ (vc++)
C++ (gcc 6.3)
C++14 (gcc 6.3)
C++14 clang

The increment order is precisely defined. It is stated there that
i = ++i + 2; // undefined behavior until C++11
Since you use a C++11 compiler, you can leave your code as is is. Nevertheless, I think that the expressiveness of
n = (n+1) % size;
is higher. You can more easily figure out what was intended by the writer of this code.

According to cppreference:
If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined:
i = ++i + 2; // undefined behavior until C++11
i = i++ + 2; // undefined behavior until C++17
f(i = -2, i = -2); // undefined behavior until C++17
f(++i, ++i); // undefined behavior until C++17, unspecified after C++17
i = ++i + i++; // undefined behavior
For the case n = ++n; it would be an undefined behavior but we do not care which assignment happens first, n = or ++n.

Related

Same code gives different output on Microsoft studio compared to other compilers [duplicate]

This question already has answers here:
How do we explain the result of the expression (++x)+(++x)+(++x)? [duplicate]
(5 answers)
Closed 3 years ago.
int a = 10;
a = a++;
cout << a<<" ";
a++;
cout << a;
In microsoft Visual its output is 11 12
And in other compilers (like codechef and codeforces) its output is 10 11
This question's Output was asked in some mcq paper and the correct answer is 10 11 but can any1 also explain how
a = a++;
++a;
cout<<a;
produces output of 11 does a = a++ does't do anything?
a = a++; is not a correct statement due to lack of sequence point or being unsequenced(C++11).
undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses outside of array bounds, signed integer overflow, null pointer dereference, more than one modifications of the same scalar in an expression without any intermediate sequence point (until C++11)that are unsequenced (since C++11), access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful.
https://en.cppreference.com/w/cpp/language/ub

Out of bounds pointer arithmetic not detected?

According to Wikipedia and this, this code is undefined behavior:
#include <iostream>
int main(int, char**) {
int data[1] = {123};
int* p = data + 5; // undefined behavior
std::cout << *(p - 5) << std::endl;
}
Compiled with clang++-6.0 -fsanitize=undefined and executed, the undefined behavior is detected which is fantastic, I get this message:
ub.cpp:5:19: runtime error: index 5 out of bounds for type 'int [1]'
But when I don't use an array, the undefined behavior is not detectable:
#include <iostream>
int main(int, char**) {
int data = 123;
int* p = &data + 5; // undefined behavior
std::cout << *(p - 5) << std::endl;
}
The sanitizer detects nothing, even though this is still undefined behavior. Valgrind also does not show any problem. Any way to detect this undefined behavior?
Since I am never accessing any invalid data, this is not a duplicate of Recommended way to track down array out-of-bound access/write in C program.
The standard very clearly specifies that most forms of undefined behaviour is "no diagnostic required". Meaning that your compiler is under no obligation to diagnose UB (which would also be unreasonable, since it is very hard to do so in many cases). Instead, the compiler is allowed to just assume that you "of course did not" write any UB and generate code as if you didn't. And if you did, that's on you and you get to keep the broken pieces.
Some tools (like asan and ubsan and turning your compilers warning level to 11) will detect some UB for you. But not all.
Your compiler implementors are not out to harm you. They do try to warn you of UB when they can. So, at the very least you should enable all warnings and let them help you as best they can.
One way to detect UB is to have intimate knowledge of the C++ standard and read code really carefully. But, you cannot really do better than that + let some tools help you find the low-hanging fruit. You just have to know (all) the rules and know what you are doing.
There are no training wheels or similar in C++.

Strange post-increment behaviour in C++ [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 6 years ago.
I have a friend who is getting different output than I do for the following program:
int main() {
int x = 20, y = 35;
x = y++ + x++;
y = ++y + ++x;
printf("%d%d", x, y);
return 0;
}
I am using Ubuntu, and have tried using gcc and clang. I get 5693 from both.
My friend is using Visual Studio 2015, and gets 5794.
The answer I get (5693) makes most sense to me, since:
the first line sets x = x + y (which is x = 20+35 = 55) (note: x was incremented, but assigned over top of, so doesn't matter)
y was incremented and is therefore 36
next line increments both, adds the result and sets it as y (which is y = 37 + 56 = 93)
which would be 56 and 93, so the output is 5693
I could see the VS answer making sense if the post-increment happened after the assignment. Is there some spec that makes one of these answers more right than the other? Is it just ambiguous? Should we fire anyone who writes code like this, making the ambiguity irrelevant?
Note: Initially, we only tried with gcc, however clang gives this warning:
coatedmoose#ubuntu:~/playground$ clang++ strange.cpp
strange.cpp:8:16: warning: multiple unsequenced modifications to 'x' [-Wunsequenced]
x = y++ + x++;
~ ^
1 warning generated.
The Clang warning is alluding to a clause in the standard, C++11 and later, that makes it undefined behaviour to execute two unsequenced modifications to the same scalar object. (In earlier versions of the standard the rule was different although similar in spirit.)
So the answer is that the spec makes all possible answers equally valid, including the program crashing; it is indeed inherently ambiguous.
By the way, Visual C++ actually does have somewhat consistent and logical behaviour in such cases, even though the standard does not require it: it performs all pre-increments first, then does arithmetic operations and assignments, and then finally performs all post-increments before moving on to the next statement. If you trace through the code you've given, you'll see that Visual C++'s answer is what you would expect from this procedure.

Variable initialization with itself

Is it safe to write such code?
#include <iostream>
int main()
{
int x = x-x;// always 0
int y = (y)? y/y : --y/y // always 1
}
I know there is undefined behaviour, but isn't it in this case just a trash value? If it is, then same value minus same is always 0, and same value divided by itself (excluding 0) is always 1. It's a great deal if one doesn't want to use integer literals, isn't it? (to feint the enemy)
Allow me to demonstrate the evil magic of undefined behaviour:
given:
#include <iostream>
int main()
{
using namespace std;
int x = x-x;// always 0
int y = (y)? y/y : --y/y; // always 1
cout << x << ", " << y << endl;
return 0;
}
apple clang, compile with -O3:
output:
1439098744, 0
Undefined is undefined. The comments in the above code are lies which will confound future maintainers of your random number generator ;-)
I know there is undefined behaviour, but isn't it in this case just a trash value? If it is, then same value minus same is always 0, and same value divided by itself (excluding 0) is always 1.
No! No, no, no!
The "trash value" is an "indeterminate value".
Subtracting an indeterminate value from itself does not yield zero: it causes your program to have undefined behaviour ([C++14: 8.5/12]).
You cannot rely on the normal rules of arithmetic to "cancel out" undefined behaviour.
Your program could travel back in time and spoil Game of Thrones/The Force Awakens/Supergirl for everyone. Please don't do this!
Undefined behavior is undefined. Always. Stuff may work or break more or less reliably on certain platforms, but in general, you can not rely on this program not crashing or any variable having a certain value.
Undefined behavior is undefined behavior. There's no "isn't it in this case something specific" (unless you are actually talking about result of a completed compilation, and looking at the generated machine code, but that is no longer C++). Compiler is allowed to do whatever it pleases.

In C/C++ is x[i] * y[i++] always equal to x[i] * y[i] [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
increment values in printf
I have a two double arrays x and y and integer i. My question is whether the statement:
double res = x[i] * y[i++];
is always equal to the statement:
double res = x[i] * y[i];
i++;
Is it possible that some compilers would change x[i] * y[i++] into y[i++] * x[i], which obviously produces different result?
No -- x[i] + y[i++] has undefined behavior. You're modifying the value of i and also using the value i without an intervening sequence point, which gives undefined behavior1.
In C++11 the standard has eliminated the "sequence point" terminology, but the effect remains the same -- the two are unordered with respect to each other.
No, it is undefined when the increment occurs.
The code modifies i and uses its value without an intervening sequence point, so the behavior is undefined. The language definition does not impose any requirements here.
No,
value of i++ + i++ are undefined in C and C++.
if you read a variable twice in an expression where you also write it, the result is undefined. Don't do that. Another example is:
v[i] = i++;
Undefined means its COMPILER DEPENDENT.
Some compiler could warn you also as undefined because the order of evaluation.
A very good reference for C++
1 http://www.stroustrup.com/bs_faq2.html#evaluation-order