[Ada] Improve last exception info availability from C++ handlers
authorOlivier Hainque <hainque@adacore.com>
Mon, 11 Jun 2018 09:19:22 +0000 (09:19 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Mon, 11 Jun 2018 09:19:22 +0000 (09:19 +0000)
commit557b744a6e41a13dd44770dc64e19a34a32092c5
tree9666d6086ce5175b23c9768eb52cb5561871b528
parentfc0e632a9972a43cd40daeacb2884beb421587dd
[Ada] Improve last exception info availability from C++ handlers

The Most_Recent_Exception service failed to provide accurate information on an
Ada exception caught by a C++ handler for foreign exceptions. The service
relies on updates of a "current exception buffer" from live exception objects
at various points of the propagation process and this update was not performed
early enough for the case of foreign exception handlers in non-Ada handlers.

The correction applied here consists in moving one of the updates earlier in
the raise process, just before unwinding starts, then refine the update API to
prevent a redundant copy during the unwinding search phase for the same
exception.

The example below, compiled with

gcc -c b.cc
gnatmake -g main.adb -largs b.o --LINK=g++

is expected to run and display

ada info:
Checking Most_Recent_Exception for CONSTRAINT_ERROR ... OK!

// b.cc

extern "C" {
 void foo ();
 extern void _ada_trigger ();
 extern void _ada_occurrence_info ();
}

void foo ()
{
 try {
   _ada_trigger ();
 } catch (const abi::__foreign_exception &e) {
   printf ("ada info:\n");
   _ada_occurrence_info();
 }
}

-- main.adb

with EH;
procedure Main is
begin
  EH.Foo;
end;

-- eh.adb

with Gnat.Most_Recent_Exception;
with Ada.Text_IO; use Ada.Text_IO;

package body EH is

  procedure Ada_Trigger is
  begin
     raise Constraint_Error;
  end;

  procedure Ada_Occurrence_Info is
  begin
     Check_MRE ("CONSTRAINT_ERROR");
  end;

  function Pre_Check_MRE (Ename : String) return Exception_Id is
     MROA : Exception_Occurrence_Access :=
       GNAT.Most_Recent_Exception.Occurrence_Access;
  begin
     Put ("Checking Most_Recent_Exception for " & Ename & " ... ");

     if MROA = null then
        Put_Line ("Most recent exception occurrence access is NULL");
        return Null_Id;
     else
        return Exception_Identity (MROA.all);
     end if;
  end;

  procedure Diagnose_MRE (MRID : Exception_Id; Ok : Boolean) is
  begin
     if Ok then
        Put_Line ("OK!");
     else
        Put_Line ("Err, Most_Recent_Exception was " & Exception_Name (MRID));
     end if;
  end;

  procedure Check_MRE (Eid : Exception_Id) is
     MRID : Exception_Id := Pre_Check_MRE (Ename => Exception_Name (Eid));
  begin
     Diagnose_MRE (MRID, Ok => Eid = MRID);
  end;

  procedure Check_MRE (Ename : String) is
     MRID : Exception_Id := Pre_Check_MRE (Ename => Ename);
  begin
     Diagnose_MRE (MRID, Ok => Ename = Exception_Name (MRID));
  end;

end;

-- eh.ads

with Ada.Exceptions; use Ada.Exceptions;
package EH is
  procedure Ada_Trigger with
    Export, Convention => C, External_Name => "_ada_trigger";

  procedure Ada_Occurrence_Info with
    Export, Convention => C, External_Name => "_ada_occurrence_info";

  procedure Foo with Import, Convention => C, External_Name => "foo";

  procedure Check_MRE (Eid : Exception_Id);
  procedure Check_MRE (Ename : String);

end;

2018-06-11  Olivier Hainque  <hainque@adacore.com>

gcc/ada/

* libgnat/s-excmac*.ads: Factorize Unwind_Action definitions ...
* libgnat/a-exexpr.adb: ... Here, then add comments describing the
major datastructures associated with the current exception raised.
(Setup_Current_Excep): Accept a "Phase" argument conveying the
unwinding phase during which this subprogram is called.  For an Ada
exception, don't update the current exception buffer from the raised
exception object during SEARCH_PHASE, as this is redundant with the
call now issued just before propagation starts.
(Propagate_GCC_Exception): Move call to Setup_Current_Excep ahead of
the unwinding start, conveying Phase 0.
(Unhandled_Except_Handler): Pass UA_CLEANUP_PHASE as the Phase value on
the call to Setup_Current_Excep.
* raise-gcc.c (personality_body): Pass uw_phases as the Phase argument
on calls to Setup_Current_Excep.

From-SVN: r261426
gcc/ada/ChangeLog
gcc/ada/libgnat/a-exexpr.adb
gcc/ada/libgnat/s-excmac__arm.ads
gcc/ada/libgnat/s-excmac__gcc.ads
gcc/ada/raise-gcc.c