comp.lang.ada
 help / color / mirror / Atom feed
* Re: Beware: Rep spec on an enumeration type clause
@ 1997-12-12  0:00 Franco Mazzanti
       [not found] ` <34912418.13716044@news.geccs.gecm.com>
  1997-12-12  0:00 ` Ken Garlington
  0 siblings, 2 replies; 6+ messages in thread
From: Franco Mazzanti @ 1997-12-12  0:00 UTC (permalink / raw)



Rakesh Malhotra wrote:

> We work on safety critical projects.  And if we have a safety critical
> bit of code that defines and uses an enumeration then we use the rep
> clause to provide more than 1 bit separation between adjacent values in
> the enumeration.  That way if 1 bit got corrupted the value could not
> become some other legal value.
>
> Hence type SIGNAL_TYPE is (RED, GREEN);
> for SIGNAL_TYPE use (RED => 16#00#, GREEN => 16#03#);
>
> So if a signal was supposed to be RED, with just a 1 bit corruption it
> could never become GREEN.  Obviously we have these kinds of enum's and
> rep clauses all over the code space, and they are used in arrays to
> index etc etc.    An even worse example (from the coder's point of view)
> is that we create our own BOOLEAN_TYPE with states defined as TRUE_STATE
> and FALSE_STATE ; then give both true and false explicit values; and
> then test for those in "if" statements etc :)  Pretty horrible eh ?
>
> --
> Rakesh.


Since the program behaviour when some invalid object is encountered is
highly
implementation dependent, this approach seems really dangerous to me ...
For example, for example, the following program, compiled with GNAT v.3.09
happily (and legally) produces the output:

> I is neither AA, BB or CC
> I is  AA or BB

with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
   type T is (AA, BB, CC);
   for T use (AA => -1, BB => 10, CC => 20);
   I:T;                -- not initialised
   V:array (T) of Integer;
begin
  if not I'Valid then
     Put_Line("I is neither AA, BB or CC ");
  end if;
   case I is
      when AA..BB =>  -- can be selected if I is invalid
        Put_line("I is AA or BB");
      when CC =>  -- can be selected if I is invalid
        Put_line("I is CC");
         V(CC) := 0;
   end case;
end Main;

------------------------------------------------------------
   Franco Mazzanti
   Istituto di Elaborazione della Informazione
   mazzanti@iei.pi.cnr.it
------------------------------------------------------------





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Beware: Rep spec on an enumeration type clause
       [not found] ` <34912418.13716044@news.geccs.gecm.com>
  1997-12-12  0:00   ` Matthew Heaney
@ 1997-12-12  0:00   ` Ken Garlington
  1 sibling, 0 replies; 6+ messages in thread
From: Ken Garlington @ 1997-12-12  0:00 UTC (permalink / raw)



Brian Orpin wrote:

> In 83 I would have simply checked to see if it was valid by
> 
> Valid := I in T'First .. T'Last;
> 
> Certainly on the Tartan Compiler for C40 this detects any invalid (not
> represented) values of T.

Be careful with this! Consider the following example (not compiled, so
forgive any minor errors):

  type IO_Value is range 0 .. 15;
  for IO_Value'Size use 16;

  Raw_Value : IO_Value;

  Raw_IO.Read ( Raw_Value );
  if Raw_Value not in IO_Value'Range then
    <handle error>
  else
    ...
  end if;

If Raw_IO.Read returns a value out of range 0 .. 15, the check is
NOT GUARANTEED TO WORK. In particular, the TI/Tartan compiler for
the MIL-STD-1750 (among others) will delete the check under almost
all optimization levels (a fact I learned from painful personal
experience), since Raw_Value is "known" to be in the range of its
type upon return from the Read call.

This is at least one of the reasons why 'Valid was introduced in
the first place.

> 
> --
> Brian Orpin    (These thoughts are my own ......... for once!)
> brian.orpin@gecm(dot)com or BrianOrpin@Bigfoot.com
> http://www.borpin.demon.co.uk/  **Anti-spam reply-to**




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Beware: Rep spec on an enumeration type clause
  1997-12-12  0:00 Beware: Rep spec on an enumeration type clause Franco Mazzanti
       [not found] ` <34912418.13716044@news.geccs.gecm.com>
@ 1997-12-12  0:00 ` Ken Garlington
  1 sibling, 0 replies; 6+ messages in thread
From: Ken Garlington @ 1997-12-12  0:00 UTC (permalink / raw)



Franco Mazzanti wrote:
> 
> Rakesh Malhotra wrote:
> 
> > We work on safety critical projects.  And if we have a safety critical
> > bit of code that defines and uses an enumeration then we use the rep
> > clause to provide more than 1 bit separation between adjacent values in
> > the enumeration.  That way if 1 bit got corrupted the value could not
> > become some other legal value.
> >

[snip]

> 
> Since the program behaviour when some invalid object is encountered is
> highly
> implementation dependent, this approach seems really dangerous to me ...
> For example, for example, the following program, compiled with GNAT v.3.09
> happily (and legally) produces the output:
> 
> > I is neither AA, BB or CC
> > I is  AA or BB

You may want to look at Dr. Wichmann's implementation of such a "safe"
boolean
type, as described in an issue of Ada Letters some time back. The
difference is
that Safe_Boolean is defined as an abstract data type, and (I recall)
each
access to such an object is checked within the ADT, with an exception
raised
for invalid values. Thus, the "I is AA or BB" would not be reached when
"I" was
a Safe_Boolean type.

Personally, I don't think the added protection for a single data type is
worth
the complexity, particularly given the availability of more
comprehensive hardware-
based approaches to detecting and handling memory faults, but I wouldn't
describe
the approach as either "wrong" or "dangerous," assuming a proper
implementation.

> 
> ------------------------------------------------------------
>    Franco Mazzanti
>    Istituto di Elaborazione della Informazione
>    mazzanti@iei.pi.cnr.it
> ------------------------------------------------------------




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Beware: Rep spec on an enumeration type clause
       [not found] ` <34912418.13716044@news.geccs.gecm.com>
@ 1997-12-12  0:00   ` Matthew Heaney
       [not found]     ` <349e19ec.16536708@news.geccs.gecm.com>
  1997-12-12  0:00   ` Ken Garlington
  1 sibling, 1 reply; 6+ messages in thread
From: Matthew Heaney @ 1997-12-12  0:00 UTC (permalink / raw)



In article <34912418.13716044@news.geccs.gecm.com>,
brian.orpin@gecm.dot.com wrote:


>>with Ada.Text_IO; use Ada.Text_IO;
>>procedure Main is
>>   type T is (AA, BB, CC);
>>   for T use (AA => -1, BB => 10, CC => 20);
>>   I:T;                -- not initialised

[snip]

>In 83 I would have simply checked to see if it was valid by 
>
>Valid := I in T'First .. T'Last;
>
>Certainly on the Tartan Compiler for C40 this detects any invalid (not
>represented) values of T.

If this works for your implementation, then it's pure surrendipity.  My
expectation is that a compiler will optimize that Boolean expression to
True, since "of course" I has be in the range of T, because it is of type
T.  This particular optimization is unwanted here, which is precisely why
the Valid attribute was added to the language.

This kind of behavior can be especially pernicious if you're using the
object to index an array.  In Ada 83, you can very easily have problems if
the value is outside the range of the array index subtype.  It's exactly
analogous to dereferencing an uninitialized access object.

In Ada 95, things are better.  The language now requires that, even if the
subtype of the index object is in the array index subtype, you're not
allowed to optimize away the range check unless you can prove the index
object has a "sensible" value.  If you try to dereference an array with a
"bad" index, then you might get Constraint_Error, or you might update the
wrong element of the array, but you can't accidently touch "components"
outside the array object.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Beware: Rep spec on an enumeration type clause
       [not found]     ` <349e19ec.16536708@news.geccs.gecm.com>
@ 1997-12-18  0:00       ` Matthew Heaney
       [not found]         ` <349a4134.5569381@news.geccs.gecm.com>
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew Heaney @ 1997-12-18  0:00 UTC (permalink / raw)



In article <349e19ec.16536708@news.geccs.gecm.com>,
brian.orpin@gecm.dot.com wrote:


>
>>If this works for your implementation, then it's pure surrendipity.  My
>>expectation is that a compiler will optimize that Boolean expression to
>>True, since "of course" I has be in the range of T, because it is of type
>>T.  This particular optimization is unwanted here, which is precisely why
>>the Valid attribute was added to the language.
>
>The item 'I' would of course be shared or the subunit optimised such that
>redundant reads were not optimised away.  If the data was internal why
>would you even use 'Valid?  If you need 'Valid for an 83 implementation I
>just assumed that you had prevented the optimisation away of the reads.

I was assuming that the data was read from an external source, and you are
correct in pointing out that it would only make sense to apply the Valid
attribute to external data.   But I'm not clear what your
make-the-object-shared argument means, or what redundant reads have to do
with anything.

If I do this:

package body P is

   O : T;

   procedure Op is
   begin
      <read value of O from an external source>

      if O in T then
         <use value of O>

      else
         <handle error>

      end if;
   end Op;

then no matter what, the predicate is going to get optimised away, because
O is already of type T.  The compiler doesn't know or care that O got its
value from an external source, it just sees an object of type T.

If you ask whether an object of type T is in the range of type T, then "of
course" the answer yes!  In your case, however, the answer may be no, but
the compiler isn't smart enough to know this.  It doesn't make special
optimization exceptions for data it "knows" is read externally.  That's why
you can't use the normal Ada mechanisms (relational expressions, membership
tests) to check for validity, because all of those mechanisms are eligible
for removal by the optimizer.

