DF-4848 / ffmat.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | /* * ffmat.c — adversarial harness for the REAL sys/dev/sound/pcm/feeder_matrix.c * (GLM 5.3 pass-2, FXROUND follow-up; DF-4847). * * T1 entry-rounding overshoot (:479): counts inside the claimed-exact * domain where SND_FXROUND(count, oalign) > count => pass sized past the * window; source writes past the window and/or return > count. * T2 ialign>oalign (:501): FXROUND(count - oalign, ialign) misrounds => * j > count - oalign (+ up to ialign-1) => src = dst + count - j < dst * (write BEFORE the window) and source window j exceeds the destination. * T3 ialign<oalign (:504): (FXDIV(count, oalign) - 1) * ialign is exact * unless FXDIV itself misrounds (counts > domain top) — covered by soak. */ #include "fxshim.h" #include "feeder_matrix.c" static struct pcm_feeder f; static int mat_setup(uint32_t in, uint32_t out) { memset(&f, 0, sizeof(f)); f.desc = &f.desc_static; f.desc->in = in; f.desc->out = out; if (feed_matrix_init(&f) != 0) return (-1); return (0); } int fx_feeder_set(struct pcm_feeder *fe, int what, int value) { (void)fe; (void)what; (void)value; return (0); } static uint64_t fails, checks; #define RESET_AUDIT(win, sz) do { \ fx_audit_max_off = 0; fx_audit_max_ask = 0; fx_audit_given = 0; \ fx_audit_asks = 0; fx_audit_wild = 0; \ fx_win_base = (uintptr_t)(win); \ fx_win_limit = (uintptr_t)(win) + (sz); \ fx_arena_base = fx_win_base - FX_GUARD_FRONT; \ fx_arena_limit = fx_win_base + (sz) + 65536; \ } while (0) static void report(const char *tag, uint32_t count, uint32_t ret, const char *where, uint64_t maxoff, uint64_t maxask, uint32_t inch, uint32_t outch) { printf("FAIL[%s] in_ch=%u out_ch=%u count=%u ret=%u %s " "maxwrite_off=%llu maxask=%llu\n", tag, inch, outch, count, ret, where ? where : "-", (unsigned long long)maxoff, (unsigned long long)maxask); fails++; } static const uint32_t bad_aligns[] = { 3, 5, 6, 7, 10, 12, 14, 15, 20, 21, 24, 28, 30 }; int main(void) { struct feed_matrix_info *info; uint32_t inch, outch, count, ret, d, found, ai; uint8_t *win; const char *where; uint32_t prng = 0x85ebca6bu; int t; /* S16 throughout (matrix keeps bps): ialign=2*inch, oalign=2*outch */ static const struct { uint32_t i, o; const char *tag; } combos[] = { { 6, 2, "T1 downmix oalign=4? no:4 pow2 -> safe" }, { 2, 6, "T2 upmix ialign=4<oalign=12" }, { 7, 5, "T2b ialign=14>oalign=10" }, { 5, 7, "T1b ialign=10<oalign=14" }, { 6, 5, "T2c ialign=12>oalign=10" }, { 5, 6, "T1c ialign=10<oalign=12" }, { 8, 7, "T2d ialign=16>oalign=14" }, { 7, 8, "T1d ialign=14<oalign=16(pw2)" }, { 3, 6, "T1e ialign=6<oalign=12" }, { 6, 3, "T2e ialign=12>oalign=6" }, }; for (t = 0; t < (int)(sizeof(combos) / sizeof(combos[0])); t++) { inch = combos[t].i; outch = combos[t].o; uint32_t in = SND_FORMAT(AFMT_S16_LE, inch, 0); uint32_t out = SND_FORMAT(AFMT_S16_LE, outch, 0); if (mat_setup(in, out) != 0) { printf("setup failed in=%08x out=%08x\n", in, out); continue; } info = f.data; for (ai = 0; ai < sizeof(bad_aligns) / sizeof(bad_aligns[0]); ai++) { d = bad_aligns[ai]; if (d != info->oalign && d != info->ialign) continue; found = 0; for (count = 1; count <= 65536 && found < 300; count++) { if (SND_FXROUND(count, d) <= count) continue; found++; fx_src_ready = 1 << 20; fx_src_give = 0; win = fx_win_alloc(count); RESET_AUDIT(win, count); ret = feed_matrix_feed(&f, NULL, win, count, NULL); where = NULL; checks++; if (fx_win_check(win, count, &where) != 0) report(combos[t].tag, count, ret, where, fx_audit_max_off, fx_audit_max_ask, inch, outch); else if (ret > count) report(combos[t].tag, count, ret, "return > count (sndbuf_acquire ring overflow)", fx_audit_max_off, fx_audit_max_ask, inch, outch); else if (fx_audit_max_off > count) report(combos[t].tag, count, ret, "source wrote past window", fx_audit_max_off, fx_audit_max_ask, inch, outch); fx_win_free(win); } } feed_matrix_free(&f); } /* random soak across channel combos and partial sources */ for (t = 0; t < 30000; t++) { prng ^= prng << 13; prng ^= prng >> 17; prng ^= prng << 5; inch = 1 + (prng % 8); prng ^= prng << 13; prng ^= prng >> 17; prng ^= prng << 5; outch = 1 + (prng % 8); if (inch == outch) continue; uint32_t in = SND_FORMAT(AFMT_S16_LE, inch, 0); uint32_t out = SND_FORMAT(AFMT_S16_LE, outch, 0); if (mat_setup(in, out) != 0) continue; prng ^= prng << 13; prng ^= prng >> 17; prng ^= prng << 5; count = 4096 + (prng % 61441); prng ^= prng << 13; prng ^= prng >> 17; prng ^= prng << 5; fx_src_ready = (prng % 3 == 0) ? (prng % count) : (1 << 20); fx_src_give = 0; win = fx_win_alloc(count); RESET_AUDIT(win, count); ret = feed_matrix_feed(&f, NULL, win, count, NULL); where = NULL; checks++; if (fx_win_check(win, count, &where) != 0) report("soak", count, ret, where, fx_audit_max_off, fx_audit_max_ask, inch, outch); else if (ret > count) report("soak", count, ret, "return > count", fx_audit_max_off, fx_audit_max_ask, inch, outch); fx_win_free(win); feed_matrix_free(&f); } printf("ffmat: checks=%llu failures=%llu -> %s\n", (unsigned long long)checks, (unsigned long long)fails, fails ? "FAIL" : "ALL PASS"); return (fails != 0); } |