C++ Logo

std-proposals

Advanced search

Re: Mistake in C++ Standard Arithmetic Conversion makes C++ compiler unreliable

From: Gašper Ažman <gasper.azman_at_[hidden]>
Date: Tue, 7 Jan 2020 18:26:11 +0000
+ std-proposals because it got dropped.

On Tue, Jan 7, 2020 at 5:57 PM Владимир Прокофьев <vov-crao_at_[hidden]> wrote:
[snip]

> and then converted back to unsigned long to write the result.
>
> No. Signed type, involved into multiplication and division operations wins
> and result will be always signed. It is a common algebra operations. The
> result for the your example above will be signed (long long). If the lvalue
> has long type then the result will be converted to long.
>

OK, just as long as we're clear we're actually changing the type of the
multiplication and division expressions. In a way that's incompatible with
C.


>
> Effectively, for T and U, and an expression
>
> auto x = (T)-1 / (U)1;
>
> what is decltype(x)?
>
> The rules say that for T=long and U = unsigned long, decltype(x) is
> unsigned long.
>
> Rule says wrong. Even common sense tells that* decltype(x)* have to be
> *long*.
>

Well, but that's not what the rule says *now*. I agree the rule might be
misguided, but it *is* the current rule. Changing it is a breaking change.
In an epochs-world I could see this happening. Perhaps. With the current
focus of the committee not to break code unless the evidence is
overwhelmingly in favor of it and the amount of code broken is miniscule,
this is a tall order.


>
> Standard doesn't tell about different behavior for *8*, *16*, *32* and
> *64* bits types. The *8* and *16* bits types shows correct behavior, just
> as I have described. But *32* and *64* bits shows *trash*. Here you can
> see different behavior https://rextester.com/CKKDX46498
> Please tell me where this behavior is explained in the Standard?
>
[conv.prom] paragraph 1:
www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4842.pdf#subsection.7.3.6

This basically says that char and short are converted to int (unsigned
versions -> unsigned int) before doing arithmetic, and the result is an
int, not a signed short or whatever. They don't work by the same rules.

> Standard doesn't tell about different behavior for *multiplication* and
> *division* operations. But *multiplication* operation works correct for
> any type (https://rextester.com/UAH19753), whereas *division* operation
> works *incorrect* for *32* and *64* bits (https://rextester.com/CKKDX46498).
> See here for proof: http://coliru.stacked-crooked.com/a/092080eabcc16667
> Please tell me where this behavior is explained in the Standard?
>
It isn't. It's a result of your assignment back to a signed type, and the
inherent meanings of multiplication and division. Observe:
https://godbolt.org/z/EoT4d6

>
> Also I have modified https://rextester.com/CKKDX46498 to show division
> table of *unsigned*/*signed* : https://rextester.com/CLJNO52206
> As you can see the result is pretty strange.
>

The result is stupid but correct by the current rules. As stated above, I
don't think the committee will be amenable to changing that, but feel free
to bring a paper.


>
> *Note*: The correct behavior is implemented in the *Assembler* language,
> because different instruction is used if signed is involved (*idiv*).
>
> We can't just change that. We can't.
>
> Please explain the difference for *16* and *32* bits *division* and
> between *multiplication* and *division* operations for *32* and *64* bits?
>
Integer promotion. See above.

> That ship has sailed in 1987.
>
> Wow! Long story. I cannot believe that I meet it only now! For 30 years of
> C/C++ coding! Debugging and testing!!
>
Shrug.

> If we change that, it will break code.
>
> Why not to add an option to fix it?
>
The standard does not define options.

>
> G
>
> On Tue, Jan 7, 2020 at 12:09 PM Владимир Прокофьев <vov-crao_at_[hidden]
> <//e.mail.ru/compose/?mailto=mailto%3avov%2dcrao_at_[hidden]>> wrote:
>
>
>
>
> Вторник, 7 января 2020, 17:39 +07:00 от Gašper Ažman <
> gasper.azman_at_[hidden]
> <//e.mail.ru/compose/?mailto=mailto%3agasper.azman_at_[hidden]>>:
>
> Then the committee is most likely going to add this to the steaming pile
> of "things we wish we could fix but can't because it would break code",
>
> Do you really think that this fix will break the existing code? I don't
> think so, because this bug produces a mess result and nobody will write the
> code wich produces such mess.
>
> But fixing it will make code reliable and stable.
>
> If it is a policy to avoid any fix which can potentiality affect the
> existing code, then it will be much reasonable to provide a compiler option
> (say *--fix-int-div*) and then this option is *ON*, the fix is applied.
> At least I will use this option everywhere.
>
> Do you remember a bug in Intel Pentium processor in *fdiv* instruction?
> It produces a slightly different result comparing to expected, but this bug
> was fixed both in CPU and in many compilers with an extra flag. Why not to
> do the same for this bug??
>
> like most of the implicit int conversions.
>
> If you don't believe me, feel free to write a paper.
>
> I am really cannot believe.
> It is first serious bug in the C++ I have found and it will not be fixed.
>
>
> On Tue, Jan 7, 2020, 10:36 Владимир Прокофьев <vov-crao_at_[hidden]
> <http://e.mail.ru/compose/?mailto=mailto%3avov%2dcrao_at_[hidden]>> wrote:
>
> Hi.
>
> See below.
>
> Вторник, 7 января 2020, 17:06 +07:00 от Gašper Ažman <
> gasper.azman_at_[hidden]
> <http://e.mail.ru/compose/?mailto=mailto%3agasper.azman_at_[hidden]>>:
>
> Did we inherit this from C?
>
> I am not sure. I see no history of modification of this rule.
>
> I tested it in gcc with -std=c99 option and the result is confirmed. See
> http://coliru.stacked-crooked.com/a/3f3ed6126e361678
>
>
>
> On Tue, Jan 7, 2020 at 6:46 AM Владимир Прокофьев via Std-Proposals <
> std-proposals_at_[hidden]
> <http://e.mail.ru/compose/?mailto=mailto%3astd%2dproposals_at_[hidden]>>
> wrote:
>
> I have found a mistake in the C++ Standard,
> https://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversion :
> in the rule:
>
> *Otherwise, if the unsigned operand's conversion rank is greater or equal
> to the conversion rank of the signed operand, the signed operand is
> converted to the unsigned operand's type.*
>
> The NEGATIVE signed value CANNOT be converted to unsigned for any types.
> But opposite conversion from unsigned to signed is valid with appropriate
> rank.
>
> To prove, please see wrong results here https://rextester.com/CKKDX46498
>
> Note, that the error is observed for VS, CLang and GCC C++ compilers.
>
> As you can see the error is observer in *division* operation to *unsigned*
> *32* and *64* bits.
> The *division* operation to *SIGNED* types is VALID (see *first* table in
> the example).
> Also *multiplication* of signed and unsigned values is VALID.
>
> The example above shows that the C++ compiler shows *unreliable* behavior
> which leads to produce wrong values as a result of division.
>
> The correct rule *shall* be:
>
>
> *Otherwise, unsigned operand is converted to signed type of same or higher
> conversion rank of unsigned operand's type and then the operand with lesser
> conversion rank is converted to the operand with the greater conversion
> rank*
> С уважением.
>
> Владимир.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> <http://e.mail.ru/compose/?mailto=mailto%3aStd%2dProposals_at_[hidden]>
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
>
>
> С уважением.
> Владимир.
>
>
>
> С уважением.
> Владимир.
>
>
>
> С уважением.
> Владимир.
>

Received on 2020-01-07 12:28:55