Avoid potential negative array index access to cached text.
[LibreOffice.git] / solenv / gcc-wrappers / wrapper.cxx
blobc84fd4990b75af024453f4761945435ba3e7d9f7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "wrapper.hxx"
12 #define WIN32_LEAN_AND_MEAN
14 #include <windows.h>
16 #define BUFLEN 2048
18 std::string getexe(std::string exename, bool maybeempty) {
19 char* cmdbuf;
20 size_t cmdlen;
21 _dupenv_s(&cmdbuf,&cmdlen,exename.c_str());
22 if(!cmdbuf) {
23 if (maybeempty) {
24 return std::string();
26 std::cout << "Error " << exename << " not defined. Did you forget to source the environment?" << std::endl;
27 exit(1);
29 std::string command(cmdbuf);
30 free(cmdbuf);
31 return command;
34 void setupccenv() {
35 // Set-up library path
36 std::string libpath="LIB=";
37 char* libbuf;
38 size_t liblen;
39 _dupenv_s(&libbuf,&liblen,"ILIB");
40 if (libbuf == nullptr) {
41 std::cerr << "No environment variable ILIB" << std::endl;
42 std::exit(EXIT_FAILURE);
44 libpath.append(libbuf);
45 free(libbuf);
46 if(_putenv(libpath.c_str())<0) {
47 std::cerr << "Error: could not export LIB" << std::endl;
48 exit(1);
51 // Set-up include path
52 std::string includepath="INCLUDE=.";
53 char* incbuf;
54 size_t inclen;
55 _dupenv_s(&incbuf,&inclen,"SOLARINC");
56 if (incbuf == nullptr) {
57 std::cerr << "No environment variable SOLARINC" << std::endl;
58 std::exit(EXIT_FAILURE);
60 std::string inctmp(incbuf);
61 free(incbuf);
63 // 2 = strlen("-I")
64 for(size_t pos=0,len=0;pos<inctmp.length();) {
65 while (pos != inctmp.length() && inctmp[pos] == ' ') {
66 ++pos;
68 size_t endpos=inctmp.find(" -I",pos+1);
69 if(endpos==std::string::npos)
70 endpos=inctmp.length();
71 len=endpos-pos;
73 while(len>0&&inctmp[pos+len-1]==' ')
74 --len;
76 if(len>2) {
77 includepath.append(";");
78 includepath.append(inctmp,pos+2,len-2);
80 pos=endpos;
82 if(_putenv(includepath.c_str())<0) {
83 std::cerr << "Error: could not export INCLUDE" << std::endl;
84 exit(1);
88 std::string processccargs(const std::vector<std::string>& rawargs, std::string &env_prefix, bool &verbose)
90 // default env var prefix
91 env_prefix = "REAL_";
92 verbose = false;
93 bool env_prefix_next_arg = false;
95 // suppress the msvc banner
96 std::string args=" -nologo";
97 // TODO: should these options be enabled globally?
98 args.append(" -EHsc");
99 const char *const pDebugRuntime(getenv("MSVC_USE_DEBUG_RUNTIME"));
100 if (pDebugRuntime && !strcmp(pDebugRuntime, "TRUE"))
101 args.append(" -MDd");
102 else
103 args.append(" -MD");
104 args.append(" -Gy");
105 args.append(" -Ob1 -Oxs -Oy-");
107 std::string linkargs;
108 bool block_linkargs = false;
110 // Instead of using synced PDB access (-FS), use individual PDB files based on output.
111 // In fact, simply use -Z7, which doesn't use PDB files at all and writes all debug into the .obj file.
112 const char *const pEnvIndividualPDBs(getenv("MSVC_USE_INDIVIDUAL_PDBS"));
113 const bool bIndividualPDBs = (pEnvIndividualPDBs && !strcmp(pEnvIndividualPDBs, "TRUE"));
114 const char *const pEnvEnableZ7Debug(getenv("ENABLE_Z7_DEBUG"));
115 const bool bEnableZ7Debug = (pEnvEnableZ7Debug && !strcmp(pEnvEnableZ7Debug, "TRUE")) || bIndividualPDBs;
117 for(std::vector<std::string>::const_iterator i = rawargs.begin(); i != rawargs.end(); ++i) {
118 if (env_prefix_next_arg)
120 env_prefix = *i;
121 env_prefix_next_arg = false;
122 continue;
125 args.append(" ");
126 if(*i == "-o") {
127 // TODO: handle more than just exe output
128 ++i;
129 size_t dot=(*i).find_last_of(".");
130 if(!(*i).compare(dot+1,3,"obj") || !(*i).compare(dot+1,1,"o"))
132 args.append("-Fo");
133 args.append(*i);
135 else if(!(*i).compare(dot+1,3,"exe"))
137 args.append("-Fe");
138 args.append(*i);
140 else if(!(*i).compare(dot+1,3,"dll"))
141 { // apparently cl.exe has no flag for dll?
142 linkargs.append(" -dll -out:");
143 linkargs.append(*i);
145 else if (dot == std::string::npos)
147 args.append("-Fe");
148 args.append(*i + ".exe");
150 else
152 std::cerr << "unknown -o argument - please adapt gcc-wrapper for \""
153 << (*i) << "\"" << std::endl;
154 exit(1);
157 else if(*i == "-g" || !(*i).compare(0,5,"-ggdb")) {
158 if(!bEnableZ7Debug)
160 args.append("-Zi");
161 args.append(" -FS");
163 else
165 // ccache doesn't work with -Zi, the -link -debug for linking will create a final PDB
166 args.append("-Z7");
169 else if(!(*i).compare(0,2,"-D")) {
170 // need to re-escape strings for preprocessor
171 std::string str = *i;
172 for(size_t pos=str.find("\""); pos!=std::string::npos; pos=str.find("\"",pos)) {
173 str.replace(pos,0,"\\");
174 pos+=2;
176 args.append(str);
178 else if(!(*i).compare(0,2,"-L")) {
179 linkargs.append(" -LIBPATH:"+(*i).substr(2));
181 else if(!(*i).compare(0,2,"-l") && (*i).compare(0,5,"-link")) {
182 linkargs.append(" "+(*i).substr(2)+".lib");
184 else if(!(*i).compare(0,5,"-def:") || !(*i).compare(0,5,"/def:")) {
185 // why are we invoked with /def:? cl.exe should handle plain
186 // "foo.def" by itself
187 linkargs.append(" " + *i);
189 else if(!(*i).compare(0,12,"-fvisibility") || *i == "-fPIC") {
190 //TODO: drop other gcc-specific options
192 else if(!(*i).compare(0,4,"-Wl,")) {
193 //TODO: drop other gcc-specific options
195 else if(*i == "-c") {
196 args.append("-c");
197 // If -c is specified, there will be no linking anyway,
198 // and passing -link with -c stops ccache from caching.
199 block_linkargs = true;
201 else if(*i == "-Werror")
202 args.append("-WX");
203 else if (*i == "--wrapper-print-cmdline")
204 verbose = true;
205 else
207 size_t pos = i->find("=");
208 if (0 == i->compare(0, pos, "--wrapper-env-prefix"))
210 if (pos == std::string::npos)
211 env_prefix_next_arg = true;
212 else if (pos + 1 == i->length())
214 // bailout - missing arg
215 env_prefix_next_arg = true;
216 break;
218 else
219 env_prefix = i->substr(pos + 1);
221 else
222 args.append(*i);
226 if (env_prefix_next_arg)
228 std::cerr << "wrapper-env-prefix needs an argument!" << std::endl;
229 exit(1);
232 if(!block_linkargs) {
233 // apparently these must be at the end
234 // otherwise configure tests may fail
235 // note: always use -debug so a PDB file is created
236 args.append(" -link -debug ");
237 args.append(linkargs);
240 return args;
243 int startprocess(std::string command, std::string args, bool verbose)
245 STARTUPINFO si;
246 PROCESS_INFORMATION pi;
247 SECURITY_ATTRIBUTES sa;
249 HANDLE childout_read;
250 HANDLE childout_write;
252 memset(&sa,0,sizeof(sa));
253 memset(&si,0,sizeof(si));
254 memset(&pi,0,sizeof(pi));
256 sa.nLength=sizeof(sa);
257 sa.bInheritHandle=TRUE;
259 if(!CreatePipe(&childout_read,&childout_write,&sa,0)) {
260 std::cerr << "Error: could not create stdout pipe" << std::endl;
261 exit(1);
264 si.cb=sizeof(si);
265 si.dwFlags |= STARTF_USESTDHANDLES;
266 si.hStdOutput=childout_write;
267 si.hStdError=childout_write;
269 // support ccache
270 size_t pos=command.find("ccache ");
271 size_t len = strlen("ccache ");
272 if(pos == std::string::npos) {
273 pos=command.find("ccache.exe ");
274 len = strlen("ccache.exe ");
276 if(pos != std::string::npos) {
277 args.insert(0,command.substr(pos+len));
278 command=command.substr(0,pos+len-1);
281 auto cmdline = "\"" + command + "\" " + args;
283 if (verbose)
284 std::cerr << "CMD= " << command << " " << args << std::endl;
286 // Commandline may be modified by CreateProcess
287 char* cmdlineBuf=_strdup(cmdline.c_str());
289 if(!CreateProcess(nullptr, // Process Name
290 cmdlineBuf, // Command Line
291 nullptr, // Process Handle not Inheritable
292 nullptr, // Thread Handle not Inheritable
293 TRUE, // Handles are Inherited
294 0, // No creation flags
295 nullptr, // Environment for process
296 nullptr, // Use same starting directory
297 &si, // Startup Info
298 &pi) // Process Information
300 auto const e = GetLastError();
301 std::cerr << "Error: could not create process \"" << cmdlineBuf << "\": " << e << std::endl;
302 exit(1);
305 // if you don't close this the process will hang
306 CloseHandle(childout_write);
308 // Get Process output
309 char buffer[BUFLEN];
310 DWORD readlen, writelen, ret;
311 HANDLE stdout_handle=GetStdHandle(STD_OUTPUT_HANDLE);
312 while(true) {
313 int success=ReadFile(childout_read,buffer,BUFLEN,&readlen,nullptr);
314 // check if the child process has exited
315 if(GetLastError()==ERROR_BROKEN_PIPE)
316 break;
317 if(!success) {
318 std::cerr << "Error: could not read from subprocess stdout" << std::endl;
319 exit(1);
321 if(readlen!=0) {
322 WriteFile(stdout_handle,buffer,readlen,&writelen,nullptr);
325 WaitForSingleObject(pi.hProcess, INFINITE);
326 GetExitCodeProcess(pi.hProcess, &ret);
327 CloseHandle(pi.hThread);
328 CloseHandle(pi.hProcess);
329 return int(ret);
332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */