[PATCH v3] Cygwin: ssp: Move command-line copy into run_program
Chandru Kumaresan <[email protected]> Thu, 25 Jun 2026 12:21:54 +0000
| Newsgroups | gmane.os.cygwin.patches |
|---|---|
| Message-ID | <PN0P287MB0295A49DE62713D1E8BB8A1392EC2@PN0P287MB0295.INDP287.PROD.OUTLOOK.COM> |
Hi Jon,
> Hmmm... from the explanation above, it seems like this is in the wrong
> place and should be inside run_program, around the call to CreateProcess?
> Otherwise, the same pointer which is passed to CreateProcess and
> potentially has its contents mutated by that is also assigned to
> dll_info[0].name, leading to a potentially corrupted string appearing in
> the DLL-profile table.
> If that supposition is correct, I'd appreciate it if you could come up
> with a follow-up patch to change that.
You are correct — moving the strdup into run_program, just before the
CreateProcess call, is the right fix. Please find the follow-up patch below.
Thanks and regards
K Chandru
Inline Patch
---
winsup/utils/ssp.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/winsup/utils/ssp.c b/winsup/utils/ssp.c
index 84de523be..deae839d6 100644
--- a/winsup/utils/ssp.c
+++ b/winsup/utils/ssp.c
@@ -379,11 +379,27 @@ run_program (char *cmdline)
int tix, i;
HANDLE hThread;
char *string;
+ char *cmdline_copy;
memset (&startup, 0, sizeof (startup));
startup.cb = sizeof (startup);
- if (!CreateProcess (0, cmdline, 0, 0, 0,
+ /* CreateProcess (called with lpApplicationName == NULL) is documented to
+ modify the lpCommandLine buffer in place. dll_info[0].name below points
+ at the caller's original string, which is read later when printing the
+ DLL-profile table, so hand CreateProcess a private writable copy to
+ scribble on instead; otherwise the program name comes back mangled
+ (observed on aarch64-cygwin as 'test_hello.exe' -> 'st_hello.exxee').
+ The copy is only needed for the CreateProcess call and is intentionally
+ leaked rather than freed, as ssp is short-lived. */
+ cmdline_copy = strdup (cmdline);
+ if (!cmdline_copy)
+ {
+ fprintf (stderr, "Out of memory duplicating cmdline\n");
+ exit (1);
+ }
+
+ if (!CreateProcess (0, cmdline_copy, 0, 0, 0,
CREATE_NEW_PROCESS_GROUP
| CREATE_SUSPENDED
| DEBUG_PROCESS
@@ -1029,23 +1045,7 @@ main (int argc, char **argv)
fprintf (stderr, "prun: [" CONTEXT_REG_FMT "," CONTEXT_REG_FMT "] Running '%s'\n",
low_pc, high_pc, argv[optind]);
- {
- /* CreateProcess (called below with lpApplicationName == NULL) is
- documented to modify the lpCommandLine buffer in place. argv[optind]
- points into our own argv, so passing it directly lets CreateProcess
- scribble on it; this was observed on aarch64-cygwin as the command
- line coming back mangled (e.g. 'test_hello.exe' -> 'st_hello.exxee')
- on later use. Pass a private writable copy instead. It is not freed
- because run_program() stores it in dll_info[0].name, which is read
- later when printing the DLL-profile table. */
- char *cmdline_copy = strdup (argv[optind]);
- if (!cmdline_copy)
- {
- fprintf (stderr, "Out of memory duplicating cmdline\n");
- exit (1);
- }
- run_program (cmdline_copy);
- }
+ run_program (argv[optind]);
hdr.lpc = low_pc;
hdr.hpc = high_pc;
--
2.49.0.windows.1
Cygwin-ssp-Move-command-line-copy-into-run_program.patch
(application/octet-stream, 3.8 KB)
From 798d62951882b7c18b427e38a804485bd303e301 Mon Sep 17 00:00:00 2001 From: chandru-mcw <[email protected]> Date: Thu, 25 Jun 2026 17:26:44 +0530 Subject: [PATCH v3] Cygwin: ssp: Move command-line copy into run_program MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous patch duplicated argv[optind] in main() before passing it to run_program(), but run_program() immediately assigns the received pointer to dll_info[0].name and then passes the same pointer to CreateProcess. Since CreateProcess (with lpApplicationName == NULL) may modify its lpCommandLine buffer in place, dll_info[0].name could end up pointing at corrupted data, producing a mangled name in the DLL-profile table. Fix this by performing the strdup inside run_program(), immediately before the CreateProcess call. The original cmdline pointer is stored in dll_info[0].name as before, preserving the intact name for later reporting, while CreateProcess receives the private copy to mutate freely. The copy is intentionally leaked; ssp is short-lived and freeing it would require threading the pointer across the entire debug loop. Revert the main() change from the previous patch so the caller passes argv[optind] directly again. Signed-off-by: Radek Bartoň <[email protected]> Signed-off-by: Thirumalai Nagalingam <[email protected]> Signed-off-by: Chandru Kumaresan <[email protected]> --- winsup/utils/ssp.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/winsup/utils/ssp.c b/winsup/utils/ssp.c index 84de523be..deae839d6 100644 --- a/winsup/utils/ssp.c +++ b/winsup/utils/ssp.c @@ -379,11 +379,27 @@ run_program (char *cmdline) int tix, i; HANDLE hThread; char *string; + char *cmdline_copy; memset (&startup, 0, sizeof (startup)); startup.cb = sizeof (startup); - if (!CreateProcess (0, cmdline, 0, 0, 0, + /* CreateProcess (called with lpApplicationName == NULL) is documented to + modify the lpCommandLine buffer in place. dll_info[0].name below points + at the caller's original string, which is read later when printing the + DLL-profile table, so hand CreateProcess a private writable copy to + scribble on instead; otherwise the program name comes back mangled + (observed on aarch64-cygwin as 'test_hello.exe' -> 'st_hello.exxee'). + The copy is only needed for the CreateProcess call and is intentionally + leaked rather than freed, as ssp is short-lived. */ + cmdline_copy = strdup (cmdline); + if (!cmdline_copy) + { + fprintf (stderr, "Out of memory duplicating cmdline\n"); + exit (1); + } + + if (!CreateProcess (0, cmdline_copy, 0, 0, 0, CREATE_NEW_PROCESS_GROUP | CREATE_SUSPENDED | DEBUG_PROCESS @@ -1029,23 +1045,7 @@ main (int argc, char **argv) fprintf (stderr, "prun: [" CONTEXT_REG_FMT "," CONTEXT_REG_FMT "] Running '%s'\n", low_pc, high_pc, argv[optind]); - { - /* CreateProcess (called below with lpApplicationName == NULL) is - documented to modify the lpCommandLine buffer in place. argv[optind] - points into our own argv, so passing it directly lets CreateProcess - scribble on it; this was observed on aarch64-cygwin as the command - line coming back mangled (e.g. 'test_hello.exe' -> 'st_hello.exxee') - on later use. Pass a private writable copy instead. It is not freed - because run_program() stores it in dll_info[0].name, which is read - later when printing the DLL-profile table. */ - char *cmdline_copy = strdup (argv[optind]); - if (!cmdline_copy) - { - fprintf (stderr, "Out of memory duplicating cmdline\n"); - exit (1); - } - run_program (cmdline_copy); - } + run_program (argv[optind]); hdr.lpc = low_pc; hdr.hpc = high_pc; -- 2.49.0.windows.1