[fpc-devel] Dangerous optimization in CASE..OF

Michael Van Canneyt michael at freepascal.org
Sun Jul 2 10:40:44 CEST 2017



On Sun, 2 Jul 2017, Martok wrote:

> Hi all,
>
>> The only way to get data with an invalid value in an enum in Pascal is by 
>> using an unchecked (aka explicit) typecast, by executing code without range 
>> checking (assigning an enum from a larger parent enum type into a smaller 
>> sub-enum type), or by having an uninitialised variable.
>
> Turns out this is really not true. There are also as "esoteric" things as using
> Read(File). Or TStream.Read. Or the socket implementation of your choice. Or by
> calling a library function. There are many ways to have an invalid value in an
> enum in any meaningful code. Pretty much everything that is not a direct
> assignment from a constant is a potential candidate.

These cases are without exception covered by the " unchecked (aka explicit) typecast,"
part of Jonas's statement. Including Read(File).

If you use Read(File) you are implicitly telling the compiler that the file
only contains valid values for the enum. If you yourself are not sure of this, 
you must use file of integer instead.

If you check their definitions, you will see that they all use untyped 
buffers to do their work. So all 'type safety' bets are off as soon as 
you use one of these mechanisms. This is not only true of enums, but for
every data type.

The correct pascal way is to do

var
   I : integer;
   M : MyEnum;

begin
   MyStream.ReadBuffer(I,SizeOf(I));
   if (I>=Ord(Low(TMyEnum))) and (I<=Ord(High(TMyEnum))) then
     M:=TMyEnum(I)
   else
     // error
end

Instead of

    MyStream.ReadBuffer(M,SizeOf(M));

Which is inherently not safe, as it uses an untyped buffer.

In essence: 
you are on your own as soon as you use external sources of values for enums.

Michael.



More information about the fpc-devel mailing list