Any program calling Gnat.Traceback.Symbolic.Enable_Cache for
dwarf based symbolization fails with a segmentation violation
when spawned with an inaccurate argv[0] such that it couldn't
be found on PATH.
argv[0] is most often found on PATH. One plausible case where
it isn't is when argv[0] is a mere file name and . isn't on PATH,
which might happen out of imprecise exec calls.
This change robustifies the Traceback.Symbolic implementation
to work in this case as well, by just trying to work with argv[0]
untouched as the executable file to fetch dwarf info from.
Tested on x86_64-pc-linux-gnu, committed on trunk
2018-05-21 Olivier Hainque <hain...@adacore.com>
gcc/ada/
* libgnat/s-trasym__dwarf.adb (Executable_Name): Return argv[0] instead
of empty string when argv[0] couldn't be found on PATH.
(Enable_Cache): Raise Program_Error instead of attempting a null
pointer dereference when the Exec_Module initialization failed.
--- gcc/ada/libgnat/s-trasym__dwarf.adb
+++ gcc/ada/libgnat/s-trasym__dwarf.adb
@@ -151,8 +151,8 @@ package body System.Traceback.Symbolic is
function Executable_Name return String;
-- Returns the executable name as reported by argv[0]. If gnat_argv not
- -- initialized or if argv[0] executable not found in path, function returns
- -- an empty string.
+ -- initialized, return an empty string. If the argv[0] executable is not
+ -- found in the PATH, return it unresolved.
function Get_Executable_Load_Address return System.Address;
pragma Import
@@ -289,6 +289,12 @@ package body System.Traceback.Symbolic is
-- Add all modules
Init_Exec_Module;
+
+ if Exec_Module_State = Failed then
+ raise Program_Error with
+ "cannot enable cache, executable state initialization failed.";
+ end if;
+
Cache_Chain := Exec_Module'Access;
if Include_Modules then
@@ -347,17 +353,33 @@ package body System.Traceback.Symbolic is
return "";
end if;
+ -- See if we can resolve argv[0] to a full path (to a file that we will
+ -- be able to open). If the resolution fails, we were probably spawned
+ -- by an imprecise exec call, typically passing a mere file name as
+ -- argv[0] for a program in the current directory with '.' not on PATH.
+ -- Best we can do is fallback to argv[0] unchanged in this case. If we
+ -- fail opening that downstream, we'll just bail out.
+
declare
- Addr : constant System.Address :=
- locate_exec_on_path (Conv.To_Pointer (Gnat_Argv) (0));
- Result : constant String := Value (Addr);
+ Argv0 : constant System.Address
+ := Conv.To_Pointer (Gnat_Argv) (0);
+
+ Resolved_Argv0 : constant System.Address
+ := locate_exec_on_path (Argv0);
+
+ Exe_Argv : constant System.Address
+ := (if Resolved_Argv0 /= System.Null_Address
+ then Resolved_Argv0
+ else Argv0);
+
+ Result : constant String := Value (Exe_Argv);
begin
-- The buffer returned by locate_exec_on_path was allocated using
- -- malloc, so we should use free to release the memory.
+ -- malloc and we should release this memory.
- if Addr /= Null_Address then
- System.CRTL.free (Addr);
+ if Resolved_Argv0 /= Null_Address then
+ System.CRTL.free (Resolved_Argv0);
end if;
return Result;