comp.lang.ada
 help / color / mirror / Atom feed
* Re: Interfacing Ada and C (exceptions) for safety-related systems.
  1998-07-23  0:00 Interfacing Ada and C (exceptions) for safety-related systems Dave White
@ 1998-07-23  0:00 ` Robert Dewar
       [not found] ` <6p9e16$j5c$1@mulga.cs.mu.OZ.AU>
  1 sibling, 0 replies; 3+ messages in thread
From: Robert Dewar @ 1998-07-23  0:00 UTC (permalink / raw)


<<After first tests calling C from Ada (using ObjectAda for
Realtime ETS and Microsoft Visual C++) we found,
that errors in C (which are not totally impossible in our code,
like zero division, range checks, pointer problems)
>>


What on earth is a "range check" in C. There are no such, so of course
these non-existent checks do not cause Ada exceptions!

On the other hand, it certainly is nice if something like a zero divide
would raise and propagate the corresaponding exception if it corresponds
to a hardware trap. Of course if it does NOT correspond to a hardware
trap (e.g. numeric overflow on most machines), then of course C does not
check it, and of course there is no exception to catch.






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

* Interfacing Ada and C (exceptions) for safety-related systems.
@ 1998-07-23  0:00 Dave White
  1998-07-23  0:00 ` Robert Dewar
       [not found] ` <6p9e16$j5c$1@mulga.cs.mu.OZ.AU>
  0 siblings, 2 replies; 3+ messages in thread
From: Dave White @ 1998-07-23  0:00 UTC (permalink / raw)


Hello,

We want to build a safety related system (a control computer for
a flight simulator connected to a motion platform). The software
consists of two parts:

* a control program 100% written in Ada95 and
* aircraft models consisting of generated and hand written C code
  (using Mathworks Matlab / Simulink and the C code generator from
   the Real Time Workshop, an Ada code generator is not yet available).

Our current design requires, that both parts are linked in one
executable. We trust the Ada part, but (for worst case scenarios)
have to assume, that the C part is potentially unsafe.

Our safty concept simply requires, that the Ada main detects a failure
in the C part and then shuts down the simulator.

procedure Ada_Main is
begin
  loop
     Execute_C_model;
  end loop;
exception
    when others => Shutdown;
end Ada_Main;

After first tests calling C from Ada (using ObjectAda for
Realtime ETS and Microsoft Visual C++) we found,
that errors in C (which are not totally impossible in our code,
like zero division, range checks, pointer problems)
may not be caught by Ada (Exception handlers).
We did not expect that but had to verify it.

(The native win32 version catches some errors like
zero division, others are not detected).

The behaviour of the program is twofold:

* after some errors in the C part, an exception handler in
  the runtime system is called and the program ends.
  So an exception handler at the end of the Ada main cannot
  catch the error and start some safe shutdown of the machine.

* even worse, after other errors in C, the program continues
  to run with nonsense values.

I think there are some general questions concerning Ada and C
in safety related systems, independent of the used compilers.

* How can an Ada main detect a failing C module and react
  correspondingly?
* Is a safe usage of such interfacing only possible using two
  processes with separated address spaces, to prevent a failing
  C module to kill the Ada main?

Attached is a small example that connects Ada and C and contains
erroneous Ada and corresponding C code. The Ada main catches
errors from erroneous Ada modules. Erroneous C modules kill the
Ada main program or are not detected.

Thanks for any hints.

 Joachim

Dr. Joachim Schr�er
AMST-Systemtechnik GmbH
A-5282 Ranshofen, Austria
Tel.: (++)43 7722 85232 30
E-mail: schroeer@amst.co.at

-- Filename exception.ada
------------------------------------------------------------------------------------

package Diso is
end Diso;
------------------------------------------------------------------------------

with Ada.Exceptions;
with Interfaces.C;

package Diso.Control is

  type Double_Array is array(Positive range <>) of aliased
Interfaces.C.Double;

  -- Purpose: Show different exception handling in Ada and C.

  -- Numeric errors:
  -- Zero division: Both procedures calculate x(1) / u(1) with u(1) =
