Download testing/capi/printf_oracle.c from PYTHAI/bankml: direct link, hf CLI and curl.
- Browser
- Download file 7.95 kB
-
https://huggingface.co/spaces/PYTHAI/bankml/resolve/main/testing/capi/printf_oracle.c
- Command line
-
hf download hf://spaces/PYTHAI/bankml/testing/capi/printf_oracle.c
-
curl -L -o printf_oracle.c https://huggingface.co/spaces/PYTHAI/bankml/resolve/main/testing/capi/printf_oracle.c
7.95 kB
| /* SPDX-License-Identifier: MIT OR Apache-2.0 */ | |
| /* | |
| * The printf oracle for bankml_log (0.3.2): for every case, the message bankml_log delivers to the sink must equal, | |
| * byte for byte (length included, an embedded NUL included), what this machine's libc snprintf writes for the same | |
| * format and arguments. Then the cases bankml_log does not support: each must come out as its explicit marker, read | |
| * no argument it cannot type, and never write through %n. | |
| * cc -O2 -Wall -Wextra -Wno-format -Werror printf_oracle.c -I capi/include -L target/release -lbankml | |
| * (-Wno-format: some cases are deliberately unusual formats.) Exit 0 only if every case passes. | |
| */ | |
| static char got[1 << 16]; | |
| static size_t got_len; | |
| static int got_level, calls, total, failed; | |
| static void sink(int level, const char *msg, size_t len, void *user) { | |
| (void)user; | |
| if (len >= sizeof got) len = sizeof got - 1; | |
| memcpy(got, msg, len); | |
| got_len = len; | |
| got_level = level; | |
| calls++; | |
| if (msg[len] != '\0') { printf(" sink: message not NUL-terminated\n"); failed++; } | |
| } | |
| static void show(const char *what, const char *s, size_t n) { | |
| printf(" %s (%zu bytes): \"", what, n); | |
| for (size_t i = 0; i < n; i++) { | |
| unsigned char c = (unsigned char)s[i]; | |
| if (c < 32 || c == '"' || c == '\\' || c >= 127) printf("\\x%02x", c); else putchar(c); | |
| } | |
| printf("\"\n"); | |
| } | |
| static void check(const char *label, const char *want, size_t want_len) { | |
| total++; | |
| if (got_level != BANKML_LOG_INFO || got_len != want_len || memcmp(got, want, want_len) != 0) { | |
| failed++; | |
| printf(" DIFFERS: %s\n", label); | |
| show("libc snprintf", want, want_len); | |
| show("bankml_log ", got, got_len); | |
| } | |
| } | |
| /* the same format and arguments through snprintf and bankml_log */ | |
| /* a case bankml_log does not support: the exact marker text */ | |
| int main(void) { | |
| bankml_set_log(sink, NULL); | |
| int local = 0; | |
| const char *s = "bankml"; | |
| const char unterminated[2] = {'a', 'b'}; | |
| /* integers, at their limits and in every supported length */ | |
| SAME("%d|%d|%d|%d|%d", 0, 1, -1, INT_MIN, INT_MAX); | |
| SAME("%i|%i", INT_MIN, INT_MAX); | |
| SAME("%u|%u|%u", 0u, 1u, UINT_MAX); | |
| SAME("%ld|%ld|%ld", LONG_MIN, LONG_MAX, 0L); | |
| SAME("%lu|%lu", ULONG_MAX, 0UL); | |
| SAME("%lld|%lld|%lld", LLONG_MIN, LLONG_MAX, -1LL); | |
| SAME("%llu|%llu", ULLONG_MAX, 0ULL); | |
| SAME("%zu|%zu|%zd|%zd", SIZE_MAX, (size_t)0, (ssize_t)-1, (ssize_t)PTRDIFF_MAX); | |
| SAME("%hhd|%hhd|%hd|%hd|%hhu|%hu", 300, -129, 70000, -32769, 511u, 65537u); | |
| SAME("%x|%X|%x|%x|%X", 0xdeadbeefu, 0xdeadbeefu, 0u, UINT_MAX, 0xabcu); | |
| SAME("%#x|%#X|%#x", 255u, 255u, 0u); | |
| SAME("%lx|%llX|%zx|%hhx|%hx", ULONG_MAX, ULLONG_MAX, SIZE_MAX, 0x1ffu, 0x12345u); | |
| SAME("[%5d|%-5d|%05d|%+d|% d|%+ d|%+d]", 42, 42, -42, 7, 7, 7, -7); | |
| SAME("[%.3d|%.0d|%.0d|%8.3d|%-8.3d|%08.3d|%.10d]", 5, 0, 1, -5, -5, 5, INT_MIN); | |
| SAME("[%08x|%#010x|%-#10x|%#.6x|%.0x|%#.0x]", 0xbeefu, 0xbeefu, 0xbeefu, 0xbeefu, 0u, 0u); | |
| SAME("[%*d|%-*d|%*d|%.*d|%.*d|%*.*d]", 6, 42, 6, 42, -6, 42, 4, 7, -1, 7, 8, 5, -3); | |
| SAME("[%+u|% u|%+x|% X]", 3u, 3u, 255u, 255u); | |
| SAME("[%020lld|%-20llu|%+lld]", LLONG_MIN, ULLONG_MAX, LLONG_MAX); | |
| /* %f: precision, rounding (ties to even on the exact binary value), signs, flags, extremes, inf and nan */ | |
| SAME("%f|%f|%f|%f", 0.0, -0.0, 1.0, -1.0); | |
| SAME("%f|%.3f|%.3f|%.1f", 3.14258, -2.0005, 2.0005, 0.25); | |
| SAME("%.0f|%.0f|%.0f|%.0f|%.0f|%.0f", 0.5, 1.5, 2.5, -0.5, 0.49999999999999994, 1e15 + 0.5); | |
| SAME("%.20f|%.17f|%.10f|%.30f", 0.1, 0.1 + 0.2, 1.0 / 3.0, 1e-20); | |
| SAME("%f|%f", 1e300, -1e300); | |
| SAME("%f|%.320f", DBL_MIN, DBL_MIN); | |
| SAME("%.1100f", 4.9406564584124654e-324); | |
| SAME("%f", DBL_MAX); | |
| SAME("[%#.0f|%#f|%#.2f]", 3.0, 3.0, 3.0); | |
| SAME("[%10.2f|%-10.2f|%010.2f|%+.1f|% .1f|%+010.3f|% 010.3f]", -1.005, 1.0, -3.25, 0.0, 0.0, 2.5, 2.5); | |
| SAME("[%*.*f|%-*.*f|%.*f]", 12, 4, 2.718281828, 12, 4, 2.718281828, -1, 2.718281828); | |
| SAME("[%lf|%F|%F]", 2.5, 1.25, -1.25); | |
| SAME("[%f|%f|%f|%f]", INFINITY, -INFINITY, NAN, -NAN); | |
| SAME("[%F|%F|%F|%F]", INFINITY, -INFINITY, NAN, -NAN); | |
| SAME("[%5f|%-6f|%05f|%+f|% f|%010F]", INFINITY, NAN, INFINITY, INFINITY, NAN, -INFINITY); | |
| SAME("%.3f|%.3f|%.3f", 1e-4, 9.9995, 0.0005); | |
| /* strings */ | |
| SAME("[%s|%s|%10s|%-10s|%.3s|%.0s|%.10s]", s, "", s, s, s, s, s); | |
| SAME("[%.*s|%*s|%-*s|%*.*s]", 2, s, -9, s, 9, s, 8, 3, s); | |
| SAME("[%s|%.5s|%.6s]", "Sav\xc3\xa9 \xf0\x9f\x98\x80", "Sav\xc3\xa9 \xf0\x9f\x98\x80", "Sav\xc3\xa9 \xf0\x9f\x98\x80"); | |
| SAME("[%.2s]", unterminated); /* a precision bounds the read: no NUL needed */ | |
| SAME("[%s|%.3s|%.6s|%10s]", (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL); | |
| /* characters, an embedded NUL and a high byte included */ | |
| SAME("[%c%c|%3c|%-3c|%c|%c]", 'o', 'k', 'x', 'y', 0, 255); | |
| /* pointers */ | |
| SAME("[%p|%p|%p]", (void *)0x1234, (void *)NULL, (void *)&local); | |
| SAME("[%20p|%-20p|%8p|%-8p]", (void *)s, (void *)s, (void *)NULL, (void *)NULL); | |
| SAME("[%p]", (void *)UINTPTR_MAX); | |
| /* %% and a mix */ | |
| SAME("100%%"); | |
| SAME("%s=%d (%.2f%%) %c %zu %#x %p end", "turn", -3, 99.5, 'Z', (size_t)4096, 48879u, (void *)0xff); | |
| SAME("no conversions at all"); | |
| SAME("%s", ""); | |
| int supported = total, supported_failed = failed; | |
| /* what bankml_log does not support: an explicit marker, never a guess */ | |
| MARKED("%<unsupported:e>", "%e", 2.0); | |
| MARKED("1 %<unsupported:g> %<skipped:d> %<skipped:s> % end", "%d %g %d %s %% end", 1, 2.0, 3, s); | |
| MARKED("%<unsupported:o>", "%o", 8u); | |
| MARKED("%<unsupported:a>|%<skipped:d>", "%a|%d", 1.0, 2); | |
| MARKED("%<unsupported:Lf>", "%Lf", (long double)1.5); | |
| MARKED("%<unsupported:ls>", "%ls", L"wide"); | |
| MARKED("%<unsupported:jd>", "%jd", (intmax_t)5); | |
| MARKED("%<unsupported:+s>|5", "%+s|%d", s, 5); /* a known type: its argument is read and dropped, the rest goes on */ | |
| MARKED("%<unsupported:05c>|6", "%05c|%d", 'q', 6); | |
| MARKED("%<unsupported:#p>|7", "%#p|%d", (void *)s, 7); | |
| MARKED("%<unsupported:#d>|8", "%#d|%d", 1, 8); | |
| MARKED("%<unsupported:.3c>|9", "%.3c|%d", 'q', 9); | |
| MARKED("%<unsupported:70000d>|10", "%70000d|%d", 1, 10); | |
| MARKED("%<unsupported:5%>|11", "%5%|%d", 11); | |
| MARKED("tail %<incomplete:>", "tail %"); | |
| int sentinel = 12345; | |
| MARKED("before %<unsupported:n> %<skipped:d>", "before %n %d", &sentinel, 1); | |
| total++; | |
| if (sentinel != 12345) { failed++; printf(" DIFFERS: %%n wrote through its argument\n"); } | |
| printf("printf oracle: %d of %d formats byte-identical to libc snprintf (ints at their limits, every length, %%f " | |
| "precision and rounding, inf/nan, strings, %%c with NUL, %%p, %%%%, width/precision/*); %d of %d unsupported " | |
| "cases written as their marker, no argument guessed, %%n never written\n", | |
| supported - supported_failed, supported, (total - supported) - (failed - supported_failed), total - supported); | |
| bankml_set_log(NULL, NULL); | |
| return failed == 0 ? 0 : 1; | |
| } | |