[Ada] cb1010a failure with GCC sjlj
Arnaud Charlet
charlet@adacore.com
Fri Aug 17 08:07:00 GMT 2007
Tested on i686-linux, committed on trunk
On x86/x86_64-linux, stack checking is achieved by a runtime library
subrogram called from function prologues. This routine is given the sp
value we'd need to reach to allocate the function frame + have enough
spare to propagate an exception, and it does propagate an exception if
this value is outside the current stack boundaries.
The current stack boundaries are evaluated on the first call. The upper
bound was obtained by taking the address of a local variable and the lower
bound obtained by just adding the size, extracted from the storage_size
attribute in tasks.
Using the address of a local object as a base is inaccurate, first because
the local variable position isn't precisely controlled and second because
the routine is never the first in a call chain, so some amount of stack has
already been consumed by callers at this point.
The net result was a shift between the actual stack boundaries and the
perception of these by the stack-checking engine, which could lead it to
believe that some addresses are within-bounds while they are not with
various possible consequences.
This was visible on ACATS cb1010a with setjmp-longjmp exceptions, which
used to die from SEGV because of a missed overflow detection.
The correction applied here consists in the introduction and use of a hook
in the stack-checking operations package to notify which boundary values
should be used, fetched from a linux specific pthread call on this OS.
2007-08-14 Olivier Hainque <hainque@adacore.com>
* s-taprop-linux.adb (Get_Stack_Attributes): New subprogram. Fetch the
stack size and initial stack pointer value for a given task.
(Enter_Task): Get the stack attributes of the task we are entering and
let the stack checking engine know about them.
* s-stchop.adb, s-stchop.ads (Notify_Stack_Attributes): New subprogram.
Let the stack-checking engine know about the initial sp value and stack
size associated with the current task.
(Set_Stack_Info): If a stack base has been notified for the current
task, honor it. Fallback to the previous less accurate method otherwise.
* s-stchop-vxworks.adb (Notify_Stack_Attributes): Dummy body.
-------------- next part --------------
Index: s-taprop-linux.adb
===================================================================
--- s-taprop-linux.adb (revision 127358)
+++ s-taprop-linux.adb (working copy)
@@ -63,8 +63,9 @@ with System.Soft_Links;
-- For example when using the restricted run time, it is replaced by
-- System.Tasking.Restricted.Stages.
+with System.Storage_Elements;
with System.Stack_Checking.Operations;
--- Used for Invalidate_Stack_Cache;
+-- Used for Invalidate_Stack_Cache and Notify_Stack_Attributes;
with Ada.Exceptions;
-- used for Raise_Exception
@@ -85,6 +86,7 @@ package body System.Task_Primitives.Oper
use System.OS_Interface;
use System.Parameters;
use System.OS_Primitives;
+ use System.Storage_Elements;
----------------
-- Local Data --
@@ -175,6 +177,13 @@ package body System.Task_Primitives.Oper
function To_pthread_t is new Ada.Unchecked_Conversion
(unsigned_long, System.OS_Interface.pthread_t);
+ procedure Get_Stack_Attributes
+ (T : Task_Id;
+ ISP : out System.Address;
+ Size : out Storage_Offset);
+ -- Fill ISP and Size with the Initial Stack Pointer value and the
+ -- thread stack size for task T.
+
-------------------
-- Abort_Handler --
-------------------
@@ -705,6 +714,50 @@ package body System.Task_Primitives.Oper
return T.Common.Current_Priority;
end Get_Priority;
+ --------------------------
+ -- Get_Stack_Attributes --
+ --------------------------
+
+ procedure Get_Stack_Attributes
+ (T : Task_Id;
+ ISP : out System.Address;
+ Size : out Storage_Offset)
+ is
+ function pthread_getattr_np
+ (thread : pthread_t;
+ attr : System.Address) return Interfaces.C.int;
+ pragma Import (C, pthread_getattr_np, "pthread_getattr_np");
+
+ function pthread_attr_getstack
+ (attr : System.Address;
+ base : System.Address;
+ size : System.Address) return Interfaces.C.int;
+ pragma Import (C, pthread_attr_getstack, "pthread_attr_getstack");
+
+ Result : Interfaces.C.int;
+
+ Attributes : aliased pthread_attr_t;
+ Stack_Base : aliased System.Address;
+ Stack_Size : aliased Storage_Offset;
+
+ begin
+ Result :=
+ pthread_getattr_np
+ (T.Common.LL.Thread, Attributes'Address);
+ pragma Assert (Result = 0);
+
+ Result :=
+ pthread_attr_getstack
+ (Attributes'Address, Stack_Base'Address, Stack_Size'Address);
+ pragma Assert (Result = 0);
+
+ Result := pthread_attr_destroy (Attributes'Access);
+ pragma Assert (Result = 0);
+
+ ISP := Stack_Base + Stack_Size;
+ Size := Stack_Size;
+ end Get_Stack_Attributes;
+
----------------
-- Enter_Task --
----------------
@@ -726,6 +779,18 @@ package body System.Task_Primitives.Oper
end loop;
Unlock_RTS;
+
+ -- Determine where the task stack starts, how large it is, and let the
+ -- stack checking engine know about it.
+
+ declare
+ Initial_SP : System.Address;
+ Stack_Size : Storage_Offset;
+ begin
+ Get_Stack_Attributes (Self_ID, Initial_SP, Stack_Size);
+ System.Stack_Checking.Operations.Notify_Stack_Attributes
+ (Initial_SP, Stack_Size);
+ end;
end Enter_Task;
--------------
@@ -1141,6 +1206,25 @@ package body System.Task_Primitives.Oper
end if;
end Resume_Task;
+ --------------------
+ -- Stop_All_Tasks --
+ --------------------
+
+ procedure Stop_All_Tasks is
+ begin
+ null;
+ end Stop_All_Tasks;
+
+ -------------------
+ -- Continue_Task --
+ -------------------
+
+ function Continue_Task (T : ST.Task_Id) return Boolean is
+ pragma Unreferenced (T);
+ begin
+ return False;
+ end Continue_Task;
+
----------------
-- Initialize --
----------------
Index: s-stchop.adb
===================================================================
--- s-stchop.adb (revision 127358)
+++ s-stchop.adb (working copy)
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1999-2006, Free Software Foundation, Inc. --
+-- Copyright (C) 1999-2007, Free Software Foundation, Inc. --
-- --
-- GNARL is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -86,6 +86,26 @@ package body System.Stack_Checking.Opera
Cache := Null_Stack;
end Invalidate_Stack_Cache;
+ -----------------------------
+ -- Notify_Stack_Attributes --
+ -----------------------------
+
+ procedure Notify_Stack_Attributes
+ (Initial_SP : System.Address;
+ Size : System.Storage_Elements.Storage_Offset)
+ is
+ My_Stack : constant Stack_Access := Soft_Links.Get_Stack_Info.all;
+
+ -- We piggyback on the 'Limit' field to store what will be used as the
+ -- 'Base' and leave the 'Size' alone to not interfere with the logic in
+ -- Set_Stack_Info below.
+
+ pragma Unreferenced (Size);
+
+ begin
+ My_Stack.Limit := Initial_SP;
+ end Notify_Stack_Attributes;
+
--------------------
-- Set_Stack_Info --
--------------------
@@ -102,7 +122,7 @@ package body System.Stack_Checking.Opera
Limit : Integer;
begin
- -- The order of steps 1 .. 3 is important, see specification.
+ -- The order of steps 1 .. 3 is important, see specification
-- 1) Get the Stack_Access value for the current task
@@ -131,7 +151,14 @@ package body System.Stack_Checking.Opera
end if;
end if;
- My_Stack.Base := Frame_Address;
+ -- If a stack base address has been registered, honor it.
+ -- Fallback to the address of a local object otherwise.
+
+ if My_Stack.Limit /= System.Null_Address then
+ My_Stack.Base := My_Stack.Limit;
+ else
+ My_Stack.Base := Frame_Address;
+ end if;
if Stack_Grows_Down then
Index: s-stchop.ads
===================================================================
--- s-stchop.ads (revision 127358)
+++ s-stchop.ads (working copy)
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1999-2006, Free Software Foundation, Inc. --
+-- Copyright (C) 1999-2007, Free Software Foundation, Inc. --
-- --
-- GNARL is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -42,6 +42,8 @@ pragma Polling (Off);
-- Turn off polling, we do not want polling to take place during stack
-- checking operations. It causes infinite loops and other problems.
+with System.Storage_Elements;
+
package System.Stack_Checking.Operations is
pragma Preelaborate;
@@ -59,6 +61,14 @@ package System.Stack_Checking.Operations
function Stack_Check (Stack_Address : System.Address) return Stack_Access;
-- This version of Stack_Check should not be inlined
+ procedure Notify_Stack_Attributes
+ (Initial_SP : System.Address;
+ Size : System.Storage_Elements.Storage_Offset);
+ -- Register Initial_SP as the initial stack pointer value for the current
+ -- task when it starts and Size as the associated stack area size. This
+ -- should be called once, after the soft-links have been initialized and
+ -- prior to the first "Stack_Check" call.
+
private
Cache : aliased Stack_Access := Null_Stack;
Index: s-stchop-vxworks.adb
===================================================================
--- s-stchop-vxworks.adb (revision 127358)
+++ s-stchop-vxworks.adb (working copy)
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1999-2006, Free Software Foundation, Inc. --
+-- Copyright (C) 1999-2007, Free Software Foundation, Inc. --
-- --
-- GNARL is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -95,6 +95,24 @@ package body System.Stack_Checking.Opera
Cache := Null_Stack;
end Invalidate_Stack_Cache;
+ -----------------------------
+ -- Notify_Stack_Attributes --
+ -----------------------------
+
+ procedure Notify_Stack_Attributes
+ (Initial_SP : System.Address;
+ Size : System.Storage_Elements.Storage_Offset)
+ is
+ -- We retrieve the attributes directly from Set_Stack_Info below, so
+ -- this implementation has nothing to do.
+
+ pragma Unreferenced (Initial_SP);
+ pragma Unreferenced (Size);
+
+ begin
+ null;
+ end Notify_Stack_Attributes;
+
--------------------
-- Set_Stack_Info --
--------------------
@@ -120,7 +138,7 @@ package body System.Stack_Checking.Opera
Task_Info : aliased OS_Stack_Info;
begin
- -- The order of steps 1 .. 3 is important, see specification.
+ -- The order of steps 1 .. 3 is important, see specification
-- 1) Get the Stack_Access value for the current task
More information about the Gcc-patches
mailing list