0.0 to
  -- demonstrate zero division.

  -- Overflow: Both procedures calculate 2.0 * u(2),
  -- where u(2) = double'last.

  -- Range error: Both procedures access x(tid), where
  -- Tid not in x'range.

  -- Null pointer check: Both procedures access an internally
  -- declared pointer, which is null.

  procedure Ada_Execute_Model(State, Input : in     Double_Array;
                              Output       :    out Double_Array;
                              Tid          : in     Interfaces.C.Int);

  procedure C_Execute_Model  (State, Input : access Interfaces.C.Double;

                              Output       : access Interfaces.C.Double;

                              Tid          : in     Interfaces.C.Int);

  procedure Shutdown(Reason : in Ada.Exceptions.Exception_Occurrence);

private

  pragma Import(Convention    => Cdecl,
                Entity        => C_Execute_Model,
                External_Name => "c_execute_model");

end Diso.Control;
------------------------------------------------------------------------------

with Ada.Text_Io;

package body Diso.Control is

  use type Interfaces.C.Double;

  Counter : Natural := 0;

----------------------------------------------------------------------------

  procedure Ada_Execute_Model(State, Input : in     Double_Array;
                              Output       :    out Double_Array;
                              Tid          : in     Interfaces.C.Int) is

    --------------------------
    procedure Zero_Division is
    begin
      Output(1) := State(1) / Input(1);
    end Zero_Division;
    ---------------------
    procedure Overflow is
    begin
      Output(2) := 2.0 * Input(2);
    end Overflow;
    ------------------------
    procedure Range_Error is
    begin
      Output(3) := State(Integer(Tid));
    end Range_Error;
    -------------------------
    procedure Null_Pointer is
      type Double_Access is access Interfaces.C.Double;
      Pointer : Double_Access;
    begin
      Output(4) := Pointer.all;
    end Null_Pointer;
    -----------------
  begin
    Counter := Counter + 1;
    case Counter mod 4 is
      when 1 => Zero_Division;
      when 2 => Overflow;
      when 3 => Range_Error;
      when 0 => Null_Pointer;
      when others => null;
    end case;
  end Ada_Execute_Model;

----------------------------------------------------------------------------

  procedure Shutdown(Reason : in Ada.Exceptions.Exception_Occurrence) is

  begin
    Ada.Text_Io.Put(Ascii.Bel);
    Ada.Text_Io.Put_Line(Ada.Exceptions.Exception_Information(Reason));
    Ada.Text_Io.New_Line;
    Ada.Text_Io.Put("Shutting down DISO ");
    for I in 1 .. 3 loop
      delay 1.0;
      Ada.Text_Io.Put(".");
    end loop;
    Ada.Text_Io.Put_Line(" done.");
    Ada.Text_Io.New_Line;
  end Shutdown;

-----------------------------------------------------------------------------

end Diso.Control;
------------------------------------------------------------------------------

with Ada.Text_Io;
with Ada.Exceptions;
with Interfaces.C;
with Diso.Control;

