Recent

Author Topic: {$OVERFLOWCHECKS ON} does not report an obvious overflow  (Read 6777 times)

Lupp

  • New Member
  • *
  • Posts: 31
{$OVERFLOWCHECKS ON} does not report an obvious overflow
« on: February 07, 2017, 09:35:55 pm »
What may be the reason for what the following little programm does not report the obvious type overflow?

Code: Pascal  [Select][+][-]
  1. program TestOverflowCheck;
  2.  
  3. {$OVERFLOWCHECKS ON}
  4.  
  5. uses
  6.   Crt;
  7. var
  8.   i32 : Longint;
  9.  
  10. begin
  11.   ClrScr;
  12.   Writeln(MaxLongint);
  13.   i32:= MaxLongint + 2;
  14.   Writeln(i32);
  15.   repeat until ReadKey = #27
  16. end.
  17.  
  18. {
  19. Why does this program not report an overflow?
  20.  
  21. Output:
  22. 2147483647   Ok, 2^31 - 1)
  23. -2147483647  NOT ok.
  24.  
  25. The calculation was donee as if the type was LongWord.
  26. The result then is shown based on the actual type.
  27. }                                              

GetMem

  • Hero Member
  • *****
  • Posts: 3757
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #1 on: February 07, 2017, 10:26:46 pm »
Just add {$R+}{$Q+}.

Nitorami

  • Sr. Member
  • ****
  • Posts: 378
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #2 on: February 07, 2017, 11:02:34 pm »
I think Lupp wants to understand why the overflowcheck does not cause an error in this case.

I have never used overflow checking because for all I needed, range checking did the job, and I am not sure what the difference is. I THINK the case is:

Range check works on the specific type, e.g. if I define var x : 1..7; and assign x := 8, this will cause a range check error. Checking this is in the responsibility of FPC's range check routine. It can to some extent be done at compile time already.

Overflow check is triggered by a CPU exception whenever an integer overflow occurs during runtime. Means this is NOT in FPC's responsibility, BUT with {OVERFLOWCHEKCS ON}, FPC will stop program execution and throw error 215 on the exception. Therefore, overflow errors are not discovered at compile time, they are thrown at runtime. In Lupps example code, i32:= MaxLongint + 2 is however calculated at compile time already. Such errors can only be discovered with range check on.

Modify the code slightly

  i32:= MaxLongint;
  Writeln(i32+3);

and you'll get the overflow error, because the addition is now done at runtime.

EDIT: Also I think that overflow checking is machine specific, and does not depend on the integer type defined. A 64 bit CPU may handle this differently than a 32 bit CPU, the purpose being to prevent calculation errors.
« Last Edit: February 07, 2017, 11:09:54 pm by Nitorami »

Lupp

  • New Member
  • *
  • Posts: 31
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #3 on: February 07, 2017, 11:29:43 pm »
Thank you all.

I thought range checking was for index positions, which always have a type whether given by a type name or by a type constant like -3 .. 11.

Overflow checking should be a more general option applying to variables of any ordinal or integer type when assignments are made.

Using {$R+} I see that this directive also covers the second case. How is thi exactly? Does {$Q+} not check indices?

In addition I thought the {$OVERFLOWCHECKS ON} directive was a clearly speaking way to tell what I wanted. Now it seems it is no longer working and {Q+} may be the mandatory replacement. Did I understand this correctly or is there a different background?

Nitorami

  • Sr. Member
  • ****
  • Posts: 378
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #4 on: February 07, 2017, 11:41:16 pm »
Quote
I thought range checking was for index positions, which always have a type whether given by a type name or by a type constant like -3 .. 11.
Yes, range check also checks array index.

Quote
Overflow checking should be a more general option applying to variables of any ordinal or integer type when assignments are made.
I am not writing compilers but there are certainly good reasons to handle range and overflow checks the way it is done. The problem is only that you have not quite understood the difference yet.

Quote
Using {$R+} I see that this directive also covers the second case. How is thi exactly? Does {$Q+} not check indices?
No, {$Q+} does not check indices. How should that work ? As said, an overflow erroe is triggere by the CPU whenever an integer operation overflows, and {$Q+} only tells FPC to stop the program in such a case.

Quote
In addition I thought the {$OVERFLOWCHECKS ON} directive was a clearly speaking way to tell what I wanted. Now it seems it is no longer working and {Q+} may be the mandatory replacement. Did I understand this correctly or is there a different background?

