[m-rev.] for review: Handle argv[0] == NULL.

Peter Wang novalazy at gmail.com
Mon Jan 31 13:48:36 AEDT 2022


On some operating systems, e.g. Linux, it is possible to enter main()
with argv[0] == NULL if the parent process calls execve() with
argv[0] == NULL, or equivalently, passing NULL for the argv parameter.

runtime/mercury_wrapper.c:
runtime/mercury_wrapper.h:
    Do not assume argc > 0 and argv[0] != NULL in MR_process_args.
    If argv[0] is NULL then set MR_progname to the empty string
    so users of MR_progname can assume it points to a valid string.

    Add a new global variable MR_progname_is_known to indicate if
    argv[0] was NULL or not.

library/io.m:
    Make io.progname return the default program name if argv[0] was
    NULL.

util/mkinit.c:
    Set MR_progname to a valid string if argv[0] is NULL.
    This is not actually necessary, since, in that case, the subsequent
    call to parse_options() would immediately exit the program
    as no file names will be found in argv.
---
 library/io.m              |  4 ++--
 runtime/mercury_wrapper.c | 25 ++++++++++++++++++++++---
 runtime/mercury_wrapper.h |  3 ++-
 util/mkinit.c             |  4 ++++
 4 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/library/io.m b/library/io.m
index f3cb7d24b..4ca3774fe 100644
--- a/library/io.m
+++ b/library/io.m
@@ -2,7 +2,7 @@
 % vim: ft=mercury ts=4 sw=4 et
 %---------------------------------------------------------------------------%
 % Copyright (C) 1993-2012 The University of Melbourne.
-% Copyright (C) 2013-2021 The Mercury team.
+% Copyright (C) 2013-2022 The Mercury team.
 % This file is distributed under the terms specified in COPYING.LIB.
 %---------------------------------------------------------------------------%
 %
@@ -11551,7 +11551,7 @@ system_temp_dir("", 0, !IO).
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         does_not_affect_liveness, may_not_duplicate],
 "
-    if (MR_progname) {
+    if (MR_progname && MR_progname_is_known) {
         MR_make_aligned_string(PrognameOut, MR_progname);
     } else {
         PrognameOut = DefaultProgname;
diff --git a/runtime/mercury_wrapper.c b/runtime/mercury_wrapper.c
index 5018d667b..cb656b9d5 100644
--- a/runtime/mercury_wrapper.c
+++ b/runtime/mercury_wrapper.c
@@ -328,6 +328,7 @@ enum MR_TimeProfileMethod
 #endif
 
 const char          *MR_progname;
+MR_bool             MR_progname_is_known;
 int                 mercury_argc;   // Not counting progname.
 char                **mercury_argv;
 int                 mercury_exit_status = 0;
@@ -1032,9 +1033,27 @@ MR_make_argv(const char *string,
 static void
 MR_process_args(int argc, char **argv)
 {
-    MR_progname = argv[0];
-    mercury_argc = argc - 1;
-    mercury_argv = argv + 1;
+    // It is possible that argc == 0 and argv[0] == NULL on some operating
+    // systems. Since that is not actually useful, we ensure that MR_progname
+    // is always set to a valid string so that uses of MR_progname do not need
+    // to check if it is NULL.
+
+    if (argc >= 1) {
+        MR_progname = argv[0];
+        mercury_argc = argc - 1;
+        mercury_argv = argv + 1;
+    } else {
+        MR_progname = NULL;
+        mercury_argc = 0;
+        mercury_argv = argv;
+    }
+
+    if (MR_progname == NULL) {
+        MR_progname = "";
+        MR_progname_is_known = MR_FALSE;
+    } else {
+        MR_progname_is_known = MR_TRUE;
+    }
 }
 
 // MR_process_environment_options() is a function to parse the options put
diff --git a/runtime/mercury_wrapper.h b/runtime/mercury_wrapper.h
index 62c210c6c..1b28acff3 100644
--- a/runtime/mercury_wrapper.h
+++ b/runtime/mercury_wrapper.h
@@ -1,7 +1,7 @@
 // vim: ts=4 sw=4 expandtab ft=c
 
 // Copyright (C) 1994-2011 The University of Melbourne.
-// Copyright (C) 2014-2016, 2018 The Mercury team.
+// Copyright (C) 2014-2016, 2018, 2022 The Mercury team.
 // This file is distributed under the terms specified in COPYING.LIB.
 
 // mercury_wrapper.h - defines the interface to mercury_wrapper.c.
@@ -176,6 +176,7 @@ extern  int                 MR_num_complexity_procs;
 #endif
 
 extern const char           *MR_progname;
+extern MR_bool              MR_progname_is_known;
 extern int                  mercury_argc;
 extern char                 **mercury_argv;
 extern int                  mercury_exit_status;
diff --git a/util/mkinit.c b/util/mkinit.c
index 4629a143a..3dfcc4466 100644
--- a/util/mkinit.c
+++ b/util/mkinit.c
@@ -2,6 +2,7 @@
 // vim:sw=4 ts=4 expandtab
 //
 // Copyright (C) 1995-2008, 2010-2012 The University of Melbourne.
+// Copyright (C) 2014-2016, 2019, 2020, 2022 The Mercury team.
 // This file may only be copied under the terms of the GNU General
 // Public License - see the file COPYING in the Mercury distribution.
 
@@ -646,6 +647,9 @@ main(int argc, char **argv)
     int exit_status;
 
     MR_progname = argv[0];
+    if (MR_progname == NULL) {
+        MR_progname = "mkinit";
+    }
 
     parse_options(argc, argv);
 
-- 
2.31.0



More information about the reviews mailing list