--- parser3/src/main/pa_exec.C 2015/10/26 01:21:58 1.85 +++ parser3/src/main/pa_exec.C 2023/09/26 20:49:10 1.97 @@ -1,8 +1,8 @@ /** @file Parser: program executing for different OS-es. - Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) - Author: Alexandr Petrosian (http://paf.design.ru) + Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) + Authors: Konstantin Morshnev , Alexandr Petrosian @todo setrlimit */ @@ -13,7 +13,7 @@ #include "pa_exception.h" #include "pa_common.h" -volatile const char * IDENT_PA_EXEC_C="$Id: pa_exec.C,v 1.85 2015/10/26 01:21:58 moko Exp $" IDENT_PA_EXEC_H; +volatile const char * IDENT_PA_EXEC_C="$Id: pa_exec.C,v 1.97 2023/09/26 20:49:10 moko Exp $" IDENT_PA_EXEC_H; #ifdef _MSC_VER @@ -21,12 +21,12 @@ volatile const char * IDENT_PA_EXEC_C="$ /// this func from http://www.ccas.ru/~posp/popov/spawn.htm static DWORD CreateHiddenConsoleProcess(LPCTSTR szCmdLine, - LPCTSTR szScriptFileSpec, - char *szEnv, - PROCESS_INFORMATION* ppi, - LPHANDLE phInWrite, - LPHANDLE phOutRead, - LPHANDLE phErrRead) + LPCTSTR szScriptFileSpec, + char *szEnv, + PROCESS_INFORMATION* ppi, + LPHANDLE phInWrite, + LPHANDLE phOutRead, + LPHANDLE phErrRead) { DWORD result=0; BOOL fCreated; @@ -45,15 +45,27 @@ static DWORD CreateHiddenConsoleProcess( // create STDIN pipe if(!CreatePipe(&hInRead, phInWrite, &sa, 0)) goto error; - + + // Ensure the write handle to the pipe for STDIN is not inherited. + if (!SetHandleInformation(*phInWrite, HANDLE_FLAG_INHERIT, 0)) + goto error; + // create STDOUT pipe if(!CreatePipe(phOutRead, &hOutWrite, &sa, 0)) goto error; + // Ensure the read handle to the pipe for STDOUT is not inherited. + if (!SetHandleInformation(*phOutRead, HANDLE_FLAG_INHERIT, 0)) + goto error; + // create STDERR pipe if(!CreatePipe(phErrRead, &hErrWrite, &sa, 0)) goto error; + // Ensure the read handle to the pipe for STDERR is not inherited. + if (!SetHandleInformation(*phErrRead, HANDLE_FLAG_INHERIT, 0)) + goto error; + // process startup information memset(&si, 0, sizeof(si)); si.cb=sizeof(si); @@ -67,7 +79,7 @@ static DWORD CreateHiddenConsoleProcess( // calculating script's directory char dir[MAX_STRING]; - strncpy(dir, szScriptFileSpec, MAX_STRING-1); dir[MAX_STRING-1]=0; + pa_strncpy(dir, szScriptFileSpec, MAX_STRING); lsplit(dir,' '); // trim arguments rsplit(dir,'/'); rsplit(dir,'\\'); // trim filename @@ -105,6 +117,20 @@ error: return result; } +static int get_exit_status(HANDLE hProcess) { + DWORD dwExitCode = 0; + if(!GetExitCodeProcess(hProcess, &dwExitCode)) + return -1; + if(dwExitCode != STILL_ACTIVE) + return dwExitCode; + // wait for 1 second for process to exit + if(WaitForSingleObject(hProcess, 1000) != WAIT_OBJECT_0) + return -2; + if(!GetExitCodeProcess(hProcess, &dwExitCode)) + return -1; + return dwExitCode; +} + static void read_pipe(String& result, HANDLE hOutRead, String::Language lang){ while(true) { char *buf=new(PointerFreeGC) char[MAX_STRING+1]; @@ -141,7 +167,7 @@ static void read_pipe(File_read_result& static const char* buildCommand(const char* file_spec_cstr, const ArrayString& argv) { const char* result=file_spec_cstr; - if(FILE *f=fopen(file_spec_cstr, "r")) { + if(FILE *f=pa_fopen(file_spec_cstr, "r")) { try { char buf[MAX_STRING]; size_t size=fread(buf, 1, MAX_STRING-1, f); @@ -257,7 +283,7 @@ static pid_t execve_piped(const char* fi // chdir to script's directory char dir[MAX_STRING]; - strncpy(dir, file_spec_cstr, MAX_STRING-1); dir[MAX_STRING-1]=0; + pa_strncpy(dir, file_spec_cstr, MAX_STRING); rsplit(dir,'/'); // trim filename chdir(dir); @@ -287,7 +313,7 @@ static pid_t execve_piped(const char* fi } static int get_exit_status(int pid) { - int status; + int status=0; pid_t cid; while ((cid=waitpid(pid, &status, WUNTRACED)) == -1 && errno == EINTR); if(!cid) @@ -309,7 +335,7 @@ static void read_pipe(String& result, in static void read_pipe(File_read_result& result, int file){ char *buf=(char*)pa_malloc(MAX_STRING+1); - ssize_t bufsize = MAX_STRING; + size_t bufsize = MAX_STRING; result.headers = 0; result.length = 0; @@ -356,19 +382,12 @@ static void append_env_pair(HashStringSt #endif } -PA_exec_result pa_exec( - bool forced_allow, - const String& file_spec, - const HashStringString* env, - const ArrayString& argv, - String& in) { +PA_exec_result pa_exec(bool forced_allow, const String& file_spec, const HashStringString* env, const ArrayString& argv, String::C in) { PA_exec_result result; #ifdef NO_PA_EXECS if(!forced_allow) - throw Exception(PARSER_RUNTIME, - &file_spec, - "parser execs are disabled [recompile parser without --disable-execs configure option]"); + throw Exception(PARSER_RUNTIME, &file_spec, "parser execs are disabled [recompile parser without --disable-execs configure option]"); #endif #ifdef _MSC_VER @@ -397,23 +416,17 @@ PA_exec_result pa_exec( if(error_size>3) // ".\r\n" szErrorDesc[error_size-3]=0; - throw Exception("file.execute", - &file_spec, - "exec failed - %s (%u). Consider adding shbang line (#!x:\\interpreter\\command line)", - error_size?szErrorDesc:"", error); + throw Exception("file.execute", &file_spec, "exec failed - %s (%u). Consider adding shbang line (#!x:\\interpreter\\command line)", error_size ? szErrorDesc : "", error); } else { - const char* in_cstr=in.cstr(); DWORD written_size; - WriteFile(hInWrite, in_cstr, in.length(), &written_size, NULL); - // EOF for stupid text reads - // normally they should read CONTENT_LENGTH bytes, - // without this char - WriteFile(hInWrite, "\x1A", 1, &written_size, NULL); + if(in.length>0) + WriteFile(hInWrite, in.str, in.length, &written_size, NULL); CloseHandle(hInWrite); read_pipe(result.out, hOutRead); CloseHandle(hOutRead); read_pipe(result.err, hErrRead, String::L_TAINTED); CloseHandle(hErrRead); + result.status=get_exit_status(pi.hProcess); // We must close the handles to the new process and its main thread // to prevent handle and memory leaks. CloseHandle(pi.hProcess); @@ -429,11 +442,8 @@ PA_exec_result pa_exec( if(!forced_allow) { struct stat finfo; - if(stat(file_spec_cstr, &finfo)!=0) - throw Exception("file.missing", - &file_spec, - "stat failed: %s (%d), actual filename '%s'", - strerror(errno), errno, file_spec_cstr); + if(pa_stat(file_spec_cstr, &finfo)!=0) + throw Exception("file.missing", &file_spec, "stat failed: %s (%d), actual filename '%s'", strerror(errno), errno, file_spec_cstr); check_safe_mode(finfo, file_spec, file_spec_cstr); } @@ -442,9 +452,7 @@ PA_exec_result pa_exec( const int argv_size=argv.count(); const int argv_max=sizeof(argv_cstrs)/sizeof(argv_cstrs[0])-1-1; if(argv_size>argv_max) - throw Exception(PARSER_RUNTIME, - &file_spec, - "too many arguments (%d > max %d)", argv_size, argv_max); + throw Exception(PARSER_RUNTIME, &file_spec, "too many arguments (%d > max %d)", argv_size, argv_max); for(int i=0; icstrm(); argv_cstrs[1+argv_size]=0; @@ -464,10 +472,8 @@ PA_exec_result pa_exec( &pipe_write, &pipe_read, &pipe_err); if(pid>0) { // in child - if(!in.is_empty()) {// there is some in data - const char* in_cstr=in.cstr(); - write(pipe_write, in_cstr, in.length()); - } + if(in.length>0) // there is some in data + write(pipe_write, in.str, in.length); close(pipe_write); read_pipe(result.out, pipe_read); close(pipe_read); @@ -477,9 +483,7 @@ PA_exec_result pa_exec( result.status=get_exit_status(pid); // negative may mean "-errno[execl()]" } else { const char* str=strerror(errno); - throw Exception("file.execute", - &file_spec, - "%s error: %s (%d)", pid<0?"fork":"pipe", str?str:"", errno); + throw Exception("file.execute", &file_spec, "%s error: %s (%d)", pid<0?"fork":"pipe", str?str:"", errno); } #endif