root/crashRun.c

Revision 1205:37d80331f28f, 8.1 kB (checked in by thomask, 6 years ago)

fixed crashRun.c for C++ compilers

Line 
1 /*
2  * crashRun - execute command with restricted CPU time and memory usage
3  *
4  * Copyright (C)
5  *      2005, 2006 Thomas Kuehne <thomas@kuehne.cn>
6  *      2005 Anders F Björrklund <afb@algonet.se> (BSD)
7  *      2005 Stewart Gordon <smjg_1998@yahoo.com> (Windows)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * $HeadURL$
24  * $Date$
25  * $Author$
26  *
27  */
28
29 #include <errno.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <signal.h>
34
35 #undef WAIT_GUARD
36 #define WAIT_GUARD 3
37
38 /* time-out in seconds
39  * Posix: cpu time(timeOut) and system time(timeOut * WAIT_GUARD)
40  * Windows: system time(timeOut)
41  */
42 long int timeOut;
43
44 /* max memory usage in megabytes (Posix only) */
45 long int memoryLimit;
46
47 /* identify system API */
48 #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
49 #define USE_POSIX 1
50 #endif
51
52 #if defined(__GNU_LIBRARY__) || defined(__GLIBC__)
53 #define USE_POSIX 1
54 #endif
55
56 #if defined(linux) || defined(__FreeBsd__) || defined(__OpenBSD__)
57 #define USE_POSIX 1
58 #endif
59
60 #if defined(__APPLE__) && defined(__MACH__)
61 #define USE_POSIX 1
62 #endif
63
64 #if !defined(USE_POSIX) && \
65     (defined(WINDOWS) || defined(WIN) || defined(WINVER) || defined(WIN32) \
66     || defined(WIN64))
67 #define USE_WINDOWS 1
68 #endif
69
70
71 /* is the environment sane? */
72 #if defined(USE_POSIX) && defined(USE_WINDOWS)
73 #error USE_WINDOWS and USE_POSIX are defined
74 #endif
75
76 #if !defined(USE_POSIX) && !defined(USE_WINDOWS)
77 #error neither USE_POSIX nor USE_WINDOWS are defined
78 #endif
79
80
81 /* API inludes and config */
82 #ifdef USE_POSIX
83 #define USE_POSIX_LIMITS
84 #include <sys/types.h>
85 #include <unistd.h>
86 #include <sys/wait.h>
87 static pid_t pID;
88 #endif
89
90 #ifdef USE_POSIX_LIMITS
91 #ifndef USE_POSIX
92 #error USE_POSIX_LIMITS requires USE_POSIX
93 #endif
94 #include <sys/resource.h>
95 #include <sys/types.h>
96 #endif
97
98 #ifdef USE_WINDOWS
99 #include <windows.h>
100 #define snprintf _snprintf
101 #endif
102
103
104
105 #ifdef USE_POSIX
106
107 void handleSignal(int signalID){
108     if( signalID==SIGALRM
109 #ifdef SIGXCPU
110         || signalID==SIGXCPU
111 #endif
112     )
113         printf("EXIT CODE: signal %d (time-out after CPU/total %li/%li seconds)\n",
114                 signalID, timeOut, timeOut * WAIT_GUARD);
115     else
116         printf("EXIT CODE: signal %d, errno %d\n", signalID, errno);
117
118     fflush(stdout);
119     fflush(stderr);
120
121     kill(-pID, SIGTERM);
122     sleep(1);
123     kill(-pID, SIGKILL);
124
125     exit(EXIT_FAILURE);
126 }
127
128 void setupLimits(){
129     struct rlimit limit;
130
131     limit.rlim_cur = timeOut;
132     limit.rlim_max = timeOut;
133     if(0!=setrlimit(RLIMIT_CPU, &limit)){
134         fprintf(stderr, "failed to set cpu limit [%d]\n", errno);
135         exit(EXIT_FAILURE);
136     }
137
138     limit.rlim_cur = memoryLimit * 1024L * 1024L;
139     limit.rlim_max = memoryLimit * 1024L * 1024L;
140 #ifdef RLIMIT_AS
141     if(0!=setrlimit(RLIMIT_AS, &limit)){
142         fprintf(stderr, "failed to set mem limit (AS) %s [%d]\n", strerror(errno), errno);
143         exit(EXIT_FAILURE);
144     }
145 #endif
146
147     if(0!=setrlimit(RLIMIT_DATA, &limit)){
148         fprintf(stderr, "failed to set mem limit (DATA) %s [%d]\n", strerror(errno), errno);
149         exit(EXIT_FAILURE);
150     }
151
152     if(0!=setrlimit(RLIMIT_RSS, &limit)){
153         fprintf(stderr, "failed to set mem limit (RSS) %s [%d]\n", strerror(errno), errno);
154         exit(EXIT_FAILURE);
155     }
156 #if defined(RLIMIT_MEMLOCK) && !defined(linux)
157     if(0!=setrlimit(RLIMIT_MEMLOCK, &limit)){
158         fprintf(stderr, "failed to set mem limit (MEMLOCK): %s [%d]\n", strerror(errno), errno);
159         exit(EXIT_FAILURE);
160     }
161 #endif
162 }
163
164 void setupHandlers(){
165 #ifdef SIGHUP
166     signal(SIGHUP, &handleSignal);
167 #endif
168     signal(SIGINT, &handleSignal);
169 #ifdef SIGQUIT
170     signal(SIGQUIT, &handleSignal);
171 #endif
172     signal(SIGILL, &handleSignal);
173 #ifdef SIGTRAP
174     signal(SIGTRAP, &handleSignal);
175 #endif
176     signal(SIGABRT, &handleSignal);
177 #ifdef SIGIOT
178     signal(SIGIOT, &handleSignal);
179 #endif
180 #ifdef SIGBUS
181     signal(SIGBUS, &handleSignal);
182 #endif
183     signal(SIGFPE, &handleSignal);
184 #ifdef SIGUSR1
185     signal(SIGUSR1, &handleSignal);
186 #endif
187     signal(SIGSEGV, &handleSignal);
188 #ifdef SIGUSR2
189     signal(SIGUSR2, &handleSignal);
190 #endif
191 #ifdef SIGPIPE
192     signal(SIGPIPE, &handleSignal);
193 #endif
194     signal(SIGALRM, &handleSignal);
195     signal(SIGTERM, &handleSignal);
196 #ifdef SIGSTKFLT
197     signal(SIGSTKFLT, &handleSignal);
198 #endif
199 #ifdef SIGTSTP
200     signal(SIGTSTP, &handleSignal);
201 #endif
202 #ifdef SIGXCPU
203     signal(SIGXCPU, &handleSignal);
204 #endif
205 #ifdef SIGXFSZ
206     signal(SIGXFSZ, &handleSignal);
207 #endif
208 #ifdef SIGVTALRM
209     signal(SIGVTALRM, &handleSignal);
210 #endif
211 #ifdef SIGSYS
212     signal(SIGSYS, &handleSignal);
213 #endif
214 }
215 #endif /* USE_POSIX */
216
217 char* reconstructCmd(int argc, char** argv){
218     size_t cmdLen=1;
219     size_t tmpLen;
220     size_t i;
221     char* tmp;
222     char* cmd;
223
224     for(i=0; i<argc; i++){
225         cmdLen+=strlen(argv[i]);
226         cmdLen+=1;
227     }
228
229     cmd = (char*) malloc(++cmdLen);
230     if(!cmd){
231         fprintf(stderr, "failed to allocate enough memory");
232         exit(EXIT_FAILURE);
233     }
234
235     *cmd = '\x00';
236     tmp = cmd;
237
238     for(i=0; i<argc; i++){
239         tmpLen = snprintf(tmp, cmdLen, "%s ", argv[i]);
240         tmp += tmpLen;
241         cmdLen -= tmpLen;
242     }
243     return cmd;
244 }
245
246 int main(int argc, char** argv){
247     char* cmd;
248     char* end;
249
250     if(argc<4){
251         fprintf(stderr, "crashRun <timeOut (s)> <maxMemory (MB)> <command> [<command arg> ...]\n");
252         return EXIT_FAILURE;
253     }
254     timeOut = strtol(argv[1], &end, 10);
255     if(*end){
256         fprintf(stderr, "the timeOut argument contains the illegal character: %c (0x%X)", *end, *end);
257         return EXIT_FAILURE;
258     }else if(timeOut < 1){
259         fprintf(stderr, "minimum timeOut is 1 second, got %li seconds\n", timeOut);
260         return EXIT_FAILURE;
261     }
262
263     memoryLimit = strtol(argv[2], &end, 10);
264     if(*end){
265         fprintf(stderr, "the maxMemory argument contains the illegal character: %c (0x%X)", *end, *end);
266         return EXIT_FAILURE;
267     }else if(memoryLimit < 1){
268         fprintf(stderr, "minimum memoryLimit is 1MB second, got %li MB\n", memoryLimit);
269         return EXIT_FAILURE;
270     }
271     cmd = reconstructCmd(argc-3, argv+3);
272
273 #ifdef DEBUG
274         printf("cmd[%li sec, %li MB]: %s \n", timeOut, memoryLimit, cmd);
275 #endif
276
277 #ifdef USE_POSIX
278     setupLimits();
279     pID = fork();
280     if(pID == 0){
281         /* child */
282         pID=setsid();
283         printf("EXIT CODE: %d\n", system(cmd));
284     }else if(pID < 0){
285         fprintf(stderr, "failed to fork\n");
286         return EXIT_FAILURE;
287     }else{
288         /* parent */
289         setupHandlers();
290 #if !(defined(USE_POSIX_LIMITS) && defined(SIGXCPU))
291         alarm(timeOut);
292 #else
293         /* safe guard against childs without CPU usage */
294         alarm(timeOut * WAIT_GUARD);
295 #endif
296         wait(NULL);
297     }
298     return EXIT_SUCCESS;
299 #elif USE_WINDOWS
300     /* BUG: maxMemory not implemented */
301
302     PROCESS_INFORMATION processInfo;
303     STARTUPINFO startupInfo;
304     SECURITY_ATTRIBUTES sa = {
305         sizeof(SECURITY_ATTRIBUTES), NULL, TRUE
306     };
307     unsigned long exitCode;
308     long int timeLeft = timeOut;    /* time limit in iterations of WFX loop */
309
310     memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
311     memset(&startupInfo, 0, sizeof(STARTUPINFO));
312     startupInfo.cb = sizeof(STARTUPINFO);
313
314     if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL,
315           &startupInfo, &processInfo)) {
316         void *message;
317
318         FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
319           | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
320            (char*) &message, 0, NULL);
321
322         /* this should never happen */
323         fprintf(stderr, "ERROR running %s:\n", cmd);
324         fprintf(stderr, "%s\n", message);
325         LocalFree((HLOCAL) message);
326         return RAND_MAX;
327     }
328
329     /* wait for exit */
330     while (TRUE) {
331         Sleep(1000);
332         GetExitCodeProcess(processInfo.hProcess, &exitCode);
333         if (exitCode == 0x103) {
334             if (--timeLeft == 0) {
335                 TerminateProcess(processInfo.hProcess, EXIT_FAILURE);
336                 printf("EXIT CODE: timeout after %li seconds\n", timeOut);
337                 Sleep(100);
338                 return EXIT_SUCCESS;
339             }
340         } else {
341             printf("EXIT CODE: %i\n", exitCode);
342             return EXIT_SUCCESS;
343         }
344     }
345
346     fprintf(stderr, "crashRun: BUG\n");
347     return EXIT_FAILURE;
348 #else
349
350 #error no implmentation for your system found (supported: Posix, Windows)
351
352 #endif /* USE_POSIX else */
353 }
Note: See TracBrowser for help on using the browser.