Description:
updated box for windows to prevent error modal dialog
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r131:d5c4e1d8daa2 - - 1 file changed: 3 inserted, 0 deleted

@@ -1,450 +1,453
1 1 /*
2 2 This sandbox module is from [Fossil
3 3 grader](http://code.google.com/p/fossil-grader/).
4 4
5 5 This library is a modification from a program called trun, taken
6 6 from an unknown source. (FIX THIS)
7 7
8 8 When compiling with Mingw, add "-lpsapi" to link Windows'memory stat
9 9 library.
10 10 */
11 11 #include <windows.h>
12 12 #include <psapi.h>
13 13 #include <tlhelp32.h>
14 14 #include <stdio.h>
15 15 #include "execute.h"
16 16
17 17 #define INITIAL_WAIT_FOR_MEM_CHECK 100
18 18
19 19 /*
20 20 ==How execute works==
21 21
22 22 ===Start up===
23 23 Set up basic configurations: input file, output file
24 24 into STARTUPINFO struct to be passed to CreateProcess.
25 25
26 26 Create a child process with CreateProcess.
27 27
28 28 ===Wait===
29 29 Use WaitForSingleObject to wait.
30 30
31 31 ===Killing chile process===
32 32 This process is really involved, because (1) programs in
33 33 DOS mode actually runs inside NTVDM so killing them
34 34 requires to kill NTVDM, (2) something a program crashes
35 35 NTVDM and a dialog box pops up, and we need to close
36 36 that dialog box MANUALLY, and (3) for Win32 apps that crash,
37 37 some reporting service in Windows opens a dialog box,
38 38 and it has to be killed.
39 39
40 40 Those extra steps are what's exactly done here:
41 41 1. Kill the process if there's any
42 42 2. In case that there's no real process, find NTVDM
43 43 and kill it (repeatedly until it's gone)
44 44 3. Check if NTVDM crashed and some warning dialog opens,
45 45 if there's any, signal the user and wait.
46 46 4. For real Win32 apps, find process "dwwin.exe" which
47 47 represents an agent for reporting service and also
48 48 opens a dialog. If finds it, kill it (repeatedly)
49 49 until it's gone.
50 50
51 51 Step 4. might be problematic --- dwwin.exe might not
52 52 be a universal process for error reporting services???
53 53 */
54 54
55 55
56 56
57 57 /*
58 58 These are routines that check NTVDM crash dialog.
59 59 It works by enumerating all window titles, and
60 60 checks for "16 bit" or something with ".exe" somewhere
61 61 and starts with "cmd.exe".
62 62 */
63 63 bool NTVDMcrashed_found;
64 64
65 65 /* this is a callback for window title enumeration */
66 66 BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
67 67 {
68 68 char buffer[256];
69 69 GetWindowText(hWnd, buffer, 256);
70 70
71 71 if(strlen(buffer)!=0) {
72 72 if(strstr(buffer,"16 bit")!=0) {
73 73 NTVDMcrashed_found = true;
74 74 }
75 75 if((strstr(buffer,".exe")!=0) &&
76 76 (strstr(buffer,"cmd.exe")==buffer)) {
77 77 NTVDMcrashed_found = true;
78 78 printf("Title: %s\n",buffer);
79 79 }
80 80 }
81 81 return TRUE;
82 82 }
83 83
84 84 bool check_ntvdm_dialog()
85 85 {
86 86 NTVDMcrashed_found = false;
87 87
88 88 FARPROC EnumProcInstance = MakeProcInstance((FARPROC)EnumWindowsProc,
89 89 AfxGetInstanceHandle());
90 90 EnumWindows((WNDENUMPROC)EnumProcInstance, (LPARAM)0);
91 91 FreeProcInstance(EnumProcInstance);
92 92
93 93 return NTVDMcrashed_found;
94 94 }
95 95
96 96 DWORD get_process_id(char *pname)
97 97 {
98 98 HANDLE hProcessSnap;
99 99 HANDLE hProcess;
100 100 PROCESSENTRY32 pe32;
101 101 DWORD dwPriorityClass;
102 102 DWORD pid=0;
103 103
104 104 hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
105 105 if( hProcessSnap == INVALID_HANDLE_VALUE ) {
106 106 return 0;
107 107 }
108 108
109 109 pe32.dwSize = sizeof( PROCESSENTRY32 );
110 110 if( !Process32First( hProcessSnap, &pe32 ) ) {
111 111 CloseHandle( hProcessSnap );
112 112 return 0;
113 113 }
114 114
115 115 do {
116 116 if(strcasecmp(pe32.szExeFile ,pname)==0)
117 117 pid = pe32.th32ProcessID;
118 118 } while( Process32Next( hProcessSnap, &pe32 ) );
119 119
120 120 CloseHandle( hProcessSnap );
121 121 return pid;
122 122 }
123 123
124 124 DWORD get_ntvdm_pid()
125 125 {
126 126 return get_process_id("ntvdm.exe");
127 127 }
128 128
129 129 void kill_error_report()
130 130 {
131 131 DWORD pid;
132 132 do {
133 133 if((pid = get_process_id("dwwin.exe"))!=0) {
134 134 fprintf(stderr," -- with error report (pid: %ld)\n",pid);
135 135 HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid);
136 136 if(hProcess!=NULL) {
137 137 TerminateProcess(hProcess, 0);
138 138 Sleep(500);
139 139 while(get_process_id("dwwin.exe")==pid) {
140 140 fprintf(stderr,"wait for dwwin.exe to die...\n");
141 141 Sleep(500);
142 142 }
143 143 } else
144 144 fprintf(stderr,"do not have permission (%d)\n",
145 145 GetLastError());
146 146 }
147 147 } while(get_process_id("dwwin.exe")!=0);
148 148 }
149 149
150 150 void wait_dialog()
151 151 {
152 152 kill_error_report();
153 153 if(check_ntvdm_dialog()) {
154 154 fprintf(stderr,"Some dialog opens; please MANUALLY kill it.");
155 155 fflush(stderr);
156 156 do {
157 157 Sleep(1000);
158 158 } while(check_ntvdm_dialog());
159 159 fprintf(stderr,"... done\n");
160 160 }
161 161 }
162 162
163 163 void setstartupinfo(STARTUPINFO *si, char *inname, char *outname)
164 164 {
165 165 SECURITY_ATTRIBUTES sa;
166 166
167 167 ZeroMemory(&sa, sizeof(sa));
168 168 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
169 169 sa.lpSecurityDescriptor = NULL;
170 170 sa.bInheritHandle = TRUE;
171 171
172 172 si->dwFlags = STARTF_USESTDHANDLES;
173 173 if((inname!=0) && (strcmp(inname,"-")!=0)) {
174 174 si->hStdInput = CreateFile(inname,
175 175 FILE_READ_DATA,
176 176 FILE_SHARE_READ,
177 177 &sa,
178 178 OPEN_EXISTING,
179 179 FILE_ATTRIBUTE_NORMAL,
180 180 NULL);
181 181 } else
182 182 si->hStdInput = NULL;
183 183
184 184 if((outname!=0) && (strcmp(outname,"-")!=0)) {
185 185 si->hStdOutput = CreateFile(outname,
186 186 FILE_WRITE_DATA,
187 187 FILE_SHARE_READ,
188 188 &sa,
189 189 CREATE_ALWAYS,
190 190 FILE_ATTRIBUTE_NORMAL,
191 191 NULL);
192 192 } else
193 193 si->hStdOutput = NULL;
194 194
195 195 si->hStdError = NULL;
196 196 }
197 197
198 198 // taken from http://msdn.microsoft.com/en-us/library/ms682050(VS.85).aspx
199 199 void PrintMemoryInfo(DWORD processID)
200 200 {
201 201 HANDLE hProcess;
202 202 PROCESS_MEMORY_COUNTERS pmc;
203 203
204 204 // Print the process identifier.
205 205
206 206 printf("\nProcess ID: %u\n", processID);
207 207
208 208 // Print information about the memory usage of the process.
209 209
210 210 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
211 211 PROCESS_VM_READ,
212 212 FALSE,processID);
213 213 if(hProcess == NULL)
214 214 return;
215 215
216 216 if(GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
217 217 printf("\tPageFaultCount: %d\n",pmc.PageFaultCount);
218 218 printf("\tPeakWorkingSetSize: %d\n",
219 219 pmc.PeakWorkingSetSize);
220 220 printf("\tWorkingSetSize: %d\n",pmc.WorkingSetSize);
221 221 printf("\tQuotaPeakPagedPoolUsage: %d\n",
222 222 pmc.QuotaPeakPagedPoolUsage);
223 223 printf("\tQuotaPagedPoolUsage: %d\n",
224 224 pmc.QuotaPagedPoolUsage);
225 225 printf("\tQuotaPeakNonPagedPoolUsage: %d\n",
226 226 pmc.QuotaPeakNonPagedPoolUsage);
227 227 printf("\tQuotaNonPagedPoolUsage: %d\n",
228 228 pmc.QuotaNonPagedPoolUsage);
229 229 printf("\tPagefileUsage: %d\n",pmc.PagefileUsage);
230 230 printf("\tPeakPagefileUsage: %d\n",
231 231 pmc.PeakPagefileUsage);
232 232 }
233 233 CloseHandle( hProcess );
234 234 }
235 235
236 236 int check_memory_usage(DWORD pid, int max_mem, int *actual_usage) {
237 237 // modified from http://msdn.microsoft.com/en-us/library/ms682050(VS.85).aspx
238 238 //PrintMemoryInfo(pid);
239 239 HANDLE hProcess;
240 240 PROCESS_MEMORY_COUNTERS pmc;
241 241
242 242 if((max_mem==0) || (pid==0))
243 243 return 1;
244 244
245 245 if(pid == get_ntvdm_pid()) {
246 246 fprintf(stderr,"ntvdm: ignored\n");
247 247 return 1;
248 248 }
249 249
250 250 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
251 251 PROCESS_VM_READ,
252 252 FALSE, pid);
253 253 if(hProcess == NULL)
254 254 return 1;
255 255
256 256 int max_mem_usage = 0;
257 257 if(GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
258 258 max_mem_usage = pmc.PeakWorkingSetSize;
259 259 if(pmc.PeakPagefileUsage > max_mem_usage)
260 260 max_mem_usage = pmc.PeakPagefileUsage;
261 261 }
262 262 CloseHandle(hProcess);
263 263 if(actual_usage != NULL)
264 264 (*actual_usage) = max_mem_usage;
265 265 return (max_mem_usage <= max_mem);
266 266 }
267 267
268 268 void report_stat(double time_used, int memory_used)
269 269 {
270 270 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
271 271 time_used,
272 272 time_used, (double)0,
273 273 memory_used);
274 274 }
275 275
276 276 double get_process_time_usage(HANDLE hProcess)
277 277 {
278 278 FILETIME creation_time;
279 279 FILETIME exit_time;
280 280 FILETIME kernel_time;
281 281 FILETIME user_time;
282 282 GetProcessTimes(hProcess,
283 283 &creation_time,
284 284 &exit_time,
285 285 &kernel_time,
286 286 &user_time);
287 287
288 288 SYSTEMTIME sys_kernel_time;
289 289 SYSTEMTIME sys_user_time;
290 290 FileTimeToSystemTime(&kernel_time, &sys_kernel_time);
291 291 FileTimeToSystemTime(&user_time, &sys_user_time);
292 292
293 293 double time_used =
294 294 ((sys_kernel_time.wSecond + sys_kernel_time.wMilliseconds/1000.0) +
295 295 (sys_user_time.wSecond + sys_user_time.wMilliseconds/1000.0));
296 296 return time_used;
297 297 }
298 298
299 299 int execute(char *exname, char *inname, char *outname, double t, int max_mem)
300 300 {
301 301 STARTUPINFO si;
302 302 PROCESS_INFORMATION pi;
303 303 int ifsuccess = EXE_RESULT_OK;
304 +
305 + SetErrorMode(SEM_FAILCRITICALERRORS);
306 + SetErrorMode(SEM_NOGPFAULTERRORBOX);
304 307
305 308 ZeroMemory(&si, sizeof(si));
306 309 si.cb = sizeof(si);
307 310 ZeroMemory(&pi, sizeof(pi));
308 311
309 312 setstartupinfo(&si, inname, outname);
310 313
311 314 if(!CreateProcess( NULL, // No module name (use command line).
312 315 TEXT(exname), // Command line.
313 316 NULL, // Process handle not inheritable.
314 317 NULL, // Thread handle not inheritable.
315 318 TRUE, // Set handle inheritance to FALSE.
316 319 0, // No creation flags.
317 320 NULL, // Use parent's environment block.
318 321 NULL, // Use parent's starting directory.
319 322 &si, // Pointer to STARTUPINFO structure.
320 323 &pi)) // Pointer to PROCESS_INFORMATION structure.
321 324 {
322 325 //printf( "CreateProcess failed (%d).\n", GetLastError() );
323 326 fprintf(stderr, "Process creation error.\n");
324 327 report_stat(0,0);
325 328 return EXE_RESULT_ERROR;
326 329 }
327 330 //fprintf(stderr,"Process ID: %ld\n",pi.dwProcessId);
328 331 //fprintf(stderr,"time limit = %d\n",t);
329 332
330 333 // checking memory usage
331 334 // wait 0.1 sec before checking mem usage
332 335
333 336 SetProcessWorkingSetSize(pi.hProcess,
334 337 1,
335 338 max_mem);
336 339 int actual_memory_usage = 0;
337 340
338 341 Sleep(INITIAL_WAIT_FOR_MEM_CHECK);
339 342 if(!check_memory_usage(pi.dwProcessId,max_mem,&actual_memory_usage)) {
340 343 // using too much memory
341 344 fprintf(stderr,"Memory limit exceeded.\n");
342 345 //PrintMemoryInfo(pi.dwProcessId);
343 346 ifsuccess = EXE_RESULT_MEMORY;
344 347 }
345 348
346 349 //printf("PID: %d\n", pi.dwProcessId);
347 350
348 351 if(ifsuccess != EXE_RESULT_MEMORY) {
349 352 int based_time = (int)(t*1000) + 1 - INITIAL_WAIT_FOR_MEM_CHECK;
350 353 bool major_timed_out = (WaitForSingleObject(pi.hProcess,
351 354 based_time)==WAIT_TIMEOUT);
352 355 if(major_timed_out) {
353 356 // wait some more for user time.
354 357 double time_used = get_process_time_usage(pi.hProcess);
355 358 while(time_used <= t) {
356 359 int iter_time = 100;
357 360 if(t - time_used < 200)
358 361 iter_time = 20;
359 362 bool iter_timed_out = (WaitForSingleObject(pi.hProcess,
360 363 iter_time)==WAIT_TIMEOUT);
361 364 if(!iter_timed_out)
362 365 break;
363 366
364 367 time_used = get_process_time_usage(pi.hProcess);
365 368 //printf("%lf\n",time_used);
366 369 }
367 370 ifsuccess = EXE_RESULT_TIMEOUT;
368 371 }
369 372 }
370 373
371 374 if((ifsuccess == EXE_RESULT_MEMORY) || (ifsuccess == EXE_RESULT_TIMEOUT)) {
372 375 // Kill process, because (1) it used too much memory, or (2) time limit
373 376 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
374 377
375 378 if(ifsuccess != EXE_RESULT_MEMORY)
376 379 fprintf(stderr,"Time limit exceeded.\n");
377 380 if(hProcess != NULL) {
378 381 fprintf(stderr,"killing pid: %ld\n",pi.dwProcessId);
379 382 TerminateProcess(hProcess, 0);
380 383 wait_dialog();
381 384 } else {
382 385 DWORD dwNtvdmId = get_ntvdm_pid();
383 386 fprintf(stderr,"killing (ntvdm) pid: %ld\n",dwNtvdmId);
384 387 if(dwNtvdmId!=0) {
385 388 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwNtvdmId);
386 389 TerminateProcess(hProcess, 0);
387 390 } else {
388 391 fprintf(stderr,"killing process error\n");
389 392 }
390 393
391 394 if(get_ntvdm_pid()!=0) {
392 395 fprintf(stderr,"killing error, ntvdm.exe still remains;");
393 396 fprintf(stderr,"please MANUALLY kill it.");
394 397 fflush(stderr);
395 398 do {
396 399 Sleep(1000);
397 400 } while(get_ntvdm_pid()!=0);
398 401 fprintf(stderr,"... done\n");
399 402 wait_dialog();
400 403 }
401 404 }
402 405 if(ifsuccess != EXE_RESULT_MEMORY)
403 406 ifsuccess = EXE_RESULT_TIMEOUT;
404 407 }
405 408
406 409 // check memory after terminated
407 410 if((ifsuccess==EXE_RESULT_OK) &&
408 411 (!check_memory_usage(pi.dwProcessId,max_mem, &actual_memory_usage))) {
409 412 // using too much memory
410 413 ifsuccess = EXE_RESULT_MEMORY;
411 414 }
412 415
413 416 // check return code
414 417 if(ifsuccess==EXE_RESULT_OK) {
415 418 DWORD exitcode;
416 419 GetExitCodeProcess(pi.hProcess, &exitcode);
417 420 if(exitcode!=0) {
418 421 fprintf(stderr,"Exit status %d.\n", (int)exitcode);
419 422 ifsuccess = EXE_RESULT_ERROR;
420 423 }
421 424 }
422 425
423 426 wait_dialog();
424 427
425 428 if(si.hStdInput!=NULL)
426 429 CloseHandle(si.hStdInput);
427 430 if(si.hStdOutput!=NULL)
428 431 CloseHandle(si.hStdOutput);
429 432
430 433 if(ifsuccess==EXE_RESULT_OK)
431 434 fprintf(stderr,"OK\n");
432 435 else if(ifsuccess==EXE_RESULT_TIMEOUT)
433 436 fprintf(stderr,"Time limit exceeded.\n");
434 437 else if(ifsuccess==EXE_RESULT_MEMORY)
435 438 fprintf(stderr,"Memory limit exceeded.\n");
436 439
437 440 double actual_time_usage = get_process_time_usage(pi.hProcess);
438 441 /*
439 442 if(ifsuccess==EXE_RESULT_TIMEOUT)
440 443 actual_time_usage = t+1;
441 444 else
442 445 actual_time_usage = t;
443 446 */
444 447
445 448 report_stat(actual_time_usage,
446 449 (actual_memory_usage + 1023)/1024);
447 450
448 451 return ifsuccess;
449 452 }
450 453
You need to be logged in to leave comments. Login now