[fpc-devel] [Suggestion] Enumeration range-check intrinsic

J. Gareth Moreton gareth at moreton-family.com
Sat Jul 13 13:47:47 CEST 2019


I see your point.  There seems to be some argument because it 
effectively bans the use of enumerations in external data (e.g. a file, 
network packet or third-party API) if there's a chance that the value is 
corrupted or has been tampered with, because sometimes allowing the 
program to crash is not acceptable.  Though misinterpreted, Michael said 
this to me when I mentioned to the effect of "in that case, you could 
only use Integers etc. for external data":

...

With this sentence you forbid storing or communicating enumerated values 
in any way: file, database, over network. It can be used only in a 
computer program and never
leave the context of the running program under any form. Because as soon as
it is somehow communicated, there is a chance it becomes invalid in return
communication.

Additionally you must then also abolish typecasting to an enumerated (or
pointers to enumerated values), since that also can be a source of invalid
values for an enumerated.

Or are you realy advocating we write code such as

Case MyInteger of
   0 : MyEnum:=ValueOrd0
   1 : MyEnum:=ValueOrd2;
else
   someError
end;
etc, whenever an integer must be changed to an enumerated ?

IMHO you would reduce the usabilty of enumerateds to almost zero by doing
so.

...

Here lies the problem - if you have a enumeration stored in a byte 
field, say, in a file, and there's a chance it's been corrupted, there's 
no reliable way to detect that, since even typecasting may not be 
reliable, and once again I'm implying that enums are unsafe to use, but 
right now, what else can one do?

Gareth aka. Kit


On 13/07/2019 12:28, Martin Frb wrote:
> On 11/07/2019 15:46, J. Gareth Moreton wrote:
>>
>> For my personal point of view, I would like these operators to be the 
>> exception to the rule of the compiler assuming an enum always 
>> contains a valid value,
>
> As much as I would like to agree with you (and yes I think such a 
> check, if possible, would be desirable - even if it meant to ignore 
> certain language design principles), it is indeed not possible.
> Maybe it would be today (as in today's fpc implementation), maybe not. 
> I do not know.
>
> But it would not be future safe.
>
> Lets say "fpc breaks the rule for "is/as" and only for those".
>
>   FooEnum := SomeApi();
>   if not (FooEnum is TFooEnum) then FooEnum := low(TFooEnum);
>
> Now we do *not* know what the optimizer does in the first line. And 
> that is the problem.
> On some platform (that we have no clue of today), the compiler may 
> store the value bitpacked into a temp var/register. The storage is 
> shared with other values.
> If the result of "SomeApi()" is out of bounds, it might overwrite one 
> of the other values stored in that var/register.
> The "is" can only check the part of the storage actually meant to be 
> used by the enum. The change to the other value goes unnoticed.
>
> So in such a future case, the is may do what you expect. A later "case 
> FooEnum" will be ok, as FooEnum is "forced" to be valid.
> But your program still crashes, due to the other var being modified 
> unexpectedly.
>
> Yes that may sound far fetched. But maybe some embedded system, with 
> scarce resources requires such behaviour?
>
> ----------------
> Maybe a possible solution would be based on:
>
> On 13/07/2019 12:48, Jonas Maebe wrote:
>> In Delphi's type system (and in C, C++, and C#), the valid values for 
>> an enum are always all values that fit within its storage size, and 
>> that storage size is fixed.
>
> Create such an enum type in fpc too (as a new type / assignment 
> compatible with the current enum)
>
>   {modeswitch StorageSizeValidEnum}
>   type TFullFooEnum = (a,b,c);
>
> would treat all values of the (unpacked) storage as valid.
> As a consequence:
>  - it can not be packed / it would keep its full size
>  - many optimizations can not be applied
>
> But for such a type, that has explicitly been defined as having all 
> the other values, you could use "is".
> Of course not straight forward. Because now  255 is a valid value for 
> that enum, so "is" would return true. But with:
>
>   {modeswitch StorageSizeValidEnum on}
>   type TFullFooEnum = (a,b,c);
>   {modeswitch StorageSizeValidEnum off}
>   type TFooEnum = (a,b,c);
>
> this would work:
>   if  FullFooEnum is TFooEnum then
>
> Since this is only/mainly used for "external" data, the extra type def 
> would not be to much overhead.
>
> Of course, it is merely syntactical sugar, since it is identical too
>   type TFullFooEnum = integer; //or whatever represents the storage size
>   type TFooEnum = (a,b,c);
>
> It only allows to have named values for that "integer"
> _______________________________________________
> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>
>

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus



More information about the fpc-devel mailing list