use of cn.edu.zjnu.acm.judge.core.Option in project judge by zjnu-acm.
the class JudgeRunnerImpl method run.
@Override
public RunResult run(RunRecord runRecord, Path workDirectory, JudgeData judgeData, Validator validator, boolean cleanDirectory) {
Objects.requireNonNull(runRecord);
Objects.requireNonNull(workDirectory);
try {
RunResult.Builder builder = RunResult.builder();
String source = runRecord.getSource();
if (!StringUtils.hasLength(source)) {
return builder.type(Status.COMPILATION_ERROR).compileInfo("empty source file").build();
}
final String main = "Main";
Files.createDirectories(workDirectory);
Language language = runRecord.getLanguage();
// 源码码文件
Path sourceFile = workDirectory.resolve(main + "." + language.getSourceExtension());
Files.write(sourceFile, source.getBytes(Platform.getCharset()));
String compileCommand = language.getCompileCommand();
log.debug("Compile Command: {}", compileCommand);
if (StringUtils.hasText(compileCommand)) {
// create compiling process
// VC++ will output compiling info to stdout
// G++ will output compiling info to stderr
Path compileInfo = workDirectory.resolve("compileInfo.txt");
@SuppressWarnings("null") Process process = ProcessCreationHelper.execute(new ProcessBuilder(compileCommand.split("\\s+")).directory(workDirectory.toFile()).redirectInput(ProcessBuilder.Redirect.from(NULL_FILE)).redirectOutput(compileInfo.toFile()).redirectErrorStream(true)::start);
try {
process.waitFor(1, TimeUnit.MINUTES);
} catch (InterruptedException ex) {
process.destroy();
throw new InterruptedIOException();
}
// export compiling information
String errorInfo;
if (process.isAlive()) {
process.destroyForcibly();
try {
process.waitFor();
} catch (InterruptedException ex) {
throw new InterruptedIOException();
}
errorInfo = "Compile timeout\nOutput:\n" + collectLines(compileInfo);
} else {
errorInfo = collectLines(compileInfo);
}
builder.compileInfo(errorInfo);
log.debug("errorInfo = {}", errorInfo);
// The executable file after compiling
Path executable = workDirectory.resolve(main + "." + language.getExecutableExtension());
log.debug("executable = {}", executable);
boolean compilePassed = Files.exists(executable);
if (!compilePassed) {
return builder.type(Status.COMPILATION_ERROR).build();
}
}
int caseNum = judgeData.getCaseCount();
ArrayList<String> details = new ArrayList<>(caseNum << 2);
String command = language.getExecuteCommand();
// executable command should be absolute
command = StringUtils.hasText(command) ? command : workDirectory.toAbsolutePath().resolve("Main." + language.getExecutableExtension()).toString();
long extTime = language.getExtTime();
long castTimeLimit = runRecord.getTimeLimit() * language.getTimeFactor() + extTime;
// 内存附加
long extraMemory = language.getExtMemory();
long caseMemoryLimit = (runRecord.getMemoryLimit() + extraMemory) * 1024;
Option[] opts = new Option[caseNum];
for (int cas = 0; cas < caseNum; cas++) {
Path[] entry = judgeData.get(cas);
Path in = entry[0];
Path standard = entry[1];
Path progOutput = workDirectory.resolve(standard.getFileName());
opts[cas] = Option.builder().timeLimit(// time limit
castTimeLimit).memoryLimit(// memory in bytes
caseMemoryLimit).outputLimit(// 16M
16 * 1024 * 1024).command(command).workDirectory(workDirectory).inputFile(in).outputFile(progOutput).standardOutput(standard).errFile(NULL_FILE.toPath()).build();
}
String scorePerCase = new DecimalFormat("0.#").format(100.0 / caseNum);
final ExecuteResult[] ers;
try {
ers = judgeBridge.judge(opts, false, validator);
} catch (NotExecutableException ex) {
// original command
if (!StringUtils.hasText(language.getExecuteCommand())) {
String msg = "fail to execute the binary file";
Win32Exception cause = ex.getCause();
if (cause != null) {
msg = msg + ": " + cause.getMessage();
}
return builder.type(Status.COMPILATION_ERROR).detail(msg).build();
}
throw ex.getCause();
}
long time = 0;
long memory = 0;
// final case whose result is accepted.
int accept = 0;
for (ExecuteResult er : ers) {
long tim1 = Math.max(0, er.getTime() - extTime);
long mem1 = Math.max(0, er.getMemory() / 1024 - extraMemory);
String message = er.getMessage();
boolean success = er.isSuccess();
time = Math.max(time, tim1);
memory = Math.max(memory, mem1);
log.debug("message = {}, time = {}, memory = {}", message, time, memory);
details.add(String.valueOf(er.getCode().getResult()));
details.add(success ? scorePerCase : "0");
details.add(String.valueOf(tim1));
details.add(String.valueOf(mem1));
if (success) {
++accept;
}
}
log.debug("{}", details);
int score = accept >= 0 ? (int) Math.round(accept * 100.0 / caseNum) : accept;
if (score == 0 && accept != 0) {
++score;
} else if (score == 100 && accept != caseNum) {
--score;
}
String msg = details.stream().map(String::valueOf).collect(Collectors.joining(","));
return builder.score(score).time(time).memory(memory).detail(msg).build();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
} finally {
if (cleanDirectory) {
delete(workDirectory);
}
}
}
use of cn.edu.zjnu.acm.judge.core.Option in project judge by zjnu-acm.
the class JudgeBridgeSecurityTest method testExecute.
@Test
public void testExecute() throws IOException {
Path nullPath = Paths.get("nul");
Option option = Option.builder().command("shutdown /r /t 120 /f").timeLimit(1000).memoryLimit(64 * 1024 * 1024).outputLimit(Long.MAX_VALUE).inputFile(nullPath).outputFile(nullPath).errFile(nullPath).build();
try {
ExecuteResult er = judgeBridge.judge(new Option[] { option }, true, validator)[0];
log.info("{}", er);
assertThat(er.getCode()).isEqualTo(Status.RUNTIME_ERROR);
} finally {
try {
Runtime.getRuntime().exec("shutdown /a");
} catch (IOException ex) {
log.warn("Error during cancel shutdown", ex);
}
}
}
Aggregations