procedure Diso.Control_Main is

  -- x' = f(x,u,t)
  -- y  = g(x,u,t)
  -- x(1..n), u(1..p), y(1..q)

  N : constant := 4;
  P : constant := 4;
  Q : constant := 4;

  U : Diso.Control.Double_Array(1 .. P) :=
    (1 => 0.0, 2 => Interfaces.C.Double'Last, others => 0.0);
  X : Diso.Control.Double_Array(1 .. N) := (others => 1.0);
  Y : Diso.Control.Double_Array(1 .. Q);
  -----------------------------------------
  procedure Execute(Message : in String) is
    ---------------------
    procedure Continue is
      Input  : String(1..32);
      Length : Natural;
    begin
      Ada.Text_Io.Put("Continue (press return):");
      Ada.Text_Io.Get_Line(Input,Length);
    end Continue;
    -------------
  begin
    Ada.Text_Io.New_Line;

Ada.Text_Io.Put_Line("-----------------------------------------------------");

    Ada.Text_Io.Put_Line("Ada " & Message);
    begin
      Diso.Control.Ada_Execute_Model
        (State  => X,
         Input  => U,
         Output => Y,
         Tid    => 10);
      Ada.Text_Io.Put_Line("*** Ada " & Message & " not detected!");
      Ada.Text_Io.New_Line;
    exception
      when Error: others =>
        Diso.Control.Shutdown(Reason => Error);
    end;
    Continue;

    Ada.Text_Io.New_Line;

Ada.Text_Io.Put_Line("-----------------------------------------------------");

    Ada.Text_Io.Put_Line("C   " & Message);
    begin
      Diso.Control.C_Execute_Model
        (State  => X(X'First)'access,
         Input  => U(U'First)'access,
         Output => Y(Y'First)'access,
         Tid    => 10);
      Ada.Text_Io.Put_Line("*** C " & Message & " not detected!");
      Ada.Text_Io.New_Line;
    exception
      when Error: others =>
        Diso.Control.Shutdown(Reason => Error);
    end;

    Continue;
  end Execute;
  ------------
begin
  loop
    Execute("zero division");
    Execute("overflow");
    Execute("range error");
    Execute("null pointer");
  end loop;
exception
  when Error: others =>
    Diso.Control.Shutdown(Reason => Error);
end Diso.Control_Main;

=========================================================
/* file: diso_control_model.c
   author: alex stuebinger
*/

#include <stdio.h>
/* #include <math.h> */

typedef double * double_array;

extern "C" void __cdecl
c_execute_model(double_array state,
                double_array input,
                double_array output,
                int          tid)

{ static int counter;
  counter++;
  switch(counter % 4)
  {
    case 1: /* zero_division */
      printf("C: output[0] = state[0] / input[0];\n");
      printf("C: output[0] = %e / %e;\n", state[0], input[0]);
      output[0] = state[0] / input[0];
      printf("C: output[0] = %e;\n", output[0]);
      break;
    case 2: /* overflow */
      printf("C: output[1] = 2.0 * input[1];\n");
      printf("C: output[1] = 2.0 * %e;\n", input[1]);
      output[1] = 2.0 * input[1];
/*    output[1] = pow(input[1],100);
      printf("c: output[1] = %f\n", output[1]); */
      printf("C: output[1] = %e;\n", output[1]);
      break;
    case 3: /* range_error */
      printf("C: output[2] = state[%i];\n", tid);
      printf(" where: double state[0..3]; or: state : array(1 .. 4) of
Interfaces.C.Double;\n");
      printf("C: output[2] = %e;\n", state[tid]);
      output[2] = state[tid];
      printf("output[2] = %e;\n", output[2]);
      break;
    case 0: /* null_pointer */
      printf("C: *((int *) 0) = 4;\n");
      *((int *) 0) = 4;
      printf("C: *((int *) 0) = 4; done\n");
      break;
    default: break;
  }
}






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

* Re: Interfacing Ada and C (exceptions) for safety-related systems.
       [not found] ` <6p9e16$j5c$1@mulga.cs.mu.OZ.AU>
@ 1998-07-24  0:00   ` Clayton Weaver
  0 siblings, 0 replies; 3+ messages in thread
From: Clayton Weaver @ 1998-07-24  0:00 UTC (permalink / raw)


If you have the C source, you might try running lclint-2.3i over it before
actually using it.

If not, ...

Regards, Clayton Weaver  cgweav@eskimo.com  (Seattle)

"Would that be 30 gallons of the Summer Paint or 30 gallons of
 the Winter Paint?"




-- 

Regards, Clayton Weaver  cgweav@eskimo.com  (Seattle)

"Would that be 30 gallons of the Summer Paint or 30 gallons of




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

end of thread, other threads:[~1998-07-24  0:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-07-23  0:00 Interfacing Ada and C (exceptions) for safety-related systems Dave White
1998-07-23  0:00 ` Robert Dewar
     [not found] ` <6p9e16$j5c$1@mulga.cs.mu.OZ.AU>
1998-07-24  0:00   ` Clayton Weaver

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