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