judge_result testcase_impl::run(env &env, compiler::result &cr) { judge_result result = {0}; shared_ptr<temp_dir> dir = _prepare_dir(env.pool(), cr); env.grant_access(dir->path()); path_a executable_path; if (cr.compiler->target_executable_path().empty()) { executable_path = dir->path(); executable_path.push(cr.compiler->target_filename().c_str()); } else { executable_path = cr.compiler->target_executable_path(); } shared_ptr<testcase_impl::context> context(new testcase_impl::context(*this)); judge::bunny bunny(env, false, executable_path.c_str(), cr.compiler->target_command_line(), dir->path(), context->stdin_pipe.read_handle(), context->stdout_pipe.write_handle(), context->stderr_pipe.write_handle(), limit_); context->stdin_pipe.close_read(); context->stdout_pipe.close_write(); context->stderr_pipe.close_write(); // stdin thread env.pool().thread_pool().queue([context]()->void { try { istream in(&context->stdin_buf); os_filebuf out_buf(context->stdin_pipe.write_handle(), false); ostream out(&out_buf); const size_t buffer_size = 4096; util::stream_copy<buffer_size>(in, out); } catch (...) { } context->stdin_pipe.close_write(); context->stdin_event.set(); }); // stderr thread env.pool().thread_pool().queue([context]()->void { try { os_filebuf in_buf(context->stderr_pipe.read_handle(), false); istream in(&in_buf); const size_t buffer_size = 4096; util::stream_copy_n<buffer_size>(in, context->stderr_stream, context->stderr_output_limit); } catch (...) { } context->stderr_pipe.close_read(); context->stderr_event.set(); }); bunny.start(); // judge { istream model_in(&context->stdout_buf); os_filebuf user_buf(context->stdout_pipe.read_handle(), false); istream user_in(&user_buf); pair<bool, string> compare_result = compare_stream(model_in, user_in); if (compare_result.first) { result.flag = max(result.flag, JUDGE_ACCEPTED); } else { result.flag = max(result.flag, JUDGE_WRONG_ANSWER); } judge_output_ = move(compare_result.second); // read all user output const size_t buffer_size = 4096; util::stream_copy<buffer_size>(user_in, onullstream()); } bunny::result bunny_result = bunny.wait(); DWORD wait_result = winstl::wait_for_multiple_objects(context->stdin_event, context->stderr_event, true, INFINITE); if (wait_result == WAIT_FAILED) { throw win32_exception(::GetLastError()); } result.flag = max(result.flag, bunny_result.flag); result.time_usage_ms = bunny_result.time_usage_ms; result.memory_usage_kb = bunny_result.memory_usage_kb; result.runtime_error = bunny_result.runtime_error; result.judge_output = judge_output_.c_str(); user_output_ = context->stderr_stream.str(); result.user_output = user_output_.c_str(); return result; }
void restricted_env::grant_access(const winstl::path_a &path) { LPSTR username = const_cast<LPSTR>(username_.c_str()); DWORD result; HANDLE file = ::CreateFileA(path.c_str(), READ_CONTROL | WRITE_DAC, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (file == INVALID_HANDLE_VALUE) { throw win32_exception(::GetLastError()); } PACL old_dacl, new_dacl; PSECURITY_DESCRIPTOR sd; EXPLICIT_ACCESSA ea = {0}; result = ::GetSecurityInfo(file, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl, NULL, &sd); if (result != ERROR_SUCCESS) { ::CloseHandle(file); throw win32_exception(result); } ea.grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE; ea.grfAccessMode = GRANT_ACCESS; ea.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; ea.Trustee.TrusteeType = TRUSTEE_IS_USER; ea.Trustee.ptstrName = username; result = ::SetEntriesInAclA(1, &ea, old_dacl, &new_dacl); if (result != ERROR_SUCCESS) { ::LocalFree(sd); ::CloseHandle(file); throw win32_exception(result); } result = ::SetSecurityInfo(file, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, new_dacl, NULL); if (result != ERROR_SUCCESS) { ::LocalFree(new_dacl); ::LocalFree(sd); ::CloseHandle(file); throw win32_exception(result); } ::LocalFree(new_dacl); ::LocalFree(sd); ::CloseHandle(file); }
void job_object::terminate(int32_t exit_code) { BOOL result = ::TerminateJobObject(handle(), static_cast<UINT>(exit_code)); if (!result) { throw win32_exception(::GetLastError()); } }
void job_object::assign(HANDLE process_handle) { BOOL result = ::AssignProcessToJobObject(handle(), process_handle); if (!result) { throw win32_exception(::GetLastError()); } }
HANDLE job_object::_create() { HANDLE result = ::CreateJobObject(NULL, NULL); if (!result) { throw win32_exception(::GetLastError()); } return result; }
HANDLE window_station::_process_window_station() { HANDLE result = ::GetProcessWindowStation(); if (!result) { throw win32_exception(::GetLastError()); } return result; }
void RegValue::CheckError(LPCSTR szMessage) { if (m_stResult != ERROR_SUCCESS) { LPCSTR szMessageTmp = szMessage != NULL? szMessage: "Error while operating with register"; throw win32_exception(szMessageTmp, m_stResult); } }
HANDLE desktop::_create_desktop(const std::string &name) { HANDLE result = ::CreateDesktopA(name.c_str(), NULL, NULL, 0, DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_WRITEOBJECTS | READ_CONTROL | WRITE_DAC | DESKTOP_SWITCHDESKTOP, 0); if (!result) { throw win32_exception(::GetLastError()); } return result; }
void job_object::limits_info::commit() { BOOL result = ::SetInformationJobObject( job_.handle(), ::JobObjectExtendedLimitInformation, static_cast<::JOBOBJECT_EXTENDED_LIMIT_INFORMATION *>(this), sizeof(::JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); if (!result) { throw win32_exception(::GetLastError()); } }
void job_object::ui_restrictions_info::commit() { BOOL result = ::SetInformationJobObject( job_.handle(), ::JobObjectBasicUIRestrictions, static_cast<::JOBOBJECT_BASIC_UI_RESTRICTIONS *>(this), sizeof(::JOBOBJECT_BASIC_UI_RESTRICTIONS)); if (!result) { throw win32_exception(::GetLastError()); } }
void win32_exception::translate(unsigned code, EXCEPTION_POINTERS* info) { switch (code) { case EXCEPTION_ACCESS_VIOLATION: throw access_violation(info); break; default: throw win32_exception(info); } }
void __cdecl win32_exception::translate(unsigned code, EXCEPTION_POINTERS* info) { // Windows guarantees that *(info->ExceptionRecord) is valid switch (code) { case EXCEPTION_ACCESS_VIOLATION: throw access_violation(*(info->ExceptionRecord)); break; default: throw win32_exception(*(info->ExceptionRecord)); } }
void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo) { switch(errorCode) { case EXCEPTION_ACCESS_VIOLATION: throw win32_access_violation(*(pInfo->ExceptionRecord)); break; default: throw win32_exception(*(pInfo->ExceptionRecord)); } }
pair<shared_ptr<process>, shared_ptr<thread_suspension> > restricted_env::create_process( const string &executable_path, const string &command_line, const path_a ¤t_dir, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle) { string desktop_name = window_station_.name() + "\\" + desktop_.name(); PROCESS_INFORMATION process_info; BOOL result; if (!proc_thread_attribute_list::is_supported()) { STARTUPINFOA startup_info = {0}; startup_info.cb = sizeof(startup_info); startup_info.lpDesktop = const_cast<LPSTR>(desktop_name.c_str()); startup_info.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES; uintptr_t handle_value = 0; duplicate_handle stdin_h(stdin_handle, handle_value); duplicate_handle stdout_h(stdout_handle, handle_value); duplicate_handle stderr_h(stderr_handle, handle_value); startup_info.hStdInput = stdin_h.target(); startup_info.hStdOutput = stdout_h.target(); startup_info.hStdError = stderr_h.target(); result = ::CreateProcessAsUserA(session_.handle(), executable_path.empty() ? NULL : executable_path.c_str(), const_cast<LPSTR>(command_line.c_str()), NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB | CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW | CREATE_SUSPENDED, NULL, current_dir.c_str(), &startup_info, &process_info); if (result) { try { stdin_h(process_info.hProcess); stdout_h(process_info.hProcess); stderr_h(process_info.hProcess); } catch (...) { ::TerminateProcess(process_info.hProcess, 1); ::CloseHandle(process_info.hProcess); ::CloseHandle(process_info.hThread); throw; } } } else { inherit_handle stdin_h(stdin_handle); inherit_handle stdout_h(stdout_handle); inherit_handle stderr_h(stderr_handle); proc_thread_attribute_list attr_list(1); vector<HANDLE> handle_list; if (stdin_handle) handle_list.push_back(stdin_handle); if (stdout_handle) handle_list.push_back(stdout_handle); if (stderr_handle) handle_list.push_back(stderr_handle); sort(handle_list.begin(), handle_list.end()); handle_list.erase(unique(handle_list.begin(), handle_list.end()), handle_list.end()); attr_list.update(PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handle_list.data(), handle_list.size() * sizeof(HANDLE)); STARTUPINFOEXA info = {0}; info.StartupInfo.cb = sizeof(info); info.StartupInfo.lpDesktop = const_cast<LPSTR>(desktop_name.c_str()); info.StartupInfo.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES; info.StartupInfo.hStdInput = stdin_handle; info.StartupInfo.hStdOutput = stdout_handle; info.StartupInfo.hStdError = stderr_handle; info.lpAttributeList = attr_list.pointer(); result = ::CreateProcessAsUserA(session_.handle(), executable_path.empty() ? NULL : executable_path.c_str(), const_cast<LPSTR>(command_line.c_str()), NULL, NULL, TRUE, CREATE_BREAKAWAY_FROM_JOB | CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW | CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT, NULL, current_dir.c_str(), &info.StartupInfo, &process_info); } if (!result) { throw win32_exception(::GetLastError()); } shared_ptr<process> p; try { p.reset(new process(process_info.hProcess)); } catch (...) { ::TerminateProcess(process_info.hProcess, 1); ::CloseHandle(process_info.hProcess); ::CloseHandle(process_info.hThread); throw; } shared_ptr<thread_suspension> t; try { t.reset(new thread_suspension(process_info.hThread)); } catch (...) { ::TerminateProcess(process_info.hProcess, 1); ::CloseHandle(process_info.hThread); throw; } return make_pair(move(p), move(t)); }