As far as I can see, {$OVERFLOWCHECKS ON} and {$Q+} are the same, and they both work. Why do you think it is no longer working ?

Lupp

  • New Member
  • *
  • Posts: 31
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #5 on: February 08, 2017, 12:41:57 am »
Quote from: Nitorami
As far as I can see, {$OVERFLOWCHECKS ON} and {$Q+} are the same, and they both work. Why do you think it is no longer working ?
That is because it actually didn't work when I tested for it. Maybe this is new in my rather fresh Lazarus 1.6.2 with FPC 3.0.0. In fact I just tested another time (only  basics) and got: {$R+} and {$Rangechecks ON} both caused checking for index ranges and for integer type overflows as well. {$Q+}and {$OVERFLOWCHECKS ON} both had neither the one nor the other effect.

Quote from: Nitorami
The problem is only that you {Lupp} have not quite understood the difference yet.
That's true. Mabe someone can help me to make another step on the way.

Quote from: Nitorami
{$Q+} does not check indices. How should that work ?
Don't we both agree that {$R+} does? It should work in the same way as checking for integer overflows. I see an index position is an implicit variable of a well defined integer type. When an array element is accessed the index positions are evaluated. That's the opportunity for the checking code. 

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 6675
  • Debugger - SynEdit - and more
    • wiki
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #6 on: February 08, 2017, 04:33:09 am »
Code: Pascal  [Select][+][-]
  1. MaxLongint + 2;
If this calculation was done in 32 bit (longint = 32 bit), then it should give a overflow.

From a very vague memory: FPC evaluates all constants in 64 bit.
If that is indeed so, then there is no overflow.

But then the result $1 0000 0001
Code: Pascal  [Select][+][-]
  1.  i32:= MaxLongint + 2;
does not fit into an longint. so when assigning the constant to the variable, there is the range check error.


I am not sure why, but even this seems to be evaluated in 64 bits.
Code: Pascal  [Select][+][-]
  1. LongInt(MaxLongint) + LongInt(2);
  2. high(int64) + 2; // apparently using unsigned

This however gives an overflow.
Code: Pascal  [Select][+][-]
  1. i32:= high(qword) + 2;

This is all about calculating with constants.

---
If you add variables, then 32 bit vars should use 32 bit math.

But
Code: Pascal  [Select][+][-]
  1. some32bitVar := some64bitVar + 1;
does 64 bit math. It depends on the operands.
The var for storing the result has no influence. the result is typecasted after the math is done.

Thaddy

  • Hero Member
  • *****
  • Posts: 10516
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #7 on: February 08, 2017, 07:36:14 am »
longint, as opposed to integer, which is guaranteed to be 32 bit only, can be 8 bytes when using a 64 bit compiler. And maxlongint is declared as a 32 bit value.
So if you compiled with a 64 bit compiler it will never overflow with your code,,,
See:
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats which is the same for FPC
See also the declaration of maxlongint in systemh.inc

That seems a bug.... If you used a 64 bit compiler.... Did you?

I suppose you did because this code fails on a 32 bit compiler and passes on a 64 bit compiler....
Code: Pascal  [Select][+][-]
  1. program TestOverflowCheck;
  2. {$OVERFLOWCHECKS ON}  //same as $Q+
  3. {$RANGECHECKS ON}        //same as $R+
  4. var
  5.   i32 : Longint;  // not true: longint is a system dependent type
  6.  
  7. begin
  8.   Writeln(MaxLongint);
  9.   i32:= MaxLongint + 2;
  10.   Writeln(i32);
  11.   readln;
  12. end.
  13.  
« Last Edit: February 08, 2017, 08:16:55 am by Thaddy »

Zoran

  • Hero Member
  • *****
  • Posts: 1592
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #8 on: February 08, 2017, 07:47:42 am »
longint, as opposed to integer, which is guaranteed to be 32 bit only, can be 8 bytes when using a 64 bit compiler.

According to FPC docs, Longint is always 32-bit. See: http://www.freepascal.org/docs-html/current/ref/refsu5.html#x27-27003r2

Thaddy

  • Hero Member
  • *****
  • Posts: 10516
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #9 on: February 08, 2017, 07:52:31 am »
Test my code! That doc seems not right and longint seems 8 bytes on a 64 bit system.
If it isn't it would be a Delphi incompatibility.

Can you report back what your results are?
« Last Edit: February 08, 2017, 08:00:02 am by Thaddy »

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 772
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #10 on: February 08, 2017, 08:31:32 am »
Test my code! That doc seems not right and longint seems 8 bytes on a 64 bit system.
The way to test that would be writeln(sizeof(longint)), and it will print "4" on all platforms.

Quote
If it isn't it would be a Delphi incompatibility.
It is indeed an incompatibility with Delphi on 64 bit platforms, but not one we greatly care about. And one that at most will be solvable using an explicit modeswitch, because very little code expects this.

And as to the confusion regarding the original program:
1) constant arithmetic evaluations in FPC are performed using 65 bit (yes, 65, not 64) signed arithmentic
2) look at http://bugs.freepascal.org/view.php?id=28384#c84884 for an explanation of the difference between overflow and range errors, combined with the previous point (there is no overflow of 65 bit arithmetic in that expression; there is a range error when converting the result of that expression to a 32 bit signed value)

Zoran

  • Hero Member
  • *****
  • Posts: 1592
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #11 on: February 08, 2017, 09:06:02 am »
Test my code! That doc seems not right and longint seems 8 bytes on a 64 bit system.
If it isn't it would be a Delphi incompatibility.

Can you report back what your results are?

Actually, Delphi incompatibility is only on iOS, see: http://docwiki.embarcadero.com/Libraries/en/System.Longint

It says:
Quote
On 32-bit platforms and 64-bit Windows platforms, LongInt is an 4-byte signed integer
...
On 64-bit iOS platforms, LongInt is an 8-byte signed integer

Thaddy

  • Hero Member
  • *****
  • Posts: 10516
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #12 on: February 08, 2017, 09:14:08 am »
Now I am confused...
I just asked to close my bug report, but it seems that some longints are more equal than others?

I indeed tested 64 bit Mac

Lupp

  • New Member
  • *
  • Posts: 31
[bug?] (was: Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow)
« Reply #13 on: February 08, 2017, 10:50:19 am »
(Reminder: I am on Win 10 with Lazarus 1.6.2 / FPC 3.0.0.)

The discussion about how FreePascal is treating integer types technically on one or another system is extremely interesting but it should be completely irrelevant in this context.
Range checking executable code has to make sure an error is risen if a var n: Longint gets assigned n := MaxLongint + 1.
In fact the compiler directive {$R+} (supposed to just be short for {$Rangecheckings ON}) causes the error to be reported.
And: If no rangecheck is on n := MaxLongint + 1 results in n = -1 consistently. This again must be independent of the technical details on whatever system and of whether the compiler is running as a 32-bit or as a 64-bit executable or whether it's compiling to this or that. Even the "volatility" of the Longint type @Thaddy pointed to should not change this. If Longint is 64 bit under certain circumstances, Maxlongint must be 2^63 - 1 consistently. 

I would like to emphasize the statement from my previous post:
Quote from: Lupp
...and got: {$R+} and {$Rangechecks ON} both caused checking for index ranges and for integer type overflows as well. {$Q+}and {$OVERFLOWCHECKS ON} both had neither the one nor the other effect.
Shouldn't this be considered a bug?
« Last Edit: February 08, 2017, 11:14:24 am by Lupp »

Nitorami

  • Sr. Member
  • ****
  • Posts: 378
Re: {$OVERFLOWCHECKS ON} does not report an obvious overflow
« Reply #14 on: February 08, 2017, 02:19:23 pm »
Yes, {$Q+} has an effect, but not the one you expect. The directive tells FPC to terminate program with error 215 in case of an arithmetic overflow in the CPU, and this is entirely independent of the variable type you declared, it is a CPU internal issue, i.e. an overflow of the 32-bit or 64-bit ALU.

Experiment with this code. Range check will never cause an error despite the 32-bit overflow, because the checking is done AFTER the multiplication, and the result, when re-assigned to a, is a valid longint.

But {$Q+} traps the error as soon as the overflow occurs within the ALU.

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$R+,Q+}
  3.  
  4. var a: longint;
  5.     i: integer;
  6.  
  7. begin
  8.   a := 1;
  9.   for i := 1 to 40 do begin
  10.     writeln (a);
  11.     a := a * 3;
  12.   end;
  13. end.
  14.  
  15.  

 

TinyPortal © 2005-2018