GOAL P4: --report-unsafe 와 --report-instances, 그리고 예산을 CI 에
'ffec 에서 unsafe 가 몇 군데인가' 는 좋은 지표인데 세는 방법이 없으면 지표가 아니다. 이제 센다. unit unsafe *T unchecked std.io 6 1 0 std.sys 10 12 0 total 16 13 0 outside std 0 0 0 Ferro 렉서와 파서, interner, 아레나, 맵을 쓰는 프로그램 전부가 std 바깥에서 0 이다. 목표치를 이미 지키고 있었던 셈인데, 그것을 아무도 확인할 수 없었다. run.py 가 그 숫자를 검사한다. std.mem 과 std.sys 밖의 unsafe 와 *T 는 검사기가 약속한 것에 뚫린 구멍이므로 0 을 유지해야 하고, 늘어나면 알아채는 것이 아니라 빌드가 실패해야 한다. unsafe 블록 하나를 넣어 실패하는 것까지 확인했다. --report-instances 는 제네릭이 무엇이 됐는지 센다. interns.fe 는 20 인스턴스, 타입 4 개에 저장소 80 바이트, 메서드 16 개다. 245/245, 38/38.
This commit is contained in:
+34
-1
@@ -34,7 +34,7 @@ FIXTURES = ROOT / "fec" / "tests"
|
||||
WATCOM = ROOT / ".dosboxx" / "watcom"
|
||||
SOURCES = ("arena", "diag", "lexer", "ast", "parser", "types", "m7", "own",
|
||||
"check", "checkexp", "checkstm", "checkgen", "checkcal", "checkpro",
|
||||
"resolve", "ir", "lower", "lowerprn", "lowerexp", "lowerstm", "x86", "driver")
|
||||
"resolve", "ir", "lower", "lowerprn", "lowerexp", "lowerstm", "x86", "report", "driver")
|
||||
|
||||
MARKER = re.compile(r"^//\s*ERROR:(?:(\d+):)?(.*)$")
|
||||
|
||||
@@ -132,8 +132,41 @@ def main() -> int:
|
||||
marked = sum(1 for p in cases if expectation(p).line is not None)
|
||||
print(f"\n{len(cases) - len(failed)}/{len(cases)} passed "
|
||||
f"({marked} pin a line and message)")
|
||||
if not args.select:
|
||||
leak = unsafe_budget(fec)
|
||||
if leak:
|
||||
print(leak)
|
||||
return 1
|
||||
return 1 if failed else 0
|
||||
|
||||
|
||||
# The programs the budget is measured on: the Ferro front end, and the ones
|
||||
# that lean hardest on the standard library.
|
||||
BUDGETED = ("exec/lexer/tree.fe", "exec/interns.fe", "exec/arenat.fe",
|
||||
"exec/maps.fe", "exec/wordfreq.fe")
|
||||
|
||||
|
||||
def unsafe_budget(fec: Path) -> str:
|
||||
"""`unsafe` and `*T` belong to std.mem and std.sys. Anywhere else they are
|
||||
a hole in what the checker promises, so the count outside std has to stay
|
||||
at zero and a regression has to fail the build rather than be noticed."""
|
||||
for rel in BUDGETED:
|
||||
path = FIXTURES / rel
|
||||
if not path.is_file():
|
||||
return f"budget: {rel} is gone"
|
||||
done = subprocess.run([str(fec), "--report-unsafe", str(path),
|
||||
f"--std={ROOT / 'fec'}"],
|
||||
capture_output=True, text=True)
|
||||
line = [l for l in done.stdout.splitlines()
|
||||
if l.startswith("outside std")]
|
||||
if not line:
|
||||
return f"budget: no report for {rel}\n{done.stdout}{done.stderr}"
|
||||
counts = line[0].split()[2:]
|
||||
if any(c != "0" for c in counts):
|
||||
return (f"budget: {rel} has unsafe/raw pointers outside std: "
|
||||
f"{line[0]}")
|
||||
return ""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
||||
Reference in New Issue
Block a user