mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-01 21:33:09 +02:00
Merge branch 'backport-1544-spawn-async-signal-safety-glib-2-64' into 'glib-2-64'
Backport !1544 “Resolve "calling malloc in fork child is undefined-behaviour"” to glib-2-64 See merge request GNOME/glib!1547
This commit is contained in:
commit
d0e54ef794
@ -1511,7 +1511,7 @@ g_local_file_delete (GFile *file,
|
||||
{
|
||||
int errsv = errno;
|
||||
|
||||
/* Posix allows EEXIST too, but the more sane error
|
||||
/* Posix allows EEXIST too, but the clearer error
|
||||
is G_IO_ERROR_NOT_FOUND, and it's what nautilus
|
||||
expects */
|
||||
if (errsv == EEXIST)
|
||||
|
@ -309,7 +309,7 @@ g_menu_model_real_iterate_item_attributes (GMenuModel *model,
|
||||
else
|
||||
{
|
||||
g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_attributes() "
|
||||
"and fails to return sane values from get_item_attributes()",
|
||||
"and fails to return valid values from get_item_attributes()",
|
||||
G_OBJECT_TYPE_NAME (model));
|
||||
result = NULL;
|
||||
}
|
||||
@ -373,7 +373,7 @@ g_menu_model_real_iterate_item_links (GMenuModel *model,
|
||||
else
|
||||
{
|
||||
g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_links() "
|
||||
"and fails to return sane values from get_item_links()",
|
||||
"and fails to return valid values from get_item_links()",
|
||||
G_OBJECT_TYPE_NAME (model));
|
||||
result = NULL;
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ g_get_console_charset (const char **charset)
|
||||
g_free (emsg);
|
||||
}
|
||||
}
|
||||
/* fall-back to UTF-8 if the rest failed (it's a sane and universal default) */
|
||||
/* fall-back to UTF-8 if the rest failed (it's a universal default) */
|
||||
if (raw == NULL)
|
||||
raw = "UTF-8";
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and
|
||||
destructors, in a sane way, including e.g. on library unload. If not you're on
|
||||
destructors, in a usable way, including e.g. on library unload. If not you're on
|
||||
your own.
|
||||
|
||||
Some compilers need #pragma to handle this, which does not work with macros,
|
||||
|
12
glib/gdate.c
12
glib/gdate.c
@ -83,8 +83,8 @@
|
||||
*
|
||||
* #GDate is simple to use. First you need a "blank" date; you can get a
|
||||
* dynamically allocated date from g_date_new(), or you can declare an
|
||||
* automatic variable or array and initialize it to a sane state by
|
||||
* calling g_date_clear(). A cleared date is sane; it's safe to call
|
||||
* automatic variable or array and initialize it by
|
||||
* calling g_date_clear(). A cleared date is safe; it's safe to call
|
||||
* g_date_set_dmy() and the other mutator functions to initialize the
|
||||
* value of a cleared date. However, a cleared date is initially
|
||||
* invalid, meaning that it doesn't represent a day that exists.
|
||||
@ -146,7 +146,7 @@
|
||||
*
|
||||
* If it's declared on the stack, it will contain garbage so must be
|
||||
* initialized with g_date_clear(). g_date_clear() makes the date invalid
|
||||
* but sane. An invalid date doesn't represent a day, it's "empty." A date
|
||||
* but safe. An invalid date doesn't represent a day, it's "empty." A date
|
||||
* becomes valid after you set it to a Julian day or you set a day, month,
|
||||
* and year.
|
||||
*/
|
||||
@ -259,7 +259,7 @@
|
||||
* g_date_new:
|
||||
*
|
||||
* Allocates a #GDate and initializes
|
||||
* it to a sane state. The new date will
|
||||
* it to a safe state. The new date will
|
||||
* be cleared (as if you'd called g_date_clear()) but invalid (it won't
|
||||
* represent an existing day). Free the return value with g_date_free().
|
||||
*
|
||||
@ -862,7 +862,7 @@ g_date_days_between (const GDate *d1,
|
||||
* @date: pointer to one or more dates to clear
|
||||
* @n_dates: number of dates to clear
|
||||
*
|
||||
* Initializes one or more #GDate structs to a sane but invalid
|
||||
* Initializes one or more #GDate structs to a safe but invalid
|
||||
* state. The cleared dates will not represent an existing date, but will
|
||||
* not contain garbage. Useful to init a date declared on the stack.
|
||||
* Validity can be tested with g_date_valid().
|
||||
@ -2055,7 +2055,7 @@ g_date_compare (const GDate *lhs,
|
||||
* @tm: (not nullable): struct tm to fill
|
||||
*
|
||||
* Fills in the date-related bits of a struct tm using the @date value.
|
||||
* Initializes the non-date parts with something sane but meaningless.
|
||||
* Initializes the non-date parts with something safe but meaningless.
|
||||
*/
|
||||
void
|
||||
g_date_to_struct_tm (const GDate *d,
|
||||
|
@ -178,7 +178,7 @@ GLIB_AVAILABLE_IN_ALL
|
||||
guint g_date_get_iso8601_week_of_year (const GDate *date);
|
||||
|
||||
/* If you create a static date struct you need to clear it to get it
|
||||
* in a sane state before use. You can clear a whole array at
|
||||
* in a safe state before use. You can clear a whole array at
|
||||
* once with the ndates argument.
|
||||
*/
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
|
@ -935,9 +935,8 @@ g_date_time_new_from_unix (GTimeZone *tz,
|
||||
* time zone @tz. The time is as accurate as the system allows, to a
|
||||
* maximum accuracy of 1 microsecond.
|
||||
*
|
||||
* This function will always succeed unless the system clock is set to
|
||||
* truly insane values (or unless GLib is still being used after the
|
||||
* year 9999).
|
||||
* This function will always succeed unless GLib is still being used after the
|
||||
* year 9999.
|
||||
*
|
||||
* You should release the return value by calling g_date_time_unref()
|
||||
* when you are done with it.
|
||||
|
312
glib/gspawn.c
312
glib/gspawn.c
@ -155,12 +155,16 @@ extern char **environ;
|
||||
*/
|
||||
|
||||
|
||||
static gint safe_close (gint fd);
|
||||
|
||||
static gint g_execute (const gchar *file,
|
||||
gchar **argv,
|
||||
gchar **envp,
|
||||
gboolean search_path,
|
||||
gboolean search_path_from_envp);
|
||||
gchar **argv,
|
||||
gchar **argv_buffer,
|
||||
gsize argv_buffer_len,
|
||||
gchar **envp,
|
||||
const gchar *search_path,
|
||||
gchar *search_path_buffer,
|
||||
gsize search_path_buffer_len);
|
||||
|
||||
static gboolean fork_exec_with_pipes (gboolean intermediate_child,
|
||||
const gchar *working_directory,
|
||||
@ -262,6 +266,9 @@ g_spawn_async (const gchar *working_directory,
|
||||
/* Avoids a danger in threaded situations (calling close()
|
||||
* on a file descriptor twice, and another thread has
|
||||
* re-opened it since the first close)
|
||||
*
|
||||
* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)).
|
||||
*/
|
||||
static void
|
||||
close_and_invalidate (gint *fd)
|
||||
@ -270,7 +277,7 @@ close_and_invalidate (gint *fd)
|
||||
return;
|
||||
else
|
||||
{
|
||||
(void) g_close (*fd, NULL);
|
||||
safe_close (*fd);
|
||||
*fd = -1;
|
||||
}
|
||||
}
|
||||
@ -1081,6 +1088,8 @@ g_spawn_check_exit_status (gint exit_status,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static gssize
|
||||
write_all (gint fd, gconstpointer vbuf, gsize to_write)
|
||||
{
|
||||
@ -1104,6 +1113,8 @@ write_all (gint fd, gconstpointer vbuf, gsize to_write)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
G_GNUC_NORETURN
|
||||
static void
|
||||
write_err_and_exit (gint fd, gint msg)
|
||||
@ -1116,6 +1127,8 @@ write_err_and_exit (gint fd, gint msg)
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static int
|
||||
set_cloexec (void *data, gint fd)
|
||||
{
|
||||
@ -1125,8 +1138,10 @@ set_cloexec (void *data, gint fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static gint
|
||||
sane_close (gint fd)
|
||||
safe_close (gint fd)
|
||||
{
|
||||
gint ret;
|
||||
|
||||
@ -1137,11 +1152,13 @@ sane_close (gint fd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
G_GNUC_UNUSED static int
|
||||
close_func (void *data, int fd)
|
||||
{
|
||||
if (fd >= GPOINTER_TO_INT (data))
|
||||
(void) sane_close (fd);
|
||||
(void) safe_close (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1156,6 +1173,8 @@ struct linux_dirent64
|
||||
char d_name[]; /* Filename (null-terminated) */
|
||||
};
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static gint
|
||||
filename_to_fd (const char *p)
|
||||
{
|
||||
@ -1169,7 +1188,7 @@ filename_to_fd (const char *p)
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
{
|
||||
if (!g_ascii_isdigit (c))
|
||||
if (c < '0' || c > '9')
|
||||
return -1;
|
||||
c -= '0';
|
||||
|
||||
@ -1184,6 +1203,8 @@ filename_to_fd (const char *p)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static int
|
||||
safe_fdwalk (int (*cb)(void *data, int fd), void *data)
|
||||
{
|
||||
@ -1200,11 +1221,11 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data)
|
||||
* may be slow on non-Linux operating systems, especially on systems allowing
|
||||
* very high number of open file descriptors.
|
||||
*/
|
||||
gint open_max;
|
||||
gint open_max = -1;
|
||||
gint fd;
|
||||
gint res = 0;
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#if 0 && defined(HAVE_SYS_RESOURCE_H)
|
||||
struct rlimit rl;
|
||||
#endif
|
||||
|
||||
@ -1232,22 +1253,41 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data)
|
||||
}
|
||||
}
|
||||
|
||||
sane_close (dir_fd);
|
||||
safe_close (dir_fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* If /proc is not mounted or not accessible we fall back to the old
|
||||
* rlimit trick */
|
||||
* rlimit trick. */
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
|
||||
open_max = rl.rlim_max;
|
||||
else
|
||||
#if 0 && defined(HAVE_SYS_RESOURCE_H)
|
||||
/* Use getrlimit() function provided by the system if it is known to be
|
||||
* async-signal safe.
|
||||
*
|
||||
* Currently there are no operating systems known to provide a safe
|
||||
* implementation, so this section is not used for now.
|
||||
*/
|
||||
if (getrlimit (RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
|
||||
open_max = rl.rlim_max;
|
||||
#endif
|
||||
open_max = sysconf (_SC_OPEN_MAX);
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
/* Use sysconf() function provided by the system if it is known to be
|
||||
* async-signal safe.
|
||||
*
|
||||
* FreeBSD: sysconf() is included in the list of async-signal safe functions
|
||||
* found in https://man.freebsd.org/sigaction(2).
|
||||
*
|
||||
* OpenBSD: sysconf() is included in the list of async-signal safe functions
|
||||
* found in https://man.openbsd.org/sigaction.2.
|
||||
*/
|
||||
if (open_max < 0)
|
||||
open_max = sysconf (_SC_OPEN_MAX);
|
||||
#endif
|
||||
/* Hardcoded fallback: the default process hard limit in Linux as of 2020 */
|
||||
if (open_max < 0)
|
||||
open_max = 4096;
|
||||
|
||||
for (fd = 0; fd < open_max; fd++)
|
||||
if ((res = cb (data, fd)) != 0)
|
||||
@ -1257,6 +1297,8 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static void
|
||||
safe_closefrom (int lowfd)
|
||||
{
|
||||
@ -1289,8 +1331,10 @@ safe_closefrom (int lowfd)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static gint
|
||||
sane_dup2 (gint fd1, gint fd2)
|
||||
safe_dup2 (gint fd1, gint fd2)
|
||||
{
|
||||
gint ret;
|
||||
|
||||
@ -1301,8 +1345,10 @@ sane_dup2 (gint fd1, gint fd2)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static gint
|
||||
sane_open (const char *path, gint mode)
|
||||
safe_open (const char *path, gint mode)
|
||||
{
|
||||
gint ret;
|
||||
|
||||
@ -1321,6 +1367,8 @@ enum
|
||||
CHILD_FORK_FAILED
|
||||
};
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)) until it calls exec(). */
|
||||
static void
|
||||
do_exec (gint child_err_report_fd,
|
||||
gint stdin_fd,
|
||||
@ -1328,10 +1376,13 @@ do_exec (gint child_err_report_fd,
|
||||
gint stderr_fd,
|
||||
const gchar *working_directory,
|
||||
gchar **argv,
|
||||
gchar **argv_buffer,
|
||||
gsize argv_buffer_len,
|
||||
gchar **envp,
|
||||
gboolean close_descriptors,
|
||||
gboolean search_path,
|
||||
gboolean search_path_from_envp,
|
||||
const gchar *search_path,
|
||||
gchar *search_path_buffer,
|
||||
gsize search_path_buffer_len,
|
||||
gboolean stdout_to_null,
|
||||
gboolean stderr_to_null,
|
||||
gboolean child_inherits_stdin,
|
||||
@ -1349,7 +1400,7 @@ do_exec (gint child_err_report_fd,
|
||||
{
|
||||
/* dup2 can't actually fail here I don't think */
|
||||
|
||||
if (sane_dup2 (stdin_fd, 0) < 0)
|
||||
if (safe_dup2 (stdin_fd, 0) < 0)
|
||||
write_err_and_exit (child_err_report_fd,
|
||||
CHILD_DUP2_FAILED);
|
||||
|
||||
@ -1358,9 +1409,11 @@ do_exec (gint child_err_report_fd,
|
||||
else if (!child_inherits_stdin)
|
||||
{
|
||||
/* Keep process from blocking on a read of stdin */
|
||||
gint read_null = sane_open ("/dev/null", O_RDONLY);
|
||||
g_assert (read_null != -1);
|
||||
sane_dup2 (read_null, 0);
|
||||
gint read_null = safe_open ("/dev/null", O_RDONLY);
|
||||
if (read_null < 0)
|
||||
write_err_and_exit (child_err_report_fd,
|
||||
CHILD_DUP2_FAILED);
|
||||
safe_dup2 (read_null, 0);
|
||||
close_and_invalidate (&read_null);
|
||||
}
|
||||
|
||||
@ -1368,7 +1421,7 @@ do_exec (gint child_err_report_fd,
|
||||
{
|
||||
/* dup2 can't actually fail here I don't think */
|
||||
|
||||
if (sane_dup2 (stdout_fd, 1) < 0)
|
||||
if (safe_dup2 (stdout_fd, 1) < 0)
|
||||
write_err_and_exit (child_err_report_fd,
|
||||
CHILD_DUP2_FAILED);
|
||||
|
||||
@ -1376,9 +1429,11 @@ do_exec (gint child_err_report_fd,
|
||||
}
|
||||
else if (stdout_to_null)
|
||||
{
|
||||
gint write_null = sane_open ("/dev/null", O_WRONLY);
|
||||
g_assert (write_null != -1);
|
||||
sane_dup2 (write_null, 1);
|
||||
gint write_null = safe_open ("/dev/null", O_WRONLY);
|
||||
if (write_null < 0)
|
||||
write_err_and_exit (child_err_report_fd,
|
||||
CHILD_DUP2_FAILED);
|
||||
safe_dup2 (write_null, 1);
|
||||
close_and_invalidate (&write_null);
|
||||
}
|
||||
|
||||
@ -1386,7 +1441,7 @@ do_exec (gint child_err_report_fd,
|
||||
{
|
||||
/* dup2 can't actually fail here I don't think */
|
||||
|
||||
if (sane_dup2 (stderr_fd, 2) < 0)
|
||||
if (safe_dup2 (stderr_fd, 2) < 0)
|
||||
write_err_and_exit (child_err_report_fd,
|
||||
CHILD_DUP2_FAILED);
|
||||
|
||||
@ -1394,8 +1449,8 @@ do_exec (gint child_err_report_fd,
|
||||
}
|
||||
else if (stderr_to_null)
|
||||
{
|
||||
gint write_null = sane_open ("/dev/null", O_WRONLY);
|
||||
sane_dup2 (write_null, 2);
|
||||
gint write_null = safe_open ("/dev/null", O_WRONLY);
|
||||
safe_dup2 (write_null, 2);
|
||||
close_and_invalidate (&write_null);
|
||||
}
|
||||
|
||||
@ -1408,7 +1463,7 @@ do_exec (gint child_err_report_fd,
|
||||
{
|
||||
if (child_setup == NULL)
|
||||
{
|
||||
sane_dup2 (child_err_report_fd, 3);
|
||||
safe_dup2 (child_err_report_fd, 3);
|
||||
set_cloexec (GINT_TO_POINTER (0), 3);
|
||||
safe_closefrom (4);
|
||||
child_err_report_fd = 3;
|
||||
@ -1432,7 +1487,8 @@ do_exec (gint child_err_report_fd,
|
||||
|
||||
g_execute (argv[0],
|
||||
file_and_argv_zero ? argv + 1 : argv,
|
||||
envp, search_path, search_path_from_envp);
|
||||
argv_buffer, argv_buffer_len,
|
||||
envp, search_path, search_path_buffer, search_path_buffer_len);
|
||||
|
||||
/* Exec failed */
|
||||
write_err_and_exit (child_err_report_fd,
|
||||
@ -1565,7 +1621,7 @@ do_posix_spawn (gchar **argv,
|
||||
else if (!child_inherits_stdin)
|
||||
{
|
||||
/* Keep process from blocking on a read of stdin */
|
||||
gint read_null = sane_open ("/dev/null", O_RDONLY | O_CLOEXEC);
|
||||
gint read_null = safe_open ("/dev/null", O_RDONLY | O_CLOEXEC);
|
||||
g_assert (read_null != -1);
|
||||
parent_close_fds[num_parent_close_fds++] = read_null;
|
||||
|
||||
@ -1589,7 +1645,7 @@ do_posix_spawn (gchar **argv,
|
||||
}
|
||||
else if (stdout_to_null)
|
||||
{
|
||||
gint write_null = sane_open ("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
gint write_null = safe_open ("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
g_assert (write_null != -1);
|
||||
parent_close_fds[num_parent_close_fds++] = write_null;
|
||||
|
||||
@ -1613,7 +1669,7 @@ do_posix_spawn (gchar **argv,
|
||||
}
|
||||
else if (stderr_to_null)
|
||||
{
|
||||
gint write_null = sane_open ("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
gint write_null = safe_open ("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
g_assert (write_null != -1);
|
||||
parent_close_fds[num_parent_close_fds++] = write_null;
|
||||
|
||||
@ -1694,6 +1750,11 @@ fork_exec_with_fds (gboolean intermediate_child,
|
||||
gint child_pid_report_pipe[2] = { -1, -1 };
|
||||
guint pipe_flags = cloexec_pipes ? FD_CLOEXEC : 0;
|
||||
gint status;
|
||||
const gchar *chosen_search_path;
|
||||
gchar *search_path_buffer = NULL;
|
||||
gsize search_path_buffer_len = 0;
|
||||
gchar **argv_buffer = NULL;
|
||||
gsize argv_buffer_len = 0;
|
||||
|
||||
#ifdef POSIX_SPAWN_AVAILABLE
|
||||
if (!intermediate_child && working_directory == NULL && !close_descriptors &&
|
||||
@ -1744,8 +1805,50 @@ fork_exec_with_fds (gboolean intermediate_child,
|
||||
}
|
||||
#endif /* POSIX_SPAWN_AVAILABLE */
|
||||
|
||||
/* Choose a search path. This has to be done before calling fork()
|
||||
* as getenv() isn’t async-signal-safe (see `man 7 signal-safety`). */
|
||||
chosen_search_path = NULL;
|
||||
if (search_path_from_envp)
|
||||
chosen_search_path = g_environ_getenv (envp, "PATH");
|
||||
if (search_path && chosen_search_path == NULL)
|
||||
chosen_search_path = g_getenv ("PATH");
|
||||
|
||||
if (chosen_search_path == NULL)
|
||||
{
|
||||
/* There is no 'PATH' in the environment. The default
|
||||
* * search path in libc is the current directory followed by
|
||||
* * the path 'confstr' returns for '_CS_PATH'.
|
||||
* */
|
||||
|
||||
/* In GLib we put . last, for security, and don't use the
|
||||
* * unportable confstr(); UNIX98 does not actually specify
|
||||
* * what to search if PATH is unset. POSIX may, dunno.
|
||||
* */
|
||||
|
||||
chosen_search_path = "/bin:/usr/bin:.";
|
||||
}
|
||||
|
||||
/* Allocate a buffer which the fork()ed child can use to assemble potential
|
||||
* paths for the binary to exec(), combining the argv[0] and elements from
|
||||
* the chosen_search_path. This can’t be done in the child because malloc()
|
||||
* (or alloca()) are not async-signal-safe (see `man 7 signal-safety`).
|
||||
*
|
||||
* Add 2 for the nul terminator and a leading `/`. */
|
||||
search_path_buffer_len = strlen (chosen_search_path) + strlen (argv[0]) + 2;
|
||||
search_path_buffer = g_malloc (search_path_buffer_len);
|
||||
|
||||
/* And allocate a buffer which is 2 elements longer than @argv, so that if
|
||||
* script_execute() has to be called later on, it can build a wrapper argv
|
||||
* array in this buffer. */
|
||||
argv_buffer_len = g_strv_length (argv) + 2;
|
||||
argv_buffer = g_new (gchar *, argv_buffer_len);
|
||||
|
||||
if (!g_unix_open_pipe (child_err_report_pipe, pipe_flags, error))
|
||||
return FALSE;
|
||||
{
|
||||
g_free (search_path_buffer);
|
||||
g_free (argv_buffer);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (intermediate_child && !g_unix_open_pipe (child_pid_report_pipe, pipe_flags, error))
|
||||
goto cleanup_and_fail;
|
||||
@ -1823,10 +1926,13 @@ fork_exec_with_fds (gboolean intermediate_child,
|
||||
stderr_fd,
|
||||
working_directory,
|
||||
argv,
|
||||
argv_buffer,
|
||||
argv_buffer_len,
|
||||
envp,
|
||||
close_descriptors,
|
||||
search_path,
|
||||
search_path_from_envp,
|
||||
chosen_search_path,
|
||||
search_path_buffer,
|
||||
search_path_buffer_len,
|
||||
stdout_to_null,
|
||||
stderr_to_null,
|
||||
child_inherits_stdin,
|
||||
@ -1853,10 +1959,13 @@ fork_exec_with_fds (gboolean intermediate_child,
|
||||
stderr_fd,
|
||||
working_directory,
|
||||
argv,
|
||||
argv_buffer,
|
||||
argv_buffer_len,
|
||||
envp,
|
||||
close_descriptors,
|
||||
search_path,
|
||||
search_path_from_envp,
|
||||
chosen_search_path,
|
||||
search_path_buffer,
|
||||
search_path_buffer_len,
|
||||
stdout_to_null,
|
||||
stderr_to_null,
|
||||
child_inherits_stdin,
|
||||
@ -1984,6 +2093,9 @@ fork_exec_with_fds (gboolean intermediate_child,
|
||||
close_and_invalidate (&child_err_report_pipe[0]);
|
||||
close_and_invalidate (&child_pid_report_pipe[0]);
|
||||
|
||||
g_free (search_path_buffer);
|
||||
g_free (argv_buffer);
|
||||
|
||||
if (child_pid)
|
||||
*child_pid = pid;
|
||||
|
||||
@ -2016,6 +2128,9 @@ fork_exec_with_fds (gboolean intermediate_child,
|
||||
close_and_invalidate (&child_pid_report_pipe[0]);
|
||||
close_and_invalidate (&child_pid_report_pipe[1]);
|
||||
|
||||
g_free (search_path_buffer);
|
||||
g_free (argv_buffer);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -2113,9 +2228,13 @@ cleanup_and_fail:
|
||||
|
||||
/* Based on execvp from GNU C Library */
|
||||
|
||||
static void
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)) until it calls exec(). */
|
||||
static gboolean
|
||||
script_execute (const gchar *file,
|
||||
gchar **argv,
|
||||
gchar **argv_buffer,
|
||||
gsize argv_buffer_len,
|
||||
gchar **envp)
|
||||
{
|
||||
/* Count the arguments. */
|
||||
@ -2123,30 +2242,29 @@ script_execute (const gchar *file,
|
||||
while (argv[argc])
|
||||
++argc;
|
||||
|
||||
/* Construct an argument list for the shell. */
|
||||
{
|
||||
gchar **new_argv;
|
||||
/* Construct an argument list for the shell. */
|
||||
if (argc + 2 > argv_buffer_len)
|
||||
return FALSE;
|
||||
|
||||
new_argv = g_new0 (gchar*, argc + 2); /* /bin/sh and NULL */
|
||||
argv_buffer[0] = (char *) "/bin/sh";
|
||||
argv_buffer[1] = (char *) file;
|
||||
while (argc > 0)
|
||||
{
|
||||
argv_buffer[argc + 1] = argv[argc];
|
||||
--argc;
|
||||
}
|
||||
|
||||
new_argv[0] = (char *) "/bin/sh";
|
||||
new_argv[1] = (char *) file;
|
||||
while (argc > 0)
|
||||
{
|
||||
new_argv[argc + 1] = argv[argc];
|
||||
--argc;
|
||||
}
|
||||
/* Execute the shell. */
|
||||
if (envp)
|
||||
execve (argv_buffer[0], argv_buffer, envp);
|
||||
else
|
||||
execv (argv_buffer[0], argv_buffer);
|
||||
|
||||
/* Execute the shell. */
|
||||
if (envp)
|
||||
execve (new_argv[0], new_argv, envp);
|
||||
else
|
||||
execv (new_argv[0], new_argv);
|
||||
|
||||
g_free (new_argv);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)). */
|
||||
static gchar*
|
||||
my_strchrnul (const gchar *str, gchar c)
|
||||
{
|
||||
@ -2157,12 +2275,17 @@ my_strchrnul (const gchar *str, gchar c)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)) until it calls exec(). */
|
||||
static gint
|
||||
g_execute (const gchar *file,
|
||||
gchar **argv,
|
||||
gchar **envp,
|
||||
gboolean search_path,
|
||||
gboolean search_path_from_envp)
|
||||
g_execute (const gchar *file,
|
||||
gchar **argv,
|
||||
gchar **argv_buffer,
|
||||
gsize argv_buffer_len,
|
||||
gchar **envp,
|
||||
const gchar *search_path,
|
||||
gchar *search_path_buffer,
|
||||
gsize search_path_buffer_len)
|
||||
{
|
||||
if (*file == '\0')
|
||||
{
|
||||
@ -2171,7 +2294,7 @@ g_execute (const gchar *file,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(search_path || search_path_from_envp) || strchr (file, '/') != NULL)
|
||||
if (search_path == NULL || strchr (file, '/') != NULL)
|
||||
{
|
||||
/* Don't search when it contains a slash. */
|
||||
if (envp)
|
||||
@ -2179,41 +2302,31 @@ g_execute (const gchar *file,
|
||||
else
|
||||
execv (file, argv);
|
||||
|
||||
if (errno == ENOEXEC)
|
||||
script_execute (file, argv, envp);
|
||||
if (errno == ENOEXEC &&
|
||||
!script_execute (file, argv, argv_buffer, argv_buffer_len, envp))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean got_eacces = 0;
|
||||
const gchar *path, *p;
|
||||
gchar *name, *freeme;
|
||||
gchar *name;
|
||||
gsize len;
|
||||
gsize pathlen;
|
||||
|
||||
path = NULL;
|
||||
if (search_path_from_envp)
|
||||
path = g_environ_getenv (envp, "PATH");
|
||||
if (search_path && path == NULL)
|
||||
path = g_getenv ("PATH");
|
||||
|
||||
if (path == NULL)
|
||||
{
|
||||
/* There is no 'PATH' in the environment. The default
|
||||
* search path in libc is the current directory followed by
|
||||
* the path 'confstr' returns for '_CS_PATH'.
|
||||
*/
|
||||
|
||||
/* In GLib we put . last, for security, and don't use the
|
||||
* unportable confstr(); UNIX98 does not actually specify
|
||||
* what to search if PATH is unset. POSIX may, dunno.
|
||||
*/
|
||||
|
||||
path = "/bin:/usr/bin:.";
|
||||
}
|
||||
|
||||
path = search_path;
|
||||
len = strlen (file) + 1;
|
||||
pathlen = strlen (path);
|
||||
freeme = name = g_malloc (pathlen + len + 1);
|
||||
name = search_path_buffer;
|
||||
|
||||
if (search_path_buffer_len < pathlen + len + 1)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the file name at the top, including '\0' */
|
||||
memcpy (name + pathlen + 1, file, len);
|
||||
@ -2243,8 +2356,12 @@ g_execute (const gchar *file,
|
||||
else
|
||||
execv (startp, argv);
|
||||
|
||||
if (errno == ENOEXEC)
|
||||
script_execute (startp, argv, envp);
|
||||
if (errno == ENOEXEC &&
|
||||
!script_execute (startp, argv, argv_buffer, argv_buffer_len, envp))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (errno)
|
||||
{
|
||||
@ -2283,7 +2400,6 @@ g_execute (const gchar *file,
|
||||
* something went wrong executing it; return the error to our
|
||||
* caller.
|
||||
*/
|
||||
g_free (freeme);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -2295,8 +2411,6 @@ g_execute (const gchar *file,
|
||||
* error.
|
||||
*/
|
||||
errno = EACCES;
|
||||
|
||||
g_free (freeme);
|
||||
}
|
||||
|
||||
/* Return the error from the last attempt (probably ENOENT). */
|
||||
|
@ -3067,7 +3067,7 @@ test_trap_clear (void)
|
||||
#ifdef G_OS_UNIX
|
||||
|
||||
static int
|
||||
sane_dup2 (int fd1,
|
||||
safe_dup2 (int fd1,
|
||||
int fd2)
|
||||
{
|
||||
int ret;
|
||||
@ -3319,7 +3319,7 @@ g_test_trap_fork (guint64 usec_timeout,
|
||||
if (fd0 < 0)
|
||||
g_error ("failed to open /dev/null for stdin redirection");
|
||||
}
|
||||
if (sane_dup2 (stdout_pipe[1], 1) < 0 || sane_dup2 (stderr_pipe[1], 2) < 0 || (fd0 >= 0 && sane_dup2 (fd0, 0) < 0))
|
||||
if (safe_dup2 (stdout_pipe[1], 1) < 0 || safe_dup2 (stderr_pipe[1], 2) < 0 || (fd0 >= 0 && safe_dup2 (fd0, 0) < 0))
|
||||
{
|
||||
errsv = errno;
|
||||
g_error ("failed to dup2() in forked test program: %s", g_strerror (errsv));
|
||||
|
@ -3102,7 +3102,7 @@ g_abort (void)
|
||||
{
|
||||
/* One call to break the debugger */
|
||||
DebugBreak ();
|
||||
/* One call in case CRT does get saner about abort() behaviour */
|
||||
/* One call in case CRT changes its abort() behaviour */
|
||||
abort ();
|
||||
/* And one call to bind them all and terminate the program for sure */
|
||||
ExitProcess (127);
|
||||
|
@ -1120,7 +1120,7 @@ g_variant_type_new_tuple_slow (const GVariantType * const *items,
|
||||
{
|
||||
/* the "slow" version is needed in case the static buffer of 1024
|
||||
* bytes is exceeded when running the normal version. this will
|
||||
* happen only in truly insane code, so it can be slow.
|
||||
* happen only with very unusually large types, so it can be slow.
|
||||
*/
|
||||
GString *string;
|
||||
gint i;
|
||||
|
@ -2321,7 +2321,7 @@ main (int argc, char *argv[])
|
||||
TEST_NEW_FAIL ("(*:0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEFG)XX", 0, G_REGEX_ERROR_NAME_TOO_LONG);
|
||||
TEST_NEW_FAIL ("\\u0100", G_REGEX_RAW | G_REGEX_JAVASCRIPT_COMPAT, G_REGEX_ERROR_CHARACTER_VALUE_TOO_LARGE);
|
||||
|
||||
/* These errors can't really be tested sanely:
|
||||
/* These errors can't really be tested easily:
|
||||
* G_REGEX_ERROR_EXPRESSION_TOO_LARGE
|
||||
* G_REGEX_ERROR_MEMORY_ERROR
|
||||
* G_REGEX_ERROR_SUBPATTERN_NAME_TOO_LONG
|
||||
|
@ -166,7 +166,7 @@ test_spawn_async (void)
|
||||
* Routine if the file descriptor does not exist.
|
||||
*/
|
||||
static void
|
||||
sane_close (int fd)
|
||||
safe_close (int fd)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close (fd);
|
||||
@ -252,10 +252,10 @@ test_spawn_async_with_fds (void)
|
||||
test_pipe[0][0], test_pipe[1][1], test_pipe[2][1],
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
sane_close (test_pipe[0][0]);
|
||||
sane_close (test_pipe[1][1]);
|
||||
safe_close (test_pipe[0][0]);
|
||||
safe_close (test_pipe[1][1]);
|
||||
if (fd_info[2] != STDOUT_PIPE)
|
||||
sane_close (test_pipe[2][1]);
|
||||
safe_close (test_pipe[2][1]);
|
||||
|
||||
data.loop = loop;
|
||||
data.stdout_done = FALSE;
|
||||
@ -297,10 +297,10 @@ test_spawn_async_with_fds (void)
|
||||
|
||||
g_main_context_unref (context);
|
||||
g_main_loop_unref (loop);
|
||||
sane_close (test_pipe[0][1]);
|
||||
sane_close (test_pipe[1][0]);
|
||||
safe_close (test_pipe[0][1]);
|
||||
safe_close (test_pipe[1][0]);
|
||||
if (fd_info[2] != STDOUT_PIPE)
|
||||
sane_close (test_pipe[2][0]);
|
||||
safe_close (test_pipe[2][0]);
|
||||
}
|
||||
|
||||
g_ptr_array_free (argv, TRUE);
|
||||
|
@ -1617,7 +1617,7 @@ object_interface_check_properties (gpointer check_data,
|
||||
|
||||
/* We do a number of checks on the properties of an interface to
|
||||
* make sure that all classes implementing the interface are
|
||||
* overriding the properties in a sane way.
|
||||
* overriding the properties correctly.
|
||||
*
|
||||
* We do the checks in order of importance so that we can give
|
||||
* more useful error messages first.
|
||||
|
@ -2291,7 +2291,7 @@ g_signal_chain_from_overridden_handler (gpointer instance,
|
||||
g_free (error);
|
||||
|
||||
/* we purposely leak the value here, it might not be
|
||||
* in a sane state if an error condition occurred
|
||||
* in a correct state if an error condition occurred
|
||||
*/
|
||||
while (i--)
|
||||
g_value_unset (param_values + i);
|
||||
@ -2347,7 +2347,7 @@ g_signal_chain_from_overridden_handler (gpointer instance,
|
||||
g_free (error);
|
||||
|
||||
/* we purposely leak the value here, it might not be
|
||||
* in a sane state if an error condition occurred
|
||||
* in a correct state if an error condition occurred
|
||||
*/
|
||||
}
|
||||
}
|
||||
@ -3446,7 +3446,7 @@ g_signal_emit_valist (gpointer instance,
|
||||
g_warning ("%s: %s", G_STRLOC, error);
|
||||
g_free (error);
|
||||
/* we purposely leak the value here, it might not be
|
||||
* in a sane state if an error condition occurred
|
||||
* in a correct state if an error condition occurred
|
||||
*/
|
||||
}
|
||||
}
|
||||
@ -3483,7 +3483,7 @@ g_signal_emit_valist (gpointer instance,
|
||||
g_free (error);
|
||||
|
||||
/* we purposely leak the value here, it might not be
|
||||
* in a sane state if an error condition occurred
|
||||
* in a correct state if an error condition occurred
|
||||
*/
|
||||
while (i--)
|
||||
g_value_unset (param_values + i);
|
||||
@ -3519,7 +3519,7 @@ g_signal_emit_valist (gpointer instance,
|
||||
g_free (error);
|
||||
|
||||
/* we purposely leak the value here, it might not be
|
||||
* in a sane state if an error condition occurred
|
||||
* in a correct state if an error condition occurred
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -376,7 +376,7 @@ g_value_set_instance (GValue *value,
|
||||
g_free (error_msg);
|
||||
|
||||
/* we purposely leak the value here, it might not be
|
||||
* in a sane state if an error condition occurred
|
||||
* in a correct state if an error condition occurred
|
||||
*/
|
||||
value_meminit (value, g_type);
|
||||
value_table->value_init (value);
|
||||
@ -440,7 +440,7 @@ g_value_init_from_instance (GValue *value,
|
||||
g_free (error_msg);
|
||||
|
||||
/* we purposely leak the value here, it might not be
|
||||
* in a sane state if an error condition occurred
|
||||
* in a correct state if an error condition occurred
|
||||
*/
|
||||
value_meminit (value, g_type);
|
||||
value_table->value_init (value);
|
||||
|
Loading…
x
Reference in New Issue
Block a user