source: trunk/src/lib/quote_argv.c

Last change on this file was 3235, checked in by bird, 7 years ago

lib/quote_argv.c: Fixed heap corruption bug when applying the watcom-passthru hack to an argument needing quoting. We'd continue with the string following the argument and eventually trample the heap. Fix was to use 'continue' in the passthru case.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.4 KB
RevLine 
[1271]1/* $Id: quote_argv.c 3235 2018-10-28 14:15:29Z bird $ */
2/** @file
[2838]3 * quote_argv - Correctly quote argv for spawn, windows specific.
[1527]4 */
5
6/*
[2812]7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
[1271]8 *
[2851]9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
[1271]15 *
[2851]16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
[1271]18 *
[2851]19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * IN THE SOFTWARE.
[1271]26 *
[2851]27 * Alternatively, the content of this file may be used under the terms of the
28 * GPL version 2 or later, or LGPL version 2.1 or later.
[1271]29 */
30
[2851]31
[1271]32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
[2838]35#include "quote_argv.h"
[1271]36#include <stdlib.h>
37#include <string.h>
[2838]38#include <ctype.h>
[1271]39
[2838]40#ifndef KBUILD_OS_WINDOWS
41# error "KBUILD_OS_WINDOWS not defined"
[1674]42#endif
[1271]43
44
[2667]45/**
[2812]46 * Checks if this is an Watcom option where we must just pass thru the string
47 * as-is.
48 *
49 * This is currnetly only used for -d (defining macros).
50 *
51 * @returns 1 if pass-thru, 0 if not.
52 * @param pszArg The argument to consider.
53 */
54static int isWatcomPassThruOption(const char *pszArg)
55{
56 char ch = *pszArg++;
57 if (ch != '-' && ch != '/')
58 return 0;
59 ch = *pszArg++;
60 switch (ch)
61 {
62 /* Example: -d+VAR="string-value" */
63 case 'd':
64 if (ch == '+')
65 ch = *pszArg++;
66 if (!isalpha(ch) && ch != '_')
67 return 0;
68 return 1;
69
70 default:
71 return 0;
72 }
73}
74
75
76/**
[2667]77 * Replaces arguments in need of quoting.
78 *
79 * For details on how MSC parses the command line, see "Parsing C Command-Line
80 * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
81 *
[2912]82 * @returns 0 on success, -1 if out of memory.
[2747]83 * @param argc The argument count.
84 * @param argv The argument vector.
85 * @param fWatcomBrainDamage Set if we're catering for wcc, wcc386 or similar
86 * OpenWatcom tools. They seem to follow some
87 * ancient or home made quoting convention.
[2838]88 * @param fFreeOrLeak Whether to free replaced argv members
89 * (non-zero), or just leak them (zero). This
90 * depends on which argv you're working on.
91 * Suggest doing the latter if it's main()'s argv.
[2667]92 */
[2912]93int quote_argv(int argc, char **argv, int fWatcomBrainDamage, int fFreeOrLeak)
[2667]94{
95 int i;
96 for (i = 0; i < argc; i++)
97 {
[2838]98 char *const pszOrgOrg = argv[i];
[2812]99 const char *pszOrg = pszOrgOrg;
[2667]100 size_t cchOrg = strlen(pszOrg);
101 const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg);
[2747]102 const char *pszProblem = NULL;
[2667]103 if ( pszQuotes
104 || cchOrg == 0
[2747]105 || (pszProblem = (const char *)memchr(pszOrg, ' ', cchOrg)) != NULL
106 || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL
107 || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL
108 || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL
109 || (pszProblem = (const char *)memchr(pszOrg, '&', cchOrg)) != NULL
110 || (pszProblem = (const char *)memchr(pszOrg, '>', cchOrg)) != NULL
111 || (pszProblem = (const char *)memchr(pszOrg, '<', cchOrg)) != NULL
112 || (pszProblem = (const char *)memchr(pszOrg, '|', cchOrg)) != NULL
113 || (pszProblem = (const char *)memchr(pszOrg, '%', cchOrg)) != NULL
114 || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL
[2778]115 || ( !fWatcomBrainDamage
[2779]116 && (pszProblem = (const char *)memchr(pszOrg, '=', cchOrg)) != NULL)
[2894]117 || ( fWatcomBrainDamage
118 && (pszProblem = (const char *)memchr(pszOrg, '\\', cchOrg)) != NULL)
[2667]119 )
120 {
121 char ch;
122 int fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\');
123 size_t cchNew = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2;
[3235]124 char *pszNew = (char *)malloc(cchNew + 1 /*term*/);
[2912]125 if (!pszNew)
126 return -1;
[2667]127
128 argv[i] = pszNew;
129
[2812]130 /* Watcom does not grok stuff like "-i=c:\program files\watcom\h",
131 it think it's a source specification. In that case the quote
132 must follow the equal sign. */
[2747]133 if (fWatcomBrainDamage)
134 {
135 size_t cchUnquoted = 0;
136 if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */
137 cchUnquoted = 1;
138 else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */
139 {
[3235]140 const char *pszNeedQuoting;
[2812]141 if (isWatcomPassThruOption(pszOrg))
142 {
[3235]143 argv[i] = pszOrgOrg;
144 free(pszNew);
145 continue; /* No quoting needed, skip to the next argument. */
[2812]146 }
[3235]147
148 pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */
149 if ( pszNeedQuoting == NULL
150 || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes))
151 pszNeedQuoting = pszProblem ? pszProblem : pszQuotes;
152 else
153 pszNeedQuoting++;
154 cchUnquoted = pszNeedQuoting - pszOrg;
[2747]155 }
156 if (cchUnquoted)
157 {
158 memcpy(pszNew, pszOrg, cchUnquoted);
159 pszNew += cchUnquoted;
160 pszOrg += cchUnquoted;
161 cchOrg -= cchUnquoted;
162 }
163 }
164
[2667]165 *pszNew++ = '"';
166 if (fComplicated)
167 {
168 while ((ch = *pszOrg++) != '\0')
169 {
170 if (ch == '"')
171 {
172 *pszNew++ = '\\';
173 *pszNew++ = '"';
174 }
175 else if (ch == '\\')
176 {
177 /* Backslashes are a bit complicated, they depends on
178 whether a quotation mark follows them or not. They
179 only require escaping if one does. */
180 unsigned cSlashes = 1;
181 while ((ch = *pszOrg) == '\\')
182 {
183 pszOrg++;
184 cSlashes++;
185 }
186 if (ch == '"' || ch == '\0') /* We put a " at the EOS. */
187 {
188 while (cSlashes-- > 0)
189 {
190 *pszNew++ = '\\';
191 *pszNew++ = '\\';
192 }
193 }
194 else
195 while (cSlashes-- > 0)
196 *pszNew++ = '\\';
197 }
198 else
199 *pszNew++ = ch;
200 }
201 }
202 else
203 {
204 memcpy(pszNew, pszOrg, cchOrg);
205 pszNew += cchOrg;
206 }
207 *pszNew++ = '"';
208 *pszNew = '\0';
[2812]209
[2838]210 if (fFreeOrLeak)
211 free(pszOrgOrg);
[2812]212 }
[2667]213 }
214
[2728]215 /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/
[2912]216 return 0;
[2667]217}
218
Note: See TracBrowser for help on using the repository browser.