feat: add lab-rv32i-c-smalloc-sbrk-libc card
This commit is contained in:
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
task01_map="$root/build/task01_libc_without_heap/prog.map"
|
||||
task05_map="$root/build/task05_picolibc_malloc/prog.map"
|
||||
|
||||
grep -q 'libc.a(strlen.c.o)' "$task01_map"
|
||||
if grep -Eq 'libc_stdlib_malloc.c.o|libc_stdlib_free.c.o|libc_misc_picosbrk.c.o' "$task01_map"; then
|
||||
echo 'FAIL Task01: heap-related archive member entered the image' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for member in libc_stdlib_malloc.c.o libc_stdlib_free.c.o libc_misc_picosbrk.c.o; do
|
||||
grep -q "$member" "$task05_map"
|
||||
done
|
||||
|
||||
printf '%s\n' \
|
||||
'PASS Task01 map: strlen.c.o present, malloc/free/picosbrk absent' \
|
||||
'PASS Task05 map: malloc/free/picosbrk archive members present'
|
||||
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
pdf_count="$(find "$root/doc/pdf" -maxdepth 1 -type f -name '*.pdf' | wc -l)"
|
||||
[[ "$pdf_count" -eq 1 ]]
|
||||
|
||||
python3 - "$root/json/card_source.json" "$root/web/card-data.json" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
with open(sys.argv[1], encoding="utf-8") as stream:
|
||||
card = json.load(stream)
|
||||
with open(sys.argv[2], encoding="utf-8") as stream:
|
||||
web = json.load(stream)
|
||||
|
||||
assert card["tasks_order"] == [f"task{number:02d}" for number in range(1, 6)]
|
||||
blocks = []
|
||||
flow_ids = []
|
||||
for task_id in card["tasks_order"]:
|
||||
task = card["tasks"][task_id]
|
||||
viewpoints = task["viewpoints"]
|
||||
assert [item["id"] for item in viewpoints] == [f"A{number}" for number in range(1, 9)]
|
||||
assert len(viewpoints) == 8
|
||||
assert all(item["status"] in {"enabled", "unavailable"} for item in viewpoints)
|
||||
assert all(item.get("id") for item in task["flow"])
|
||||
flow_ids.extend(item["id"] for item in task["flow"])
|
||||
blocks.extend(item for item in task["flow"] if item["id"].startswith(task_id + ".a"))
|
||||
assert len(blocks) == 40
|
||||
assert len(flow_ids) == len(set(flow_ids))
|
||||
task02_proof = next(
|
||||
item for item in card["tasks"]["task02"]["flow"]
|
||||
if item["id"] == "task02.proof"
|
||||
)
|
||||
assert "programu hostowego" not in task02_proof["evidence_tex"]
|
||||
assert "brakująca nazwa" in task02_proof["evidence_tex"]
|
||||
|
||||
def viewpoint_ids(value):
|
||||
if isinstance(value, dict):
|
||||
identifier = value.get("id")
|
||||
if isinstance(identifier, str) and identifier.rsplit(".", 1)[-1] in {
|
||||
f"a{number}" for number in range(1, 9)
|
||||
}:
|
||||
yield identifier
|
||||
for child in value.values():
|
||||
yield from viewpoint_ids(child)
|
||||
elif isinstance(value, list):
|
||||
for child in value:
|
||||
yield from viewpoint_ids(child)
|
||||
|
||||
web_ids = list(viewpoint_ids(web))
|
||||
assert len(web_ids) == 40
|
||||
assert len(set(web_ids)) == 40
|
||||
print("PASS card JSON: 5 tasks x exact A1-A8 = 40 viewpoint blocks")
|
||||
PY
|
||||
|
||||
tex_viewpoints="$(rg -o '\\begin\{ESCBlockFrame\}\{A[1-8] ' \
|
||||
"$root/doc/generated/main.tex" | wc -l)"
|
||||
[[ "$tex_viewpoints" -eq 40 ]]
|
||||
for viewpoint in {1..8}; do
|
||||
count="$(rg -o "\\\\begin\\{ESCBlockFrame\\}\\{A${viewpoint} " \
|
||||
"$root/doc/generated/main.tex" | wc -l)"
|
||||
[[ "$count" -eq 5 ]]
|
||||
done
|
||||
|
||||
tex_count="$(rg -o '\\textbf\{N/D\.\}' "$root/doc/generated/main.tex" | wc -l)"
|
||||
[[ "$tex_count" -ge 6 ]]
|
||||
qpdf --check "$root"/doc/pdf/*.pdf
|
||||
rg -q 'task02\.a6' "$root/json/card_source.json"
|
||||
|
||||
pdf_text="$(mktemp)"
|
||||
trap 'rm -f -- "$pdf_text"' EXIT
|
||||
pdftotext "$root"/doc/pdf/*.pdf "$pdf_text"
|
||||
pdf_viewpoints="$(rg -o 'BLOCK A[1-8]' "$pdf_text" | wc -l)"
|
||||
[[ "$pdf_viewpoints" -eq 40 ]]
|
||||
if rg -qi 'anonymous|anonimowy|bez nazwy' "$pdf_text"; then
|
||||
echo 'FAIL card: anonymous block marker found' >&2
|
||||
exit 1
|
||||
fi
|
||||
printf 'PASS card artifacts: TeX, web and one valid PDF\n'
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
nm_tool="${RISCV_PREFIX:-riscv64-unknown-elf-}nm"
|
||||
readelf_tool="${RISCV_PREFIX:-riscv64-unknown-elf-}readelf"
|
||||
|
||||
symbol_value() {
|
||||
"$nm_tool" -n "$1" | awk -v wanted="$2" '$3 == wanted { print $1; exit }'
|
||||
}
|
||||
|
||||
for task in \
|
||||
task01_libc_without_heap \
|
||||
task03_bounded_sbrk \
|
||||
task04_smalloc \
|
||||
task05_picolibc_malloc; do
|
||||
elf="$root/build/$task/prog.elf"
|
||||
start_hex="$(symbol_value "$elf" __heap_start)"
|
||||
end_hex="$(symbol_value "$elf" __heap_end)"
|
||||
stack_bottom_hex="$(symbol_value "$elf" __stack_bottom)"
|
||||
reset_hex="$(symbol_value "$elf" .reset_handler)"
|
||||
[[ -n "$start_hex" && -n "$end_hex" && -n "$stack_bottom_hex" ]]
|
||||
[[ "$reset_hex" == "80000040" ]]
|
||||
(( 16#$start_hex <= 16#$end_hex ))
|
||||
(( 16#$end_hex == 16#$stack_bottom_hex ))
|
||||
(( (16#$start_hex & 15) == 0 ))
|
||||
(( (16#$end_hex & 15) == 0 ))
|
||||
"$readelf_tool" -h "$elf" | grep -q 'Class:.*ELF32'
|
||||
if "$readelf_tool" -lW "$elf" | grep -Eq 'LOAD.*RWE'; then
|
||||
echo "FAIL $task: writable and executable LOAD segment" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
task05="$root/build/task05_picolibc_malloc/prog.elf"
|
||||
for symbol in _sbrk sbrk malloc free __heap_start __heap_end; do
|
||||
[[ -n "$(symbol_value "$task05" "$symbol")" ]]
|
||||
done
|
||||
|
||||
printf '%s\n' \
|
||||
'PASS linker: reset=0x80000040; bounded aligned heap; no RWX LOAD segment' \
|
||||
'PASS Task05 ELF: vendor _sbrk and picolibc sbrk coexist'
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
if [[ "${1:-}" != "--already-built" ]]; then
|
||||
make -C "$root" PROFILE=observe host >/dev/null
|
||||
fi
|
||||
|
||||
check_output() {
|
||||
local program="$1" expected="$2" actual
|
||||
actual="$($program)"
|
||||
if [[ "$actual" != "$expected" ]]; then
|
||||
printf 'FAIL %s\nexpected: %s\nactual: %s\n' \
|
||||
"$program" "$expected" "$actual" >&2
|
||||
return 1
|
||||
fi
|
||||
printf 'PASS %s: %s\n' "$(basename -- "$(dirname -- "$program")")" "$actual"
|
||||
}
|
||||
|
||||
check_output "$root/host-build/task01_libc_without_heap/prog" \
|
||||
'length=16 pass=1'
|
||||
check_output "$root/host-build/task03_bounded_sbrk/prog" \
|
||||
'grow=40 rejected_grow=40 shrink=32 rejected_shrink=32 preserved=1 bounds=1 pass=1'
|
||||
check_output "$root/host-build/task04_smalloc/prog" \
|
||||
'header=16 first=32 second=48 delta=32 aligned=1 metadata=1 append=1 reset=1 pass=1'
|
||||
check_output "$root/host-build/task05_picolibc_malloc/prog" \
|
||||
'nonnull=1 delta_nonzero=1 checksum=4612 nonoverlap=1 aligned=1 freed=1 pass=1'
|
||||
|
||||
Reference in New Issue
Block a user