/* DF-3053 hammer version - nfsm_mbuftouio ignores copyout fault.
 * A: read(fd, region, 4096); B: flips mprotect NONE<->RW continuously.
 * BUG hit = read returns 4096 while region still 0x5A (fault swallowed).
 * userland accesses to the region are guarded with sigsetjmp/SIGSEGV.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/mman.h>
static char *region; static volatile int stop=0, in_guard=0;
static sigjmp_buf jb;
static long bug_hits=0, ok_reads=0, fault_reads=0, total=0, guard_faults=0;
static void segv(int sig){ (void)sig; if(in_guard){ in_guard=0; siglongjmp(jb,1);} _exit(99); }
static void *flipper(void*a){
    while(!stop){ mprotect(region,8192,PROT_NONE); mprotect(region,8192,PROT_READ|PROT_WRITE); }
    return NULL;
}
#define GUARDED(stmt) do{ if(sigsetjmp(jb,1)==0){ in_guard=1; stmt; in_guard=0; } else { guard_faults++; mprotect(region,8192,PROT_READ|PROT_WRITE); } } while(0)
int main(int argc,char**argv){
    pthread_t t; int iters=argc>2?atoi(argv[2]):20000;
    struct sigaction sa; memset(&sa,0,sizeof sa); sa.sa_handler=segv; sigaction(SIGSEGV,&sa,NULL);
    if(argc<2){fprintf(stderr,"usage: df3053b file [iters]\n");return 2;}
    int fd=open(argv[1],O_RDONLY);
    if(fd<0){perror("open");return 1;}
    region=mmap(NULL,8192,PROT_READ|PROT_WRITE,MAP_ANON|MAP_PRIVATE,-1,0);
    if(region==MAP_FAILED){perror("mmap");return 1;}
    pthread_create(&t,NULL,flipper,NULL);
    for(int i=0;i<iters;i++){
        GUARDED({ mprotect(region,8192,PROT_READ|PROT_WRITE); memset(region,0x5A,4096); });
        errno=0;
        ssize_t r=read(fd,region,4096);
        total++;
        int stale=1;
        GUARDED({ mprotect(region,8192,PROT_READ|PROT_WRITE);
                  for(int q=0;q<4096;q++) if(region[q]!=(char)0x5A){stale=0;break;} });
        if(r==4096 && stale) bug_hits++;
        else if(r==4096) ok_reads++;
        else fault_reads++;
    }
    stop=1; pthread_join(t,NULL);
    printf("total=%ld bug_full_success_stale=%ld delivered_ok=%ld fault_reported=%ld guard_faults=%ld\n",
           total,bug_hits,ok_reads,fault_reads,guard_faults);
    return 0;
}