Valid is special, in the sense that the optimizer is not allowed to
optimize the check away (I think).

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Beware: Rep spec on an enumeration type clause
       [not found]         ` <349a4134.5569381@news.geccs.gecm.com>
@ 1997-12-19  0:00           ` Matthew Heaney
  0 siblings, 0 replies; 6+ messages in thread
From: Matthew Heaney @ 1997-12-19  0:00 UTC (permalink / raw)



In article <349a4134.5569381@news.geccs.gecm.com>, brian.orpin@gecm.dot.com
wrote:

>In 83 it is imperative to check explicitly for valid ranges for external
>data in the absence of the 'Valid attribute.  On previous compilers this
>has been achieved by doing a type cast and forcing it to check.  The
>Tartan compiler always optimises this method away for exactly the reasons
>you state (I presume) so the explicit range check (as recommended by the
>manual) is the best way to check for valid data.

Yes, in Ada 83 you have to check too, I'm just saying there are smarted
ways to do it, ways that are guaranteed to work no matter which compiler
you're using.  For example, suppose I have a 8 bit message_id that has a
specific range:

type Message_Id is range 0 .. 10;
for Message_Id'Size use 16;

and I want to check it for validity (in Ada 83).  Here's what NOT to do:

Id : Message_Id;

procedure Get_Message is
begin
   Read (fd, Id);

   if Id in Message_Id then
      <process id>

   else
      <handle error>

   end if;
