Description:
reports running time, checks exit status; modified running time test case, memory test case.
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r114:e28e189186ff - - 4 files changed: 86 inserted, 17 deleted

@@ -1,377 +1,428
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 + void report_stat(double time_used, int memory_used)
269 + {
270 + fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
271 + time_used,
272 + time_used, (double)0,
273 + memory_used);
274 + }
275 +
276 + double get_process_time_usage(HANDLE hProcess)
277 + {
278 + FILETIME creation_time;
279 + FILETIME exit_time;
280 + FILETIME kernel_time;
281 + FILETIME user_time;
282 + GetProcessTimes(hProcess,
283 + &creation_time,
284 + &exit_time,
285 + &kernel_time,
286 + &user_time);
287 +
288 + SYSTEMTIME sys_kernel_time;
289 + SYSTEMTIME sys_user_time;
290 + FileTimeToSystemTime(&kernel_time, &sys_kernel_time);
291 + FileTimeToSystemTime(&user_time, &sys_user_time);
292 +
293 + double time_used =
294 + ((sys_kernel_time.wSecond + sys_kernel_time.wMilliseconds/1000.0) +
295 + (sys_user_time.wSecond + sys_user_time.wMilliseconds/1000.0));
296 + return time_used;
297 + }
298 +
268 299 int execute(char *exname, char *inname, char *outname, double t, int max_mem)
269 300 {
270 301 STARTUPINFO si;
271 302 PROCESS_INFORMATION pi;
272 303 int ifsuccess = EXE_RESULT_OK;
273 304
274 305 ZeroMemory(&si, sizeof(si));
275 306 si.cb = sizeof(si);
276 307 ZeroMemory(&pi, sizeof(pi));
277 308
278 309 setstartupinfo(&si, inname, outname);
279 310
280 311 if(!CreateProcess( NULL, // No module name (use command line).
281 312 TEXT(exname), // Command line.
282 313 NULL, // Process handle not inheritable.
283 314 NULL, // Thread handle not inheritable.
284 315 TRUE, // Set handle inheritance to FALSE.
285 316 0, // No creation flags.
286 317 NULL, // Use parent's environment block.
287 318 NULL, // Use parent's starting directory.
288 319 &si, // Pointer to STARTUPINFO structure.
289 320 &pi)) // Pointer to PROCESS_INFORMATION structure.
290 321 {
291 322 //printf( "CreateProcess failed (%d).\n", GetLastError() );
323 + fprintf(stderr, "Process creation error.\n");
324 + report_stat(0,0);
325 + return EXE_RESULT_ERROR;
292 326 }
293 327 //fprintf(stderr,"Process ID: %ld\n",pi.dwProcessId);
294 328 //fprintf(stderr,"time limit = %d\n",t);
295 329
296 330 // checking memory usage
297 331 // wait 0.1 sec before checking mem usage
298 332
333 + SetProcessWorkingSetSize(pi.hProcess,
334 + 1,
335 + max_mem);
299 336 int actual_memory_usage = 0;
300 337
301 338 Sleep(INITIAL_WAIT_FOR_MEM_CHECK);
302 339 if(!check_memory_usage(pi.dwProcessId,max_mem,&actual_memory_usage)) {
303 340 // using too much memory
304 341 fprintf(stderr,"Memory limit exceeded.\n");
305 342 //PrintMemoryInfo(pi.dwProcessId);
306 343 ifsuccess = EXE_RESULT_MEMORY;
307 344 }
308 345
309 346 if((ifsuccess == EXE_RESULT_MEMORY) ||
310 347 (WaitForSingleObject(pi.hProcess,
311 348 (int)(t*1000) + 1
312 349 - INITIAL_WAIT_FOR_MEM_CHECK)==WAIT_TIMEOUT)) {
313 - // need to kill...
350 + // Kill process, because (1) it used too much memory, or (2) time limit
314 351 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
315 352
316 353 if(ifsuccess != EXE_RESULT_MEMORY)
317 354 fprintf(stderr,"Time limit exceeded.\n");
318 355 if(hProcess != NULL) {
319 356 fprintf(stderr,"killing pid: %ld\n",pi.dwProcessId);
320 357 TerminateProcess(hProcess, 0);
321 358 wait_dialog();
322 359 } else {
323 360 DWORD dwNtvdmId = get_ntvdm_pid();
324 361 fprintf(stderr,"killing (ntvdm) pid: %ld\n",dwNtvdmId);
325 362 if(dwNtvdmId!=0) {
326 363 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwNtvdmId);
327 364 TerminateProcess(hProcess, 0);
328 365 } else {
329 366 fprintf(stderr,"killing process error\n");
330 367 }
331 368
332 369 if(get_ntvdm_pid()!=0) {
333 370 fprintf(stderr,"killing error, ntvdm.exe still remains;");
334 371 fprintf(stderr,"please MANUALLY kill it.");
335 372 fflush(stderr);
336 373 do {
337 374 Sleep(1000);
338 375 } while(get_ntvdm_pid()!=0);
339 376 fprintf(stderr,"... done\n");
340 377 wait_dialog();
341 378 }
342 379 }
343 380 if(ifsuccess != EXE_RESULT_MEMORY)
344 381 ifsuccess = EXE_RESULT_TIMEOUT;
345 382 }
383 +
384 + // check memory after terminated
346 385 if((ifsuccess==EXE_RESULT_OK) &&
347 386 (!check_memory_usage(pi.dwProcessId,max_mem, &actual_memory_usage))) {
348 387 // using too much memory
349 388 ifsuccess = EXE_RESULT_MEMORY;
350 389 }
390 +
391 + // check return code
392 + if(ifsuccess==EXE_RESULT_OK) {
393 + DWORD exitcode;
394 + GetExitCodeProcess(pi.hProcess, &exitcode);
395 + if(exitcode!=0) {
396 + fprintf(stderr,"Exit status %d.\n", (int)exitcode);
397 + ifsuccess = EXE_RESULT_ERROR;
398 + }
399 + }
400 +
351 401 wait_dialog();
402 +
352 403 if(si.hStdInput!=NULL)
353 404 CloseHandle(si.hStdInput);
354 405 if(si.hStdOutput!=NULL)
355 406 CloseHandle(si.hStdOutput);
356 407
357 408 if(ifsuccess==EXE_RESULT_OK)
358 409 fprintf(stderr,"OK\n");
359 410 else if(ifsuccess==EXE_RESULT_TIMEOUT)
360 411 fprintf(stderr,"Time limit exceeded.\n");
361 - else
412 + else if(ifsuccess==EXE_RESULT_MEMORY)
362 413 fprintf(stderr,"Memory limit exceeded.\n");
363 414
364 - double actual_time_usage;
415 + double actual_time_usage = get_process_time_usage(pi.hProcess);
416 + /*
365 417 if(ifsuccess==EXE_RESULT_TIMEOUT)
366 418 actual_time_usage = t+1;
367 419 else
368 420 actual_time_usage = t;
421 + */
369 422
370 - fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
371 - actual_time_usage,
372 - actual_time_usage, (double)0,
423 + report_stat(actual_time_usage,
373 424 (actual_memory_usage + 1023)/1024);
374 425
375 426 return ifsuccess;
376 427 }
377 428
@@ -1,25 +1,26
1 1 /*
2 2 This sandbox module is from [Fossil
3 3 grader](http://code.google.com/p/fossil-grader/).
4 4
5 5 The code is a modification from an unknown source on the internet.
6 6
7 7 */
8 8 #ifndef EXECUTE_H_INCLUDED
9 9 #define EXECUTE_H_INCLUDED
10 10
11 11 #define EXE_RESULT_OK 0
12 12 #define EXE_RESULT_TIMEOUT 1
13 13 #define EXE_RESULT_MEMORY 2
14 + #define EXE_RESULT_ERROR 3
14 15
15 16 #ifdef __cplusplus
16 17 extern "C" {
17 18 #endif
18 19
19 20 int execute(char *exname, char *inname, char *outname, double t, int max_mem=0);
20 21
21 22 #ifdef __cplusplus
22 23 }
23 24 #endif
24 25
25 26 #endif
@@ -1,20 +1,20
1 1 #include <stdio.h>
2 2 #include <stdlib.h>
3 3
4 4 int main()
5 5 {
6 6 int a,b;
7 7 int r;
8 8 char *huge_array;
9 9
10 10 r = scanf("%d %d",&a,&b);
11 11
12 - huge_array = (char *)malloc(5000000);
12 + huge_array = (char *)malloc(5*1024*1024);
13 13 if(huge_array==NULL)
14 14 printf("NO!");
15 15 else
16 16 printf("%d\n",a+b);
17 17
18 18 return 0;
19 19 }
20 20
@@ -1,39 +1,56
1 1 #include <stdio.h>
2 2 #include <stdlib.h>
3 3 #include <unistd.h>
4 - #include <sys/time.h>
5 4 #include <time.h>
6 - #include <sys/resource.h>
5 + #include <windows.h>
6 +
7 + // run it for 0.5 s
7 8
8 - // run it for 1.5 s
9 + double get_running_time()
10 + {
11 + FILETIME creation_time;
12 + FILETIME exit_time;
13 + FILETIME kernel_time;
14 + FILETIME user_time;
15 + GetProcessTimes(GetCurrentProcess(),
16 + &creation_time,
17 + &exit_time,
18 + &kernel_time,
19 + &user_time);
20 +
21 + SYSTEMTIME sys_kernel_time;
22 + SYSTEMTIME sys_user_time;
23 +
24 + FileTimeToSystemTime(&kernel_time, &sys_kernel_time);
25 + FileTimeToSystemTime(&user_time, &sys_user_time);
26 +
27 + double time_used =
28 + ((sys_kernel_time.wSecond + sys_kernel_time.wMilliseconds/1000.0) +
29 + (sys_user_time.wSecond + sys_user_time.wMilliseconds/1000.0));
30 + return time_used;
31 + }
9 32
10 33 int main()
11 34 {
12 35 int a,b;
13 36
14 37 int c=0;
15 38 int r;
16 39
17 40 r = scanf("%d %d",&a,&b);
18 41 printf("%d\n",a+b);
19 42
20 - struct rusage ru;
21 -
22 43 while(1) {
23 44 c++;
24 45 b+=c;
25 46 while(c<100000) {
26 47 c++;
27 48 b+=c;
28 49 }
29 - getrusage(RUSAGE_SELF,&ru);
30 - double rtime = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
31 - rtime += (double)ru.ru_utime.tv_usec / 1000000.0;
32 - rtime += (double)ru.ru_stime.tv_usec / 1000000.0;
33 - if(rtime > 0.5)
50 + if(get_running_time() > 0.5)
34 51 break;
35 52 }
36 53 printf("%d\n",b);
37 54 exit(0);
38 55 }
39 56
You need to be logged in to leave comments. Login now