diff --git a/src/LiquidCode.Tester.Worker/Services/CSharpExecutionServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/CSharpExecutionServiceIsolate.cs index 709d7be..3261ea9 100644 --- a/src/LiquidCode.Tester.Worker/Services/CSharpExecutionServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/CSharpExecutionServiceIsolate.cs @@ -61,8 +61,15 @@ public class CSharpExecutionServiceIsolate : IExecutionService }); chmodProcess?.WaitForExit(); - // Prepare output file in box + // Prepare input/output files inside the sandbox var outputFilePath = Path.Combine(boxDir, "output.txt"); + string? sandboxInputPath = null; + + if (!string.IsNullOrEmpty(inputFilePath) && File.Exists(inputFilePath)) + { + sandboxInputPath = Path.Combine(boxDir, "input.txt"); + File.Copy(inputFilePath, sandboxInputPath, overwrite: true); + } // Run in Isolate var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions @@ -75,7 +82,7 @@ public class CSharpExecutionServiceIsolate : IExecutionService StackLimitKb = 256 * 1024, ProcessLimit = 1, // Single process for C# EnableNetwork = false, - StdinFile = inputFilePath, + StdinFile = sandboxInputPath, StdoutFile = outputFilePath, WorkingDirectory = "/box" }); diff --git a/src/LiquidCode.Tester.Worker/Services/CppExecutionServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/CppExecutionServiceIsolate.cs index 1c3789b..298d536 100644 --- a/src/LiquidCode.Tester.Worker/Services/CppExecutionServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/CppExecutionServiceIsolate.cs @@ -61,8 +61,15 @@ public class CppExecutionServiceIsolate : IExecutionService }); chmodProcess?.WaitForExit(); - // Prepare output file in box + // Prepare input/output files inside the sandbox var outputFilePath = Path.Combine(boxDir, "output.txt"); + string? sandboxInputPath = null; + + if (!string.IsNullOrEmpty(inputFilePath) && File.Exists(inputFilePath)) + { + sandboxInputPath = Path.Combine(boxDir, "input.txt"); + File.Copy(inputFilePath, sandboxInputPath, overwrite: true); + } // Run in Isolate var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions @@ -75,7 +82,7 @@ public class CppExecutionServiceIsolate : IExecutionService StackLimitKb = 256 * 1024, // 256 MB stack ProcessLimit = 1, // Single process only EnableNetwork = false, // No network access - StdinFile = inputFilePath, + StdinFile = sandboxInputPath, StdoutFile = outputFilePath, WorkingDirectory = "/box" }); diff --git a/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs b/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs index e34cac5..5e73382 100644 --- a/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs +++ b/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs @@ -1,3 +1,4 @@ +using System; using System.Diagnostics; using System.Text; @@ -157,17 +158,17 @@ public class IsolateService // I/O redirection if (!string.IsNullOrEmpty(options.StdinFile)) { - args.Add($"--stdin={options.StdinFile}"); + args.Add($"--stdin={MapSandboxPath(options.StdinFile, options.BoxId)}"); } if (!string.IsNullOrEmpty(options.StdoutFile)) { - args.Add($"--stdout={options.StdoutFile}"); + args.Add($"--stdout={MapSandboxPath(options.StdoutFile, options.BoxId)}"); } if (!string.IsNullOrEmpty(options.StderrFile)) { - args.Add($"--stderr={options.StderrFile}"); + args.Add($"--stderr={MapSandboxPath(options.StderrFile, options.BoxId)}"); } // Working directory @@ -210,6 +211,25 @@ public class IsolateService return string.Join(" ", args); } + private static string MapSandboxPath(string path, int boxId) + { + if (string.IsNullOrEmpty(path)) + { + return path; + } + + var normalizedPath = Path.GetFullPath(path); + var boxRoot = Path.GetFullPath($"/var/local/lib/isolate/{boxId}/box"); + + if (normalizedPath.StartsWith(boxRoot, StringComparison.Ordinal)) + { + var relative = normalizedPath.Substring(boxRoot.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + return relative.Length == 0 ? "/box" : $"/box/{relative.Replace(Path.DirectorySeparatorChar, '/')}"; + } + + return normalizedPath; + } + /// /// Parse isolate metadata file /// @@ -267,9 +287,6 @@ public class IsolateService case "status": result.Status = value; - result.TimeLimitExceeded = value == "TO"; - result.MemoryLimitExceeded = value == "XX" || value == "MLE"; - result.RuntimeError = value == "RE" || value == "SG"; break; case "message": @@ -282,7 +299,10 @@ public class IsolateService case "cg-oom-killed": result.CgroupOomKilled = value == "1"; - result.MemoryLimitExceeded = true; + if (result.CgroupOomKilled) + { + result.MemoryLimitExceeded = true; + } break; case "csw-voluntary": @@ -297,6 +317,29 @@ public class IsolateService } } + // Derive status-related flags after parsing all metadata + switch (result.Status) + { + case "TO": + result.TimeLimitExceeded = true; + break; + case "RE": + case "SG": + result.RuntimeError = true; + break; + case "XX": + // Internal error reported by isolate + result.RuntimeError = true; + break; + } + + if (!result.MemoryLimitExceeded && + !string.IsNullOrEmpty(result.Message) && + result.Message.Contains("memory limit", StringComparison.OrdinalIgnoreCase)) + { + result.MemoryLimitExceeded = true; + } + return result; } diff --git a/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs index 27fc0b9..d71bb4f 100644 --- a/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs @@ -57,8 +57,15 @@ public class JavaExecutionServiceIsolate : IExecutionService File.Copy(file, destPath, overwrite: true); } - // Prepare output file in box + // Prepare input/output files inside the sandbox var outputFilePath = Path.Combine(boxDir, "output.txt"); + string? sandboxInputPath = null; + + if (!string.IsNullOrEmpty(inputFilePath) && File.Exists(inputFilePath)) + { + sandboxInputPath = Path.Combine(boxDir, "input.txt"); + File.Copy(inputFilePath, sandboxInputPath, overwrite: true); + } // Run in Isolate // Note: Java needs more memory for JVM overhead @@ -75,7 +82,7 @@ public class JavaExecutionServiceIsolate : IExecutionService StackLimitKb = 256 * 1024, // 256 MB stack ProcessLimit = 64, // Java creates multiple threads EnableNetwork = false, - StdinFile = inputFilePath, + StdinFile = sandboxInputPath, StdoutFile = outputFilePath, WorkingDirectory = "/box" }); diff --git a/src/LiquidCode.Tester.Worker/Services/KotlinExecutionServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/KotlinExecutionServiceIsolate.cs index a95c686..f5d11ce 100644 --- a/src/LiquidCode.Tester.Worker/Services/KotlinExecutionServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/KotlinExecutionServiceIsolate.cs @@ -52,8 +52,15 @@ public class KotlinExecutionServiceIsolate : IExecutionService File.Copy(executablePath, boxJarPath, overwrite: true); - // Prepare output file in box + // Prepare input/output files inside the sandbox var outputFilePath = Path.Combine(boxDir, "output.txt"); + string? sandboxInputPath = null; + + if (!string.IsNullOrEmpty(inputFilePath) && File.Exists(inputFilePath)) + { + sandboxInputPath = Path.Combine(boxDir, "input.txt"); + File.Copy(inputFilePath, sandboxInputPath, overwrite: true); + } // Run in Isolate (Kotlin runs via Java) var kotlinMemoryMb = Math.Max(memoryLimitMb, 128); // Minimum 128MB for JVM @@ -69,7 +76,7 @@ public class KotlinExecutionServiceIsolate : IExecutionService StackLimitKb = 256 * 1024, ProcessLimit = 64, // JVM creates multiple threads EnableNetwork = false, - StdinFile = inputFilePath, + StdinFile = sandboxInputPath, StdoutFile = outputFilePath, WorkingDirectory = "/box" }); diff --git a/src/LiquidCode.Tester.Worker/Services/PythonExecutionServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/PythonExecutionServiceIsolate.cs index 78f3a01..0ec1f06 100644 --- a/src/LiquidCode.Tester.Worker/Services/PythonExecutionServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/PythonExecutionServiceIsolate.cs @@ -55,8 +55,15 @@ public class PythonExecutionServiceIsolate : IExecutionService File.Copy(executablePath, boxScriptPath, overwrite: true); - // Prepare output file in box + // Prepare input/output files inside the sandbox var outputFilePath = Path.Combine(boxDir, "output.txt"); + string? sandboxInputPath = null; + + if (!string.IsNullOrEmpty(inputFilePath) && File.Exists(inputFilePath)) + { + sandboxInputPath = Path.Combine(boxDir, "input.txt"); + File.Copy(inputFilePath, sandboxInputPath, overwrite: true); + } // Get Python executable from configuration var pythonExecutable = _configuration["Python:Executable"] ?? "python3"; @@ -73,7 +80,7 @@ public class PythonExecutionServiceIsolate : IExecutionService StackLimitKb = 256 * 1024, ProcessLimit = 1, // Single process for Python EnableNetwork = false, - StdinFile = inputFilePath, + StdinFile = sandboxInputPath, StdoutFile = outputFilePath, WorkingDirectory = "/box" });