test-jv / runner.py
Arghya Ghosh
Update runner.py
f79700a verified
import os
import re
import shutil
import subprocess
import tempfile
import uuid
import resource
import time
MAX_CODE_SIZE = 50_000 # 50 KB max user code
MAX_EXECUTION_TIME = 5 # 5 seconds max execution
JAVA_HEAP_LIMIT = "1024m" # 1 GB max heap for Java user code
def extract_class_name(code: str) -> str:
match = re.search(r'public\s+class\s+(\w+)', code)
return match.group(1) if match else "Main"
def set_limits():
# Limit only CPU time; no artificial memory limit
import resource
resource.setrlimit(resource.RLIMIT_CPU, (MAX_EXECUTION_TIME, MAX_EXECUTION_TIME))
def run_java(code: str):
import os, tempfile, subprocess, uuid, shutil, time, re
if len(code.encode("utf-8")) > MAX_CODE_SIZE:
return {"status": "error", "message": "Code too large"}
run_id = str(uuid.uuid4())
workdir = os.path.join(tempfile.gettempdir(), f"runner_{run_id}")
os.makedirs(workdir, exist_ok=True)
try:
class_name = re.search(r'public\s+class\s+(\w+)', code)
class_name = class_name.group(1) if class_name else "Main"
java_file = os.path.join(workdir, f"{class_name}.java")
with open(java_file, "w") as f:
f.write(code)
# Compile
start_compile = time.time()
compile_proc = subprocess.run(
["javac", java_file],
capture_output=True, text=True, cwd=workdir
)
compile_time = (time.time() - start_compile) * 1000
if compile_proc.returncode != 0:
return {
"status": "error",
"stage": "compile",
"compile_time_ms": round(compile_time, 2),
"exit_code": compile_proc.returncode,
"stdout": compile_proc.stdout,
"stderr": compile_proc.stderr
}
# Run
start_run = time.time()
run_proc = subprocess.run(
["java", f"-Xmx{JAVA_HEAP_LIMIT}", "-cp", workdir, class_name],
capture_output=True, text=True,
cwd=workdir,
timeout=MAX_EXECUTION_TIME,
preexec_fn=set_limits
)
run_time = (time.time() - start_run) * 1000
return {
"status": "success",
"compile_time_ms": round(compile_time, 2),
"execution_time_ms": round(run_time, 2),
"exit_code": run_proc.returncode,
"stdout": run_proc.stdout,
"stderr": run_proc.stderr
}
except subprocess.TimeoutExpired:
return {"status": "error", "stage": "run", "message": "Execution timed out"}
finally:
shutil.rmtree(workdir, ignore_errors=True)