Recent

Author Topic: FPC dealing with overflow  (Read 1282 times)

PascalDragon

  • Hero Member
  • *****
  • Posts: 4573
  • Compiler Developer
Re: FPC dealing with overflow
« Reply #15 on: July 10, 2022, 11:46:19 am »
First, you might possibly do better using the fundamental types listed at https://www.freepascal.org/docs-html/current/ref/refsu4.html#x26-250003.1.1 since things like int8 are really there for compatibility with e.g. OS-level APIs and (I'll probably get in trouble for saying this) might have quirks.

I personally prefer the (U)IntX types, cause there I know what width the type has (I always need to look up whether SmallInt or ShortInt is the signed 8 Bit type). The aliases were added for a reason, so use them.

Second, I believe constants default to int64 unless explicitly cast, irrespective of the type of other variables etc. in an expression.

Constants default to the native integer type or the next largest signed type in which they fit (e.g. a 64-bit value on a 32-bit system would be an Int64 instead of the native LongInt).

It's strange that just because I wrapped it around a variable the compiler ignores the overflow. Also, I thought Pascal would not allow this purely based on them being different types, given the strictness of the language. I guess all integers are of a same base type.

This behavior is compatible to TP and Delphi and makes working with different types oh so convenient. If you need stricter checks then enable range and overflow checks (they are local directives, so you can enable them for one line and disable them again for the next).

I tested wrapping the code around a try except block, and it did output the range error:
Code: Pascal  [Select][+][-]
  1. exception occurred: ERangeError, message: Range check error
I couldn't get it to output the line number where the error occurred, I'm sure there are ways to do it, I didn't find out how. But regardless, this would create a dependency on exceptions. Also, if i simply import sysutils it tells me the error type, but with the memory addresses still.

You can get a dump of the location if you use DumpExceptionBacktrace, but to get line numbers you need to have debug information (e.g. -glw2) enabled.

FreePascal can also cycle unsigned datatypes
Code: Pascal  [Select][+][-]
  1.  uses Math;
  2. var
  3.   X: uint8;
  4.   s: int8;
  5. begin
  6. SetExceptionMask([exOverflow]);
  7.   s := -3;
  8.   X := 15 div s;
  9.   WriteLn('X is now: ', X);
  10.   writeln('Press return to end . . .');
  11.   readln;
  12. end.
So it is always another option.

Please note that the exception mask is for floating point operations (it's in the name of the type: TFPUExceptionMask).

Code: Pascal  [Select][+][-]
  1. program untitled;
  2. {$mode objfpc}{$R+}

I have a question about the this ^. In the document you linked you always add the $mode after program, on my example I placed it before, does it make a difference, isn't it global?

As $R is a local directive it doesn't matter where it is placed as long as it's placed before the instruction you want it to affect. It's then active as long as you don't disable it.

I also noticed you used {R+}  after the program. In the docs, it says that directives like R are set until the are unset or end of unit;
So if I wanted to restrict it to a certain region, i guess I'd have to do {R+} ... {R-}. Correct?

For local handling the following pattern is suggested (as they can be set by command line as well and you might not know what the default was (or you'd need to check with $IfOpt):

Code: Pascal  [Select][+][-]
  1. // with range checking enabled:
  2. {$push}
  3. {$R+}
  4. ...
  5. {$pop}
  6.  
  7. // with range checking disabled:
  8. {$push}
  9. {$R-}
  10. ...
  11. {$pop}

Now it does not matter what options you compile the unit with, the part between the $push and $pop will now have the correct settings for that part of code.

I also saw, in the docs, this example:
Code: Pascal  [Select][+][-]
  1. {$BITPACKING ON}  
  2. Type  
  3.   TMyRecord = packed record  
  4.     B1,B2,B3,B4 : Boolean;  
  5.   end;
I'm guessing the directive ends on "end;" But does it, shouldn't it follow the above requirements?
I think this is related hence the question.

No, the range is until the next change of the corresponding setting or the end of the file.

Now back to my original post, your piece on avoiding range error and overflows is great, but it doesn't really solve my problem.
The real scenario for what my example was simulating, is a situation where you receive a variable, that you have no control over, and you expect it to be a positive value, but it's actually a negative value, you don't know it and it screws your system. There are lots of unexpected bugs like that in c/c++, and sure you can clearly catch it at runtime, and now I know a lot more about how to do it in pascal.

Then you manually check the range upon input and upon further use you can rely on the range being valid.

1. The mode place can be both on top or after the program name, but nowhere else

It does not depend on the module header (program …;, library …;, unit …;, package …;), but on the uses-clause or where it would be (in case the module does not use any other unit).

Hence my comment about a trait system, so that e.g. the variable declared as part of a for-do block can be of a type compatible with both signed and unsigned with errors caught by runtime checking.

And I KNOW that there are multiple things in that last sentence which will cause Sven to go up the wall.

Object Pascal has a static type system, so if you want something that's compatible with both a signed and unsigned type then you need to use a type that can contain both ranges (though you'll reach a limit somewhere, cause there's always a maxium available size). And runtime checks do work in that case, but only if they're enabled, cause they affect performance.

The last sentence is simply computer science based. I wonder if Sarah even to bothers to answer.

I do have a masters degree in computer science, thank you very much... ::)

MarkMLl

  • Hero Member
  • *****
  • Posts: 5213
Re: FPC dealing with overflow
« Reply #16 on: July 10, 2022, 11:58:38 am »
I personally prefer the (U)IntX types, cause there I know what width the type has (I always need to look up whether SmallInt or ShortInt is the signed 8 Bit type). The aliases were added for a reason, so use them.

I was being very cautious in case some of those "C-like" types were susceptible to different checking rules.

Quote
Object Pascal has a static type system, so if you want something that's compatible with both a signed and unsigned type then you need to use a type that can contain both ranges (though you'll reach a limit somewhere, cause there's always a maxium available size). And runtime checks do work in that case, but only if they're enabled, cause they affect performance.

Yes. We've crossed swords over my comments about ** trait-based typing etc. in the past, and I don't think we need to start again here.

** Please note that they were neither "suggestions relating to" nor "requests for", and they were most definitely not "demands for", and they were made in the context that they were incompatible with existing FPC assignment rules.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 4573
  • Compiler Developer
Re: FPC dealing with overflow
« Reply #17 on: July 11, 2022, 01:29:34 pm »
I personally prefer the (U)IntX types, cause there I know what width the type has (I always need to look up whether SmallInt or ShortInt is the signed 8 Bit type). The aliases were added for a reason, so use them.

I was being very cautious in case some of those "C-like" types were susceptible to different checking rules.

No, they're simple aliases to the corresponding base types.

MarkMLl

  • Hero Member
  • *****
  • Posts: 5213
Re: FPC dealing with overflow
« Reply #18 on: July 11, 2022, 01:39:45 pm »
No, they're simple aliases to the corresponding base types.

Thanks.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018