/* Verify the C promotion semantics that defeat DF-0903's claimed chain.
 * `uio->uio_resid` is `size_t` (unsigned, sys/sys/_uio.h:69).
 * `xfersize` is `int` (signed, ufs_readwrite.c:220).
 * Line 294: `if (uio->uio_resid < xfersize)` -- the int is promoted to size_t,
 * turning negative xfersize into a huge value, so the comparison is TRUE and
 * line 295 clamps xfersize to uio_resid (a small positive). The negative
 * xfersize NEVER reaches line 356's uiomove.
 */
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

int main(void){
    int fs_bsize = 8192;
    int blkoffset = 10000;             /* from crafted fs_qbmask */
    int xfersize = fs_bsize - blkoffset; /* -1808 */
    size_t uio_resid = 16;             /* from pwrite(fd,buf,16,10000) */

    printf("xfersize (int)     = %d\n", xfersize);
    printf("(size_t)xfersize   = 0x%016zx (%zu)\n",
           (size_t)xfersize, (size_t)xfersize);
    printf("uio_resid          = %zu\n", uio_resid);
    /* The kernel comparison: */
    if (uio_resid < xfersize) {        /* size_t < int -> int promoted to size_t */
        printf("LINE 294: uio_resid < xfersize is TRUE (size_t promotion)\n");
        printf("LINE 295: xfersize = uio_resid = %zu\n", uio_resid);
        xfersize = (int)uio_resid;     /* clamped to 16 */
    }
    printf("xfersize after clamp = %d (POSITIVE -- OOB path defeated)\n", xfersize);
    /* balloc size check: */
    int balloc_size = blkoffset + xfersize; /* 10000 + 16 = 10016 */
    printf("balloc: blkoffset + xfersize = %d + %d = %d > fs_bsize=%d => PANIC 'blk too big'\n",
           blkoffset, xfersize, balloc_size, fs_bsize);
    return 0;
}