end Get_Message;

This is not guaranteed to work, for the reasons I cited earlier.  A better
way to do this is declare a subtype that occupies every value in the base
range of the type, as in

type Message_Id_Base is range 0 .. 255;

subtype Message_Id is Message_Id_Base range 0 .. 10;

Id : Message_Id_Base;  -- note the type here

Now when I do a membership test, 

if Id in Message_Id then -- note type here

then this really does have the behavior you want, and the test can't get
optimized away.  

This is exactly the kind of test you must do for enumeration types. 
Suppose Message_Id is an enumeration type:

type Message_Id is (A, B, C);
for Message_Id (2, 5, 9);

Whatever you do, never ever read into an object of type Message_Id, if the
object can have a value not in the set {2, 5, 9}.  Just ditch the rep
clause and check the value yourself.  Sometimes I also add an extra value
for the subtype:

type Message_Id is (A, B, C, Invalid);

function Get_Message_Id (File : File_Descriptor) return Message_Id is

   Id : Message_Id_Base;
begin
   Read (File, Id);

   case Id is
      when 2 => return A;
      when 5 => return B;
      when 9 => return C;
      when others => return Invalid;
   end case;
end Get_Message_Id;


This is why I think rep clauses for enumeration types don't even need to be
in the language.  You're mixing types that are at fundamentally different
levels of abstraction.  I didn't miss the Valid attribute in Ada 83, and
I'm kind of ho-hum about its presence in Ada 95.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~1997-12-19  0:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1997-12-12  0:00 Beware: Rep spec on an enumeration type clause Franco Mazzanti
     [not found] ` <34912418.13716044@news.geccs.gecm.com>
1997-12-12  0:00   ` Matthew Heaney
     [not found]     ` <349e19ec.16536708@news.geccs.gecm.com>
1997-12-18  0:00       ` Matthew Heaney
     [not found]         ` <349a4134.5569381@news.geccs.gecm.com>
1997-12-19  0:00           ` Matthew Heaney
1997-12-12  0:00   ` Ken Garlington
1997-12-12  0:00 ` Ken Garlington

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox