2006-04-12 23:53:22 +08:00
|
|
|
/* winf.h
|
|
|
|
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
2013-07-20 01:28:34 +08:00
|
|
|
#pragma once
|
2006-04-13 09:37:00 +08:00
|
|
|
/* Hack for Cygwin processes. If the Windows command line length gets slightly
|
|
|
|
bigger than this value, the stack position is suddenly moved up by 64K for
|
|
|
|
no apparent reason, which results in subsequent forks failing. Since Cygwin
|
|
|
|
processes get the full command line as argv array anyway, this only affects
|
2006-05-29 23:51:18 +08:00
|
|
|
the maximum command line length of Cygwin applications which nonsensically
|
|
|
|
have a WinMain instead of a main entry point or which use GetCommandLine. */
|
|
|
|
#define MAXCYGWINCMDLEN 30000
|
2006-04-13 09:37:00 +08:00
|
|
|
|
2006-04-12 23:53:22 +08:00
|
|
|
#define MAXWINCMDLEN 32767
|
2007-12-05 23:10:20 +08:00
|
|
|
#define LINE_BUF_CHUNK (MAX_PATH * 2)
|
2006-04-12 23:53:22 +08:00
|
|
|
|
|
|
|
class av
|
|
|
|
{
|
|
|
|
char **argv;
|
|
|
|
int calloced;
|
|
|
|
public:
|
|
|
|
int argc;
|
|
|
|
bool win16_exe;
|
Cygwin: execve: drop argument size limit
Before commit 44f73c5a6206 ("Cygwin: Fix segfalt when too many command
line args are specified.") we had no actual argument size limit, except
for the fact that the child process created another copy of the argv
array on the stack, which could result in a stack overflow and a
subsequent SEGV. Commit 44f73c5a6206 changed that by allocating the
additional argv array via malloc, and it introduced a new SC_ARG_MAX
limit along the lines of the typical Linux limit.
However, this new limit is artificial. Cygwin allocates all argument
and environment data on the cygheap. We only run out of ARG_MAX space
if we're out of memory resources.
Change argument size handling accordingly:
- Drop the args size check from child_info_spawn::worker.
- Return -1 from sysconf (SC_ARG_MAX), i. e., the argument size limit
is undefined.
- Change argv handling in class av, so that a failing cmalloc is not
fatal. This allows the parent process to return E2BIG if it's out
of cygheap resources.
- In the child, add a check around the new malloc call, so that it
doesn't result in a SEGV if the child process gets unexpectedly into
an ENOMEM situation at this point. In this (unlikely) case, proceed
with the original __argv array instead. Add comment to explain why.
Fixes: 44f73c5a6206 ("Cygwin: Fix segfalt when too many command line args are specified.")
Tested-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2023-08-29 17:55:10 +08:00
|
|
|
av () : argv (NULL), argc (0) {}
|
|
|
|
av (int ac_in, const char * const *av_in)
|
|
|
|
: calloced (0), win16_exe (false)
|
2006-04-12 23:53:22 +08:00
|
|
|
{
|
Cygwin: execve: drop argument size limit
Before commit 44f73c5a6206 ("Cygwin: Fix segfalt when too many command
line args are specified.") we had no actual argument size limit, except
for the fact that the child process created another copy of the argv
array on the stack, which could result in a stack overflow and a
subsequent SEGV. Commit 44f73c5a6206 changed that by allocating the
additional argv array via malloc, and it introduced a new SC_ARG_MAX
limit along the lines of the typical Linux limit.
However, this new limit is artificial. Cygwin allocates all argument
and environment data on the cygheap. We only run out of ARG_MAX space
if we're out of memory resources.
Change argument size handling accordingly:
- Drop the args size check from child_info_spawn::worker.
- Return -1 from sysconf (SC_ARG_MAX), i. e., the argument size limit
is undefined.
- Change argv handling in class av, so that a failing cmalloc is not
fatal. This allows the parent process to return E2BIG if it's out
of cygheap resources.
- In the child, add a check around the new malloc call, so that it
doesn't result in a SEGV if the child process gets unexpectedly into
an ENOMEM situation at this point. In this (unlikely) case, proceed
with the original __argv array instead. Add comment to explain why.
Fixes: 44f73c5a6206 ("Cygwin: Fix segfalt when too many command line args are specified.")
Tested-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2023-08-29 17:55:10 +08:00
|
|
|
argv = (char **) cmalloc (HEAP_1_ARGV, (ac_in + 5) * sizeof (char *));
|
|
|
|
if (argv)
|
|
|
|
{
|
|
|
|
argc = ac_in;
|
|
|
|
memcpy (argv, av_in, (argc + 1) * sizeof (char *));
|
|
|
|
}
|
2006-04-12 23:53:22 +08:00
|
|
|
}
|
|
|
|
void *operator new (size_t, void *p) __attribute__ ((nothrow)) {return p;}
|
|
|
|
~av ()
|
|
|
|
{
|
|
|
|
if (argv)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < calloced; i++)
|
2013-06-20 00:00:43 +08:00
|
|
|
cfree (argv[i]);
|
2006-04-12 23:53:22 +08:00
|
|
|
cfree (argv);
|
|
|
|
}
|
|
|
|
}
|
2022-05-24 03:52:52 +08:00
|
|
|
int unshift (const char *what);
|
2006-04-12 23:53:22 +08:00
|
|
|
operator char **() {return argv;}
|
|
|
|
void all_calloced () {calloced = argc;}
|
|
|
|
void replace0_maybe (const char *arg0)
|
|
|
|
{
|
|
|
|
/* Note: Assumes that argv array has not yet been "unshifted" */
|
|
|
|
if (!calloced)
|
|
|
|
{
|
|
|
|
argv[0] = cstrdup1 (arg0);
|
2013-06-20 00:00:43 +08:00
|
|
|
calloced = 1;
|
2006-04-12 23:53:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
void dup_all ()
|
|
|
|
{
|
|
|
|
for (int i = calloced; i < argc; i++)
|
|
|
|
argv[i] = cstrdup1 (argv[i]);
|
2013-06-20 00:00:43 +08:00
|
|
|
calloced = argc;
|
2006-04-12 23:53:22 +08:00
|
|
|
}
|
2013-06-20 01:21:25 +08:00
|
|
|
int setup (const char *, path_conv&, const char *, int, const char *const *,
|
2022-05-24 03:52:52 +08:00
|
|
|
bool);
|
2006-04-12 23:53:22 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class linebuf
|
|
|
|
{
|
|
|
|
size_t ix;
|
|
|
|
char *buf;
|
|
|
|
size_t alloced;
|
2013-07-20 01:28:34 +08:00
|
|
|
public:
|
2006-04-12 23:53:22 +08:00
|
|
|
linebuf () : ix (0), buf (NULL), alloced (0) {}
|
|
|
|
~linebuf () {if (buf) free (buf);}
|
2022-05-24 03:52:52 +08:00
|
|
|
void add (const char *, int);
|
2006-04-12 23:53:22 +08:00
|
|
|
void add (const char *what) {add (what, strlen (what));}
|
2009-08-02 03:52:46 +08:00
|
|
|
void prepend (const char *, int);
|
2022-05-24 03:52:52 +08:00
|
|
|
void finish (bool);
|
|
|
|
bool fromargv(av&, const char *, bool);;
|
2013-07-20 01:28:34 +08:00
|
|
|
operator size_t () const { return ix + 1; }
|
|
|
|
operator const char * () const { return buf; }
|
|
|
|
operator wchar_t * ()
|
|
|
|
{
|
|
|
|
size_t n = ix + 1;
|
|
|
|
/* Note that this malloc'ed buffer is not freed by the destructor.
|
|
|
|
It is up to the caller to do (or not do) that. */
|
|
|
|
wchar_t *wbuf = (wchar_t *) malloc (sizeof (wchar_t) * n);
|
|
|
|
return wcs (wbuf, n);
|
|
|
|
}
|
2013-07-20 06:44:02 +08:00
|
|
|
wchar_t *wcs (wchar_t *wbuf) { return wcs (wbuf, ix + 1); }
|
2013-07-20 01:28:34 +08:00
|
|
|
wchar_t *wcs (wchar_t *wbuf, size_t n)
|
|
|
|
{
|
|
|
|
if (n == 1)
|
|
|
|
wbuf[0] = L'\0';
|
|
|
|
else
|
|
|
|
sys_mbstowcs (wbuf, n, buf);
|
|
|
|
return wbuf;
|
|
|
|
}
|
2006-04-12 23:53:22 +08:00
|
|
|
};
|