http://bugs.winehq.org/show_bug.cgi?id=10618
Summary: dll/kernel32/process.c build_argv returns incorrect argv array for a given command line string Product: Wine Version: CVS/GIT Platform: Other OS/Version: other Status: UNCONFIRMED Severity: enhancement Priority: P2 Component: wine-kernel AssignedTo: wine-bugs@winehq.org ReportedBy: felix@compsoc.nuigalway.ie
Created an attachment (id=9421) --> (http://bugs.winehq.org/attachment.cgi?id=9421) Additional traces to allow bug to be seen
When building the argv array to send to a new process started by another within wine, the function build_argv in dlls/kernel32/process.c fails to return an array argv correctly.
In the case of msiexec being the target program, this has necessitated a custom command line parse that reconstructs the the correct argv.
Application that highlights this behaviour is the Excel Viewer installer.
The problem was discovered when examining bug 9628 to see why a patch to use the standard command line parser call was reverted in favour of a custom parser internal to msiexec.
You will need to apply the attached patch to be able to see the broken behaviour, it basically adds some additional traces and also increases the debug buffer so that the full command line can be seen when using the debug functions to print.
Steps to reproduce: 1. Apply patch, rebuild wine, and install as necessary. adds TRACES that allow you to see the contents of argv 2. Download the Microsoft Excel Viewer 2003 installer from Microsoft 3. Run the installer with the following environment variable set on the command line "WINEDEBUG=+msiexec,+process" 4. Check for the lines outputting "trace:process:build_argv cmdlineW = ..." command line being sent to new process "trace:process:build_argv resulting argv[]" + a number of lines following outputting the contents of the constructed argv array. "trace:msiexec:main argv[0]..." and a number of lines following.
5. Exit installation dialogs by cancelling 6. Run installation of msi directly by using the command line printed out by the first trace described in step 4. 7. You should see the difference between what is outputted by the trace displaying "trace:msiexec:main argv[0]..." in step 4 and step 6. The argv seen by msiexec in running step 3 should appear exactly the same as step 6.
Results Observed:
Command line run using built area: WINEPREFIX=/tmp/winebug9628/ WINEDEBUG=+msiexec,+process ./wine ~/tmp/xlviewer.exe
output from step 4: 1. "trace:process:build_argv cmdlineW = ..."
trace:process:build_argv cmdlineW = L""c:\windows\system32\msiexec.exe" /I C:\windows\temp\IXP030.TMP\XLVIEW.MSI CDCACHE="2" LAUNCHEDFROMSETUP="1" SETUPEXEPATH="C:\windows\temp\IXP030.TMP\" SETUPEXENAME="SETUP.EXE" /lpiwaeo "C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054)_Task(0001).txt" CDCACHE="0" DWSETUPLOGFILE="C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054).txt" DWMSILOGFILE="C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054)_Task(0001).txt""
2. "trace:process:build_argv resulting argv[]" + following lines
trace:process:build_argv resulting argv[] trace:process:build_argv argv[1] = "c:\windows\system32\msiexec.exe" trace:process:build_argv argv[2] = "/I" trace:process:build_argv argv[3] = "C:\windows\temp\IXP030.TMP\XLVIEW.MSI" trace:process:build_argv argv[4] = "CDCACHE=2" trace:process:build_argv argv[5] = "LAUNCHEDFROMSETUP=1" trace:process:build_argv argv[6] = "SETUPEXEPATH=C:\windows\temp\IXP030.TMP" SETUPEXENAME=SETUP.EXE /lpiwaeo C:\windows\temp\Microsoft" trace:process:build_argv argv[7] = "Office" trace:process:build_argv argv[8] = "Excel" trace:process:build_argv argv[9] = "Viewer" trace:process:build_argv argv[10] = "2003" trace:process:build_argv argv[11] = "Setup(0054)_Task(0001).txt CDCACHE=0 DWSETUPLOGFILE=C:\windows\temp\Microsoft" trace:process:build_argv argv[12] = "Office" trace:process:build_argv argv[13] = "Excel" trace:process:build_argv argv[14] = "Viewer" trace:process:build_argv argv[15] = "2003" trace:process:build_argv argv[16] = "Setup(0054).txt DWMSILOGFILE=C:\windows\temp\Microsoft" trace:process:build_argv argv[17] = "Office" trace:process:build_argv argv[18] = "Excel" trace:process:build_argv argv[19] = "Viewer" trace:process:build_argv argv[20] = "2003" trace:process:build_argv argv[21] = "Setup(0054)_Task(0001).txt"
3. "trace:msiexec:main argv[0]..." and following lines trace:msiexec:main argv[0] = "c:\windows\system32\msiexec.exe" trace:msiexec:main argv[1] = "/I" trace:msiexec:main argv[2] = "C:\windows\temp\IXP030.TMP\XLVIEW.MSI" trace:msiexec:main argv[3] = "CDCACHE=2" trace:msiexec:main argv[4] = "LAUNCHEDFROMSETUP=1" trace:msiexec:main argv[5] = "SETUPEXEPATH=C:\windows\temp\IXP030.TMP" SETUPEXENAME=SETUP.EXE /lpiwaeo C:\windows\temp\Microsoft" trace:msiexec:main argv[6] = "Office" trace:msiexec:main argv[7] = "Excel" trace:msiexec:main argv[8] = "Viewer" trace:msiexec:main argv[9] = "2003" trace:msiexec:main argv[10] = "Setup(0054)_Task(0001).txt CDCACHE=0 DWSETUPLOGFILE=C:\windows\temp\Microsoft" trace:msiexec:main argv[11] = "Office" trace:msiexec:main argv[12] = "Excel" trace:msiexec:main argv[13] = "Viewer" trace:msiexec:main argv[14] = "2003" trace:msiexec:main argv[15] = "Setup(0054).txt DWMSILOGFILE=C:\windows\temp\Microsoft" trace:msiexec:main argv[16] = "Office" trace:msiexec:main argv[17] = "Excel" trace:msiexec:main argv[18] = "Viewer" trace:msiexec:main argv[19] = "2003" trace:msiexec:main argv[20] = "Setup(0054)_Task(0001).txt"
Output from step 6 in running the following command line in the built area: WINEPREFIX=/tmp/winebug9628/ WINEDEBUG=+msiexec,+process ./programs/msiexec/msiexec /I C:\windows\temp\IXP030.TMP\XLVIEW.MSI CDCACHE="2" LAUNCHEDFROMSETUP="1" SETUPEXEPATH="C:\windows\temp\IXP030.TMP\" SETUPEXENAME="SETUP.EXE" /lpiwaeo "C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054)_Task(0001).txt" CDCACHE="0" DWSETUPLOGFILE="C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054).txt" DWMSILOGFILE="C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054)_Task(0001).txt"
Note the only change from the line outputted by the traces were all '"' converted to '"' and using the msiexec in the locally built area.
1. "trace:msiexec:main argv[0]..." and following lines trace:msiexec:main argv[0] = "./programs/msiexec/msiexec.exe.so" trace:msiexec:main argv[1] = "/I" trace:msiexec:main argv[2] = "C:\windows\temp\IXP030.TMP\XLVIEW.MSI" trace:msiexec:main argv[3] = "CDCACHE=2" trace:msiexec:main argv[4] = "LAUNCHEDFROMSETUP=1" trace:msiexec:main argv[5] = "SETUPEXEPATH=C:\windows\temp\IXP030.TMP" trace:msiexec:main argv[6] = "SETUPEXENAME=SETUP.EXE" trace:msiexec:main argv[7] = "/lpiwaeo" trace:msiexec:main argv[8] = "C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054)_Task(0001).txt" trace:msiexec:main argv[9] = "CDCACHE=0" trace:msiexec:main argv[10] = "DWSETUPLOGFILE=C:\windows\temp\Microsoft Office Excel Viewer 2003 Setup(0054).txt"
Which is not the same as previously got when msiexec was called by the setup exe.
http://bugs.winehq.org/show_bug.cgi?id=10618
Darragh Bailey felix@compsoc.nuigalway.ie changed:
What |Removed |Added ---------------------------------------------------------------------------- Severity|enhancement |normal
--- Comment #1 from Darragh Bailey felix@compsoc.nuigalway.ie 2007-11-30 19:14:03 ---
I believe the problem stems from the handling of the following msi property on the command line: SETUPEXEPATH="C:\windows\temp\IXP030.TMP\"
This should resolve to a directory with a slash at the end, however that slash disappears in argv generated by the build_argv function.
http://bugs.winehq.org/show_bug.cgi?id=10618
--- Comment #2 from Darragh Bailey felix@compsoc.nuigalway.ie 2007-11-30 20:09:12 ---
Looking at the first loop in build_argv demonstrates the problem perfectly.
Everything is working fine up until it starts to look at the following string 'S', 'E', 'T', 'U', 'P', 'E', 'X', 'E', 'P', 'A', 'T', 'H', '=', '"', 'C', ':', '', 'w', 'i', 'n', 'd', 'o', 'w', 's', '', 't', 'e', 'm', 'p', '', 'I', 'X', 'P', '0', '3', '1', '.', 'T', 'M', 'P', '', '"', ' ',
At the point it reaches the following characters '', '"', ' ', argc=5, in_quotes=1 & bcount=0
loop on '' causes bcount=1 loop on '"' the causes the following line of code to evaluate as false } else if ((*s=='"') && ((bcount & 1)==0)) {
As a result in_quotes remains at 1 and it doesn't recognise the end of the argument on the space in the following loop.
Looks like it needs an improved test to determine when it has in fact encountered an escaped quote.
http://bugs.winehq.org/show_bug.cgi?id=10618
--- Comment #3 from Darragh Bailey felix@compsoc.nuigalway.ie 2007-11-30 20:14:35 --- Following code snippet causes argv to be created correctly for this case, but its hardly code that should be committed. Need to sit down and actually work out how it should determine what is an escaped quote and when it is just a quote preceded by a backslash.
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index d770fd7..1f19037 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -988,7 +993,7 @@ static char **build_argv( const WCHAR *cmdlineW, int reserved ) } else if (*s=='\') { /* '', count them */ bcount++; - } else if ((*s=='"') && ((bcount & 1)==0)) { + } else if ((*s=='"') && ( ((bcount & 1)==0) || ((*(s-2)!=' ') && (*(s-2)!='\t') && (*(s-2)!='\0')) )) { /* unescaped '"' */ in_quotes=!in_quotes; bcount=0; @@ -1026,7 +1032,7 @@ static char **build_argv( const WCHAR *cmdlineW, int reserved ) bcount++; } else if (*s=='"') { /* '"' */ - if ((bcount & 1)==0) { + if ( ((bcount & 1)==0) || ((*(s-2)!=' ') && (*(s-2)!='\t') && (*(s-2)!='\0')) ) { /* Preceded by an even number of '', this is half that * number of '', plus a '"' which we discard. */
http://bugs.winehq.org/show_bug.cgi?id=10618
Darragh Bailey felix@compsoc.nuigalway.ie changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution| |INVALID
--- Comment #4 from Darragh Bailey felix@compsoc.nuigalway.ie 2008-03-18 18:58:08 --- It appears this is not a bug really. Ran a test by building the following code on windows with the command line: /I C:\DOCUME~1\admin\LOCALS~1\Temp\IXP001.TMP\XLVIEW.MSI CDCACHE="2" LAUNCHEDFROMSETUP="1" SETUPEXEPATH="C:\DOCUME~1\admin\LOCALS~1\Temp\IXP001.TMP" SETUPEXENAME="SETUP.EXE"
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[]) { int i; for(i=0; i<argc; i++) { printf("argv[%d] = "", i); for(int j=0; argv[i][j] != '\0'; j++) { printf("%c", argv[i][j]); } printf(""\n"); } return 0; }
Outputted result was as follows. argv[0] = "printargs.exe" argv[1] = "/I" argv[2] = "C:\DOCUME~1\admin\LOCALS~1\Temp\IXP001.TMP\XLVIEW.MSI" argv[3] = "CDCACHE=2" argv[4] = "LAUNCHEDFROMSETUP=1" argv[5] = "SETUPEXEPATH=C:\DOCUME~1\admin\LOCALS~1\Temp\IXP001.TMP" SETUPEXENAME=SETUP.EXE"
Basically this proves that wine is building the argv correctly, but msiexec has custom handling of the command line since when run with the same command line it has no such problems, and adding the /l*v to see the command line shows that it reads in the properties correctly.
Sorry for the noise
http://bugs.winehq.org/show_bug.cgi?id=10618
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #5 from Austin English austinenglish@gmail.com 2008-10-13 14:38:21 --- Closing invalid.
http://bugs.winehq.org/show_bug.cgi?id=10618
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Version|CVS/GIT |unspecified