Search code examples
coperating-systemglibcstdio

How to detect which piece of my code is generating "Fatal error: glibc detected an invalid stdio handle" error?


I'm trying to code a simple program to copy a file into another using 2 processes. I want to use shared memory to open both files and get a piece of shared memory of 1Byte to be used as exchange memory in a mutually exclusive way.

So the main process should open both files and put them in shared memories; fork twice, I obtain 2 processes A and B. Process A should read 1 byte of the first file, put it in the shared exchange memory and unlock the mutex for process B. Process B should copy the file from the shared exchange memory and put it in its file and unlock the mutex for process A. And so on.

#define SIZE 4096

void reader_process(FILE* fptr,char*exch, sem_t*mut){
    while(1){
        sem_wait(mut);
        *exch = (char) getc(fptr);
        sem_post(mut+1);
    }
}

void writer_process(FILE* fptr,char*exch, sem_t*mut){
    if(*exch == EOF){
        printf("done\n");
        exit(0);
    }

    while(1){
        sem_wait(mut);
        putc((int)*exch,fptr);
        sem_post(mut-1);
    }
}

int main(int argc, char *argv[]){
    FILE* shared_f_ptr[2];
    pid_t pid;
    //2 files name.
    char *files[2];
    int fd[2];

    //open files.
    files[0] = argv[1];
    printf("%s\n",files[0]);
    FILE* fpointer1 = fopen(files[0],"r+");
    if (fpointer1 == NULL){
        perror("fopen\n");
        exit(-1);
    }
    fd[0] = fileno(fpointer1);

    files[1] = argv[2];
    printf("%s\n",files[1]);
    FILE* fpointer2 = fopen(files[1],"r+");
    if (fpointer2 == NULL){
        perror("fopen\n");
        exit(-1);
    }
    fd[1] = fileno(fpointer2);

    //shared File pointers.
    shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
       fd[0], 0);
    if (shared_f_ptr[0] == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }

    shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
       fd[1], 0); 
    if (shared_f_ptr[1] == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }
    //shared mem for 1B exchange.
    char *shared_exchange = (char*)mmap(NULL, sizeof(char),
    PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
     -1, 0);
    if (shared_exchange == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }

    //mutex.
    sem_t *mut = (sem_t*)mmap(NULL, 2*sizeof(sem_t),
        PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
        -1, 0);
    sem_init(&mut[0],1,0);
    sem_init(&mut[1],1,0);



    //fork.

    pid = fork();
    if (pid == 0) {
        reader_process(shared_f_ptr[0],
        shared_exchange, &mut[0]);
    }
    if (pid == -1){
        perror("fork\n");
        exit(-1);
    }

    else pid = fork();

    if (pid == 0) writer_process(shared_f_ptr[1],
        shared_exchange, &mut[1]);

    if (pid == -1){
        perror("fork\n");
        exit(-1);
    }

    else{
        sem_post(&mut[0]);
    }
}

I don't expect the error i am getting Fatal error: glibc detected an invalid stdio handle but i don't really know how to find what's causing the problem.


Solution

  • Don't do this:

    //shared File pointers.
    shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
       fd[0], 0);
    if (shared_f_ptr[0] == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }
    
    shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
       fd[1], 0); 
    if (shared_f_ptr[1] == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }
    

    Use this instead:

    shared_f_ptr[0] = fpointer1;
    shared_f_ptr[1] = fpointer2;
    

    Don't use the file descriptors underlying each FILE. Instead, simply use the FILE itself.

    Also, instead of using fpointer1 and fpointer2, just use shared_f_ptr[0] and shared_f_ptr[1].

    This is a possible definition of the FILE structure:

    typedef struct _IO_FILE
    {
        int __fd;
        int __flags;
        int __unget;
        char *__buffer;
        struct {
            size_t __orig;
            size_t __size;
            size_t __written;
        } __bufsiz;
        fpos_t __fpos;
    } FILE;
    

    As you can see, it's a structure, not just a flat pointer.