test memory limit
Some checks failed
memory-limit / Build judge (push) Successful in 18s
memory-limit / Linux / gcc (push) Failing after 14s
memory-limit / Linux / clang (push) Failing after 15s
memory-limit / Windows / clang (push) Failing after 16s
memory-limit / Windows / msvc (push) Failing after 17s
Some checks failed
memory-limit / Build judge (push) Successful in 18s
memory-limit / Linux / gcc (push) Failing after 14s
memory-limit / Linux / clang (push) Failing after 15s
memory-limit / Windows / clang (push) Failing after 16s
memory-limit / Windows / msvc (push) Failing after 17s
This commit is contained in:
126
.gitea/workflows/memory.yml
Normal file
126
.gitea/workflows/memory.yml
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
name: memory-limit
|
||||||
|
run-name: "memory_limit enforcement check"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
SUITE_FILE: mem.jdg
|
||||||
|
EXAMPLE_DIR: example/mem-limit
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_judge:
|
||||||
|
name: Build judge
|
||||||
|
runs-on: Linux-Runner
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.22'
|
||||||
|
|
||||||
|
- name: Cross-compile judge
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dist/judge-linux-amd64 ./cmd/cli
|
||||||
|
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o dist/judge-windows-amd64.exe ./cmd/cli
|
||||||
|
|
||||||
|
- name: Upload judge binaries
|
||||||
|
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: judge-bin-mem
|
||||||
|
path: dist/
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
check:
|
||||||
|
needs: build_judge
|
||||||
|
name: "${{ matrix.toolchain.system }} / ${{ matrix.toolchain.use_compiler }}"
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
toolchain:
|
||||||
|
- { system: Linux, use_compiler: gcc }
|
||||||
|
- { system: Linux, use_compiler: clang }
|
||||||
|
- { system: Windows, use_compiler: clang }
|
||||||
|
- { system: Windows, use_compiler: msvc }
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.toolchain.system }}-Runner
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
|
env:
|
||||||
|
CC: ${{ matrix.toolchain.use_compiler }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout judge harness
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up MSVC environment
|
||||||
|
if: matrix.toolchain.use_compiler == 'msvc'
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
|
||||||
|
- name: Download judge binary
|
||||||
|
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: judge-bin-mem
|
||||||
|
path: judge-bin
|
||||||
|
|
||||||
|
- name: Install judge on PATH
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p bin
|
||||||
|
if [ "${{ matrix.toolchain.system }}" = "Windows" ]; then
|
||||||
|
cp judge-bin/judge-windows-amd64.exe bin/judge.exe
|
||||||
|
else
|
||||||
|
cp judge-bin/judge-linux-amd64 bin/judge
|
||||||
|
chmod +x bin/judge
|
||||||
|
fi
|
||||||
|
echo "$PWD/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
- name: Install jq (Linux)
|
||||||
|
if: matrix.toolchain.system == 'Linux'
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y jq
|
||||||
|
|
||||||
|
- name: Run judge and capture JSON
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ env.EXAMPLE_DIR }}
|
||||||
|
run: |
|
||||||
|
# `|| true` — the "exceeds_limit" group is *expected* to have a
|
||||||
|
# failing test, so judge will exit non-zero.
|
||||||
|
judge "$SUITE_FILE" . --json > report.json || true
|
||||||
|
cat report.json
|
||||||
|
|
||||||
|
- name: Assert enforcement
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ env.EXAMPLE_DIR }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
pass_status=$(jq -r '.groups[] | select(.name=="within_limit") | .tests[] | select(.name=="allocate_16mb") | .status' report.json)
|
||||||
|
fail_status=$(jq -r '.groups[] | select(.name=="exceeds_limit") | .tests[] | select(.name=="allocate_256mb") | .status' report.json)
|
||||||
|
pass_peak=$(jq -r '.groups[] | select(.name=="within_limit") | .tests[] | select(.name=="allocate_16mb") | .peak_memory_kb // 0' report.json)
|
||||||
|
fail_peak=$(jq -r '.groups[] | select(.name=="exceeds_limit") | .tests[] | select(.name=="allocate_256mb") | .peak_memory_kb // 0' report.json)
|
||||||
|
|
||||||
|
echo "within_limit/allocate_16mb: status=$pass_status peak=${pass_peak} KiB"
|
||||||
|
echo "exceeds_limit/allocate_256mb: status=$fail_status peak=${fail_peak} KiB"
|
||||||
|
|
||||||
|
rc=0
|
||||||
|
if [ "$pass_status" != "PASS" ]; then
|
||||||
|
echo "FAIL: within_limit test should PASS, got $pass_status"
|
||||||
|
rc=1
|
||||||
|
fi
|
||||||
|
if [ "$fail_status" != "MLE" ]; then
|
||||||
|
echo "FAIL: exceeds_limit test should be MLE, got $fail_status"
|
||||||
|
rc=1
|
||||||
|
fi
|
||||||
|
if [ "${pass_peak:-0}" -le 0 ]; then
|
||||||
|
echo "FAIL: within_limit peak memory not reported (got $pass_peak)"
|
||||||
|
rc=1
|
||||||
|
fi
|
||||||
|
exit $rc
|
||||||
35
example/mem-limit/mem.jdg
Normal file
35
example/mem-limit/mem.jdg
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// End-to-end check that memory_limit is actually enforced by the runner.
|
||||||
|
// The solution allocates N MiB (argv[1]) and touches every page.
|
||||||
|
//
|
||||||
|
// - "within_limit" allocates 16 MiB under a 256 MiB cap → expected PASS
|
||||||
|
// - "exceeds_limit" allocates 256 MiB under a 64 MiB cap → expected MLE
|
||||||
|
//
|
||||||
|
// The workflow runs judge --json and asserts these statuses via jq.
|
||||||
|
|
||||||
|
build "$CC -O2 -std=c11 -Wall -Wextra solution.c -o solution"
|
||||||
|
build_windows "if /I \"%CC%\"==\"msvc\" (cl /nologo /O2 /W3 solution.c /Fe:solution.exe) else (%CC% -O2 -std=c11 -Wall -Wextra solution.c -o solution.exe)"
|
||||||
|
|
||||||
|
binary = "solution"
|
||||||
|
timeout 10s
|
||||||
|
|
||||||
|
normalize_crlf = true
|
||||||
|
|
||||||
|
group("within_limit") {
|
||||||
|
weight = 1.0
|
||||||
|
memory_limit = 256M
|
||||||
|
|
||||||
|
test("allocate_16mb") {
|
||||||
|
args = ["16"]
|
||||||
|
stdout = "ok 16\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group("exceeds_limit") {
|
||||||
|
weight = 0.0 // score doesn't matter — we assert the status in CI
|
||||||
|
memory_limit = 64M
|
||||||
|
|
||||||
|
test("allocate_256mb") {
|
||||||
|
args = ["256"]
|
||||||
|
// no stdout matcher: process is expected to be killed before it prints
|
||||||
|
}
|
||||||
|
}
|
||||||
27
example/mem-limit/solution.c
Normal file
27
example/mem-limit/solution.c
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "usage: %s <megabytes>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
long mb = strtol(argv[1], NULL, 10);
|
||||||
|
if (mb <= 0) return 1;
|
||||||
|
|
||||||
|
size_t bytes = (size_t)mb * 1024 * 1024;
|
||||||
|
char *p = (char *)malloc(bytes);
|
||||||
|
if (!p) {
|
||||||
|
fprintf(stderr, "malloc failed\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < bytes; i += 4096) {
|
||||||
|
p[i] = (char)(i & 0xff);
|
||||||
|
}
|
||||||
|
volatile char sink = p[bytes - 1];
|
||||||
|
(void)sink;
|
||||||
|
|
||||||
|
printf("ok %ld\n", mb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user