https://gcc.gnu.org/g:cf703b60e49d39d3ea80f3c23c490bf005481caf
commit r17-945-gcf703b60e49d39d3ea80f3c23c490bf005481caf Author: Ronan Desplanques <[email protected]> Date: Tue Mar 17 15:38:44 2026 +0100 ada: Stop using gnat_envp First, a bit of context: Ada has only had support for manipulating environment variables in the standard library since Ada 2005 and the introduction of Ada.Environment_Variables. Prior to that, GNAT had introduced the implementation-specific Ada.Command_Line.Environment, which still exists today. Until now, Ada.Command_Line.Environment used a global variable, gnat_envp, which must be initialized with envp, the optional third parameter to main in C. When the main was in Ada, the binder generated the appropriate assignment. The rest of the time, it was the responsibility of the user to write this assignment. Failure to do so would cause null pointer dereferences when using Ada.Command_Line.Environment. Although documented in the spec of Ada.Command_Line, this was rather easy to miss. Worse, the assignment caused linking failures in the rather common case of a C GPR project with'ing an Ada GPR project and linking dynamically. Also, Ada.Command_Line.Environment was inconsistent across platforms with regard to how it was affected by calls to putenv. When we added support for the standard Ada.Environment_Variables, the gnat_envp machinery wasn't reused. Instead, another mechanism based on the Unix global variable environ (and its close equivalents on other platforms) was introduced. What this patch does is switch Ada.Command_Line.Environment over to this new environ-based mechanism. All uses of gnat_envp are removed, but the definition itself is kept for backwards compatibility. gcc/ada/ChangeLog: * argv-lynxos178-raven-cert.c: Update comments. * argv.c (gnat_envp): Add comment about it being unused. (__gnat_env_count, __gnat_len_env, __gnat_fill_env): Use __gnat_environ instead of gnat_envp. * bindgen.adb (Command_Line_Used): Update comment. (Gen_Main): Remove gnat_envp assignment generation. Remove generated envp parameter. (Gen_Output_File_Ada): Remove generated envp parameter. * env.h: Make usable as C++. * libgnat/a-colien.ads: Remove comment. * libgnat/a-comlin.ads: Update comment. * targparm.ads: Update comment. Diff: --- gcc/ada/argv-lynxos178-raven-cert.c | 17 +++++++++++---- gcc/ada/argv.c | 43 ++++++++++++++++++++----------------- gcc/ada/bindgen.adb | 13 ++++------- gcc/ada/env.h | 8 +++++++ gcc/ada/libgnat/a-colien.ads | 6 ------ gcc/ada/libgnat/a-comlin.ads | 4 +--- gcc/ada/targparm.ads | 8 +++---- 7 files changed, 53 insertions(+), 46 deletions(-) diff --git a/gcc/ada/argv-lynxos178-raven-cert.c b/gcc/ada/argv-lynxos178-raven-cert.c index 1f4147fb8f6f..5876fea7c042 100644 --- a/gcc/ada/argv-lynxos178-raven-cert.c +++ b/gcc/ada/argv-lynxos178-raven-cert.c @@ -48,13 +48,22 @@ extern "C" { #endif -/* argc and argv of the main program are saved under gnat_argc and gnat_argv, - envp of the main program is saved under gnat_envp. - While gnat_argc and gnat_envp are not needed, they are referenced from - the binder-generated file so they need to be defined here */ +/* argc and argv of the main program are saved under gnat_argc and gnat_argv. + While gnat_argc is not needed, it's referenced from the binder-generated + file so it needs to be defined here */ int gnat_argc = 0; char **gnat_argv = NULL; + +/* It used to be the case that users were required to forward the envp + parameter of main to the variable below when using a non-Ada main. The + consequences for failing to meet the requirement was improper operation of + Ada.Command_Line.Environment. + + Today, users are not required to do anything with gnat_envp and + Ada.Command_Line.Environment does not use it anymore. In fact it's not used + by anything, but we keep its definition so that programs that obey the old + requirement keep linking. */ char **gnat_envp = NULL; int diff --git a/gcc/ada/argv.c b/gcc/ada/argv.c index aed6d2257f15..6d670e1aa5dd 100644 --- a/gcc/ada/argv.c +++ b/gcc/ada/argv.c @@ -37,11 +37,6 @@ gnat_argv are the values as modified by toplev, and these routines are accessed from the Osint package. */ -/* Also routines for accessing the environment from the runtime library. - Gnat_envp is the original envp value as stored by the binder generated - main program, and these routines are accessed from the - Ada.Command_Line.Environment package. */ - #ifdef IN_RTS #include "runtime.h" #include <stdlib.h> @@ -55,24 +50,27 @@ #include "adaint.h" #endif +#include "env.h" + #ifdef __cplusplus extern "C" { #endif -/* argc and argv of the main program are saved under gnat_argc and gnat_argv, - envp of the main program is saved under gnat_envp. */ +/* argc and argv of the main program are saved under gnat_argc and gnat_argv */ int gnat_argc = 0; char **gnat_argv = NULL; -char **gnat_envp = NULL; -#if defined (_WIN32) && !defined (RTX) -/* Note that on Windows environment the environ point to a buffer that could - be reallocated if needed. It means that gnat_envp needs to be updated - before using gnat_envp to point to the right environment space */ -/* for the environ variable definition */ -#define gnat_envp (environ) -#endif +/* It used to be the case that users were required to forward the envp + parameter of main to the variable below when using a non-Ada main. The + consequences for failing to meet the requirement was improper operation of + Ada.Command_Line.Environment. + + Today, users are not required to do anything with gnat_envp and + Ada.Command_Line.Environment does not use it anymore. In fact it's not used + by anything, but we keep its definition so that programs that obey the old + requirement keep linking. */ +char **gnat_envp = NULL; int __gnat_arg_count (void) @@ -100,8 +98,9 @@ int __gnat_env_count (void) { int i; + char **envp = __gnat_environ(); - for (i = 0; gnat_envp[i]; i++) + for (i = 0; envp[i]; i++) ; return i; } @@ -109,8 +108,10 @@ __gnat_env_count (void) int __gnat_len_env (int env_num) { - if (gnat_envp != NULL) - return strlen (gnat_envp[env_num]); + char **envp = __gnat_environ(); + + if (envp != NULL) + return strlen (envp[env_num]); else return 0; } @@ -118,8 +119,10 @@ __gnat_len_env (int env_num) void __gnat_fill_env (char *a, int i) { - if (gnat_envp != NULL) - memcpy (a, gnat_envp[i], strlen (gnat_envp[i])); + char **envp = __gnat_environ(); + + if (envp != NULL) + memcpy (a, envp[i], strlen (envp[i])); } #ifdef __cplusplus diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb index 8e940c314125..2f13cd6dee40 100644 --- a/gcc/ada/bindgen.adb +++ b/gcc/ada/bindgen.adb @@ -61,8 +61,8 @@ package body Bindgen is -- Flag indicating whether the unit Ada.Command_Line is in the closure of -- the partition. This is set by Resolve_Binder_Options, and is used to -- determine whether or not to import and use symbols defined in - -- Ada.Command_Line's support packages (gnat_argc, gnat_argv, gnat_envp - -- and gnat_exit_status). Conservatively, it is always set to True for + -- Ada.Command_Line's support packages (gnat_argc, gnat_argv and + -- gnat_exit_status). Conservatively, it is always set to True for -- non-configurable run-times as parts of the compiler and run-time assume -- these symbols are available and can be imported directly. @@ -2021,8 +2021,7 @@ package body Bindgen is if Command_Line_Args_On_Target then Write_Statement_Buffer; WBI (" (argc : Integer;"); - WBI (" argv : System.Address;"); - WBI (" envp : System.Address)"); + WBI (" argv : System.Address)"); if Exit_Status_Supported_On_Target then WBI (" return Integer"); @@ -2135,7 +2134,6 @@ package body Bindgen is WBI (" gnat_argc := argc;"); WBI (" gnat_argv := argv;"); WBI (" end if;"); - WBI (" gnat_envp := envp;"); WBI (""); end if; @@ -2613,12 +2611,10 @@ package body Bindgen is WBI (""); WBI (" gnat_argc : Integer;"); WBI (" gnat_argv : System.Address;"); - WBI (" gnat_envp : System.Address;"); WBI (""); WBI (" pragma Import (C, gnat_argc);"); WBI (" pragma Import (C, gnat_argv);"); - WBI (" pragma Import (C, gnat_envp);"); end if; -- Define exit status if supported by the target. The exit status is @@ -2723,9 +2719,8 @@ package body Bindgen is if Command_Line_Args_On_Target then Write_Statement_Buffer; WBI (" (argc : Integer;"); - WBI (" argv : System.Address;"); Set_String - (" envp : System.Address)"); + (" argv : System.Address)"); if Exit_Status_Supported_On_Target then Write_Statement_Buffer; diff --git a/gcc/ada/env.h b/gcc/ada/env.h index 29c96fd762fe..5bf69e7f5bbd 100644 --- a/gcc/ada/env.h +++ b/gcc/ada/env.h @@ -29,8 +29,16 @@ * * ****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + extern void __gnat_getenv (char *name, int *len, char **value); extern void __gnat_setenv (char *name, char *value); extern char **__gnat_environ (void); extern void __gnat_unsetenv (char *name); extern void __gnat_clearenv(void); + +#ifdef __cplusplus +} +#endif diff --git a/gcc/ada/libgnat/a-colien.ads b/gcc/ada/libgnat/a-colien.ads index b687f083cea6..a84e3cd52023 100644 --- a/gcc/ada/libgnat/a-colien.ads +++ b/gcc/ada/libgnat/a-colien.ads @@ -29,12 +29,6 @@ -- -- ------------------------------------------------------------------------------ --- Note: Services offered by this package are guaranteed to be platform --- independent as long as no call to GNAT.OS_Lib.Setenv or to C putenv --- routine is done. On some platforms the services below will report new --- environment variables (e.g. Windows) on some others it will not --- (e.g. GNU/Linux and Solaris). - package Ada.Command_Line.Environment is function Environment_Count return Natural; diff --git a/gcc/ada/libgnat/a-comlin.ads b/gcc/ada/libgnat/a-comlin.ads index a7d37a7151f6..f6e2cf2a6fbd 100644 --- a/gcc/ada/libgnat/a-comlin.ads +++ b/gcc/ada/libgnat/a-comlin.ads @@ -100,14 +100,12 @@ package Ada.Command_Line is -- main program, and the following is an example of a complete C main -- program that stores the required information: - -- main(int argc, char **argv, char **envp) + -- main(int argc, char **argv) -- { -- extern int gnat_argc; -- extern char **gnat_argv; - -- extern char **gnat_envp; -- gnat_argc = argc; -- gnat_argv = argv; - -- gnat_envp = envp; -- adainit(); -- adamain(); diff --git a/gcc/ada/targparm.ads b/gcc/ada/targparm.ads index d5004baa85c5..0ece5857ee0e 100644 --- a/gcc/ada/targparm.ads +++ b/gcc/ada/targparm.ads @@ -267,10 +267,10 @@ package Targparm is -- -- This has some specific effects as follows -- - -- The binder generates the gnat_argc/argv/envp variables in the - -- binder file instead of being imported from the run-time library. - -- If Command_Line_Args_On_Target is set to False, then the - -- generation of these variables is suppressed completely. + -- The binder generates the gnat_argc/argv variables in the binder file + -- instead of being imported from the run-time library. If + -- Command_Line_Args_On_Target is set to False, then the generation of + -- these variables is suppressed completely. -- -- The routine __gnat_break_start is defined within the binder file -- instead of being imported from the run-time library.
