Repository navigation
fix(hy-check): reject known non-string fmt format operands (HYB-E1002) — Fixes #4195 - #4196
Conversation
The fmt printf-family validator from limitlessprojects#4087 only rejected non-string *literals* as the format argument, so a statically known non-string expression - fmt.printf(x) with x := 42, fmt.printf(42 * 1), fmt.fprintf(w, x) - passed hyb check with 0 diagnostics and failed go build with cannot use ... as string in argument to fmt.Printf. Extends the printf/sprintf/eprintf/errorf and fprintf branches of check_call_operands with a kind check: when kind_of_expr of the format operand is definitely non-string (Int/Float/Bool/...) the existing HYB-E1002 fires. Str, Unknown, and any (Interface) stay fail-open exactly like every other accept-side guard in buildable.rs. Tests: 8 regression tests in fmt_special_member_calls_buildable.rs (int local, int/float binop, sprintf/eprintf/errorf int local, fprintf int local; accepts for string local, string concat, any).
Landed — merge
|
| Gate | Result |
|---|---|
| Merge gate | auto-merge clean, no conflict; landed fmt arms + scan suite verified present in merged tree |
cargo test --workspace |
3198 passed / 0 failed; 486 suites = 486 Running lines (1:1) |
| corpus harness | 139/139, tripwire not fired (verdict-level 2/139, as-written 3/139, threshold ~25%) |
| differential loop | FULL AGREEMENT — accept 47/47 + reject 92/92 |
Protocol followed: merge --no-ff with hand-written credit commit (evidence in the merge message), pushed and git ls-remote == local HEAD asserted before this reply. No silent closes, no fixture fixups needed.
Bounty rail: recorded as a Row-13 BUILDABLE soundness improvement for the current cycle per BOUNTY.md — main pool ladder ($500/cycle, 1st $75 → 10th $45) plus Wildcard Track, judged in discussion #295. This one qualifies on the main track: it turns a real go-build-failure class into a checker-level reject with a positive control.
Next in queue: #4198/#4199/#4221. Pending author fixes: #4202/#4201 (suite controls), #4206, #4097, #4217, #4219, #4215/#4213/#4211 (allowlist re-target).
Fixes #4195.
Change
Extends the printf-family operand validation from #4087 (which only rejected non-string literals) to statically known non-string expressions:
hy-check/buildable.rs: incheck_call_operands, both theprintf/sprintf/eprintf/errorfbranch (format =args[0]) and thefprintfbranch (format =args[1]) now also checkkind_of_exprof the format operand. A definitely-non-stringkind (int,float64,bool, …) fires the existingHYB-E1002.Str,Unknown, andany(Interface) stay fail-open, mirroring every other accept-side guard in the file.hy-check/tests/fmt_special_member_calls_buildable.rs: 8 regression tests (int local, int/float binop, sprintf/eprintf/errorf int local, fprintf int-local format; plus string-local / string-concat /anyaccepts).Evidence
Before (current
main@ce6219cd, freshhyb check):x := 42; fmt.printf(x)→OK (0 diagnostics)fmt.printf(42 * 1),fmt.printf(1 + 2),fmt.sprintf(x),fmt.fprintf(os.stdout, x)→ allOK (0 diagnostics)After this change (same binary rebuilt from this branch):
error[HYB-E1002]: \fmt.printf` requires a string format argument, found non-string (int) (HYB-E1002)`s := "hello"; fmt.printf(s)→ stillOK (0 diagnostics)Tests
cargo test -p hy-check --test fmt_special_member_calls_buildable: 21/21 ok (13 existing + 8 new).cargo test --workspace --no-fail-fast: 0 regressions — the only failures are 10 tests in 6hyb-crate binaries that shell out tohyb buildand require the pinnedgo1.26.9(HYB-E9001on this machine'sgo1.27.2); verified byte-identical failures on pristineorigin/mainwithout this change.python3 tools/check_test_registration.py→OK (40 test file(s), 36 discovery pattern(s)).Payout wallet (Base USDC):
0xbbe6966949d7265a7f5f0b793f08293b9b7fe926