-1

My question is regarding this question: segmentation fault on c K&R fopen and fillbuf.

  1. In this question, in myfopen() function, there is a for loop; what I don't understand is that fp will have value starting from _iob but I don't get what values will fp->flag take after the first three values(which have been fixed). Will they take zero values and one more thing is there that in the answers(see beneath the code) they are saying that we have to use malloc to provide memory space to fp but fp has already been provided memory space because _iob array has space and fp will keep on taking addresses of elements of arrays so what is the need of malloc?Also if all the elements are zero then will the for loop always break at fp =_iob+3?
  2. Secondly in main() function, the mode mentioned is "r" but the system call being used afterwords is write() although it does not show error but why is this possible?
  3. Thirdly, the compiler does not show error or warning on compiling this code but shows a dialog box stating that "f_open.exe has stopped working" and this remains the same even if we write the malloc line(or without) or even if there is "r" mode or "w" mode. So what is wrong?

    #include<fcntl.h>
    #include<unistd.h>
    #include<stdlib.h>
    #define PERM 0644
    #define EOF (-1)
    #define BUFSIZE 1024
    #define OPEN_MAX 20
    
    typedef struct _iobuf{
        int cnt;
        char *ptr;
        char *base;
        int flag;
        int fd;
    } myFILE;
    
    enum _flags {
        _READ   = 01,
        _WRITE  = 02,
        _UNBUF  = 04,
        _EOF    = 010,
        _ERR    = 020
    };
    
    myFILE _iob[OPEN_MAX]={
        {0, (char *) 0, (char *) 0, _READ, 0 },
        {0, (char *) 0, (char *) 0, _WRITE, 1 },
        {0, (char *) 0, (char *) 0, _WRITE | _UNBUF, 2 }
    };
    
    #define stdin (&_iob[0])
    #define stdout (&_iob[1])
    #define stderr (&_iob[2])
    
    #define getc(p)     ( --(p)->cnt>=0 ? (unsigned char) *(p)->ptr++ : _fillbuf(p) )
    
    int _fillbuf(myFILE *fp)
    {
        int bufsize;
    
        if((fp->flag & (_READ|_EOF|_ERR))!=_READ)
            return EOF;
    
        bufsize=(fp->flag & _UNBUF)? 1 : BUFSIZE;
    
        if(fp->base==NULL)
            if((fp->base=(char *)malloc(bufsize))==NULL)
                return EOF;
    
        fp->ptr=fp->base; 
        fp->cnt=read(fp->fd, fp->ptr, bufsize);
    
        if(--fp->cnt<0){
            if(fp->cnt == -1)
                fp->flag |= _EOF;
            else
                fp->flag |= _ERR;
            return EOF;
        }
        return (unsigned char) *fp->ptr++;  
    }
    
    myFILE *myfopen(char *name, char *mode)
    {
        int fd;
        myFILE *fp;
    
        if(*mode!='r' && *mode!='w' && *mode!='a')
              return NULL;
        for(fp=_iob; fp<_iob+OPEN_MAX; fp++)
            if((fp->flag & (_READ | _WRITE))==0)
                break;
    
        if(fp>=_iob+OPEN_MAX)
            return NULL;
    
        if(*mode=='w')
             fd=creat(name, PERM);
        else if(*mode=='a'){
            if((fd=open(name, O_WRONLY, 0))==-1)
                fd=creat(name, PERM);   
            lseek(fd, 0L, 2);
        } else
            fd=open(name, O_RDONLY, 0);
    
        if(fd==-1)
            return NULL;
    
        fp->fd = fd;
        fp->cnt = 0;
        fp->base = NULL;
        fp->flag = (*mode=='r')? _READ : _WRITE;
    
            return fp;    
        } 
    
    int main(int argc, char *argv[])
    {
        myFILE *fp;
       int c;
    
        if((fp=myfopen(argv[1], "r"))!=NULL)
            write(1, "opened\n", sizeof("opened\n"));
    
         while((c=getc(fp))!=EOF)
              write(1, &c, sizeof(c));
    
        return 0;
    }
    

Solution provided was:

myFILE *fp;

if(*mode!='r' && *mode!='w' && *mode!='a')
      return NULL;
for(fp=_iob; fp<_iob+OPEN_MAX; fp++)
    if((fp->flag & (_READ | _WRITE))==0) // marked line
        break;

When you reach the marked line, you try to dereference the fp pointer. Since it is (likely, but not certainly) initialized to zero (but I should say NULL), you are dereferencing a null pointer. Boom. Segfault.

Here's what you need to change.

myFILE *fp = (myFILE *)malloc(sizeof(myFILE));

Be sure to #include to use malloc.

Also your close function should later free() your myFILE to prevent memory leaks.

As you can see the above is the answer given for the linked question: segmentation fault on c K&R fopen and fillbuf

RSSB
  • 144
  • 2
  • 4
  • 14
  • 4
    *** need code *** – nicomp Jun 01 '18 at 17:21
  • The code is exactly the same as written in the linked question – RSSB Jun 01 '18 at 17:33
  • 3
    And when that question is deleted, what then? Always post the code you are asking about, it makes your question self-contained and more useful in the future. – jwdonahue Jun 01 '18 at 17:39
  • 2
    Welcome to Stack Overflow. Please read the [**About**](http://stackoverflow.com/tour) page soon and also visit the links describing [**How to Ask a Question**](http://stackoverflow.com/questions/how-to-ask) and [**How to create a Minimal, Complete, and Verifiable example**](http://stackoverflow.com/help/mcve). Providing the necessary details, including your code, and associated errors, if any, will allow everyone here to help you with your question. – David C. Rankin Jun 01 '18 at 17:42
  • @jwdonahue Thanks sir! I have edited my question and have added the code. – RSSB Jun 01 '18 at 17:54
  • 1
    The remaining rows of the `_iob` array are initialized to all bytes zero. The `write` system calls are not using the `FILE *`; the `getc()` call does. – Jonathan Leffler Jun 01 '18 at 17:59
  • @jonathan-leffler Then what is the need for malloc? – RSSB Jun 01 '18 at 18:01
  • 1
    The code in '[t]he solution provided was' is spouting nonsense. The loop does a marginally unorthodox traversal of the `_iob` array, and the pointers to the elements of the array are definitively not null pointers. The memory allocation proposed is not needed for the reasons given. – Jonathan Leffler Jun 01 '18 at 18:09
  • @Jonathan Leffler Thanks! I understood the write() part as here write function is being used to write to stdout with file descripter 1. But getc() is a macro here and the malloc was suggested by an answer to some question having the same code as this.You can see in the link given. – RSSB Jun 01 '18 at 18:09
  • I'm looking at the other question — and I'm disagreeing with its solution. I'd be relatively surprised if the trouble was not that no file name argument was provided when the program was called. It doesn't check that there is a non-null `argv[1]` before passing it to `myfopen()`. The question says "get segmentation error when I compile" which is bogus; if the compiler's crashing, you don't get a program to run, – Jonathan Leffler Jun 01 '18 at 18:20
  • @jonathan Leffler Maybe this is the reason that I am getting no error or warning rather a dialog box saying "f_open.exe is not working". I did not know that it is called compiler crashing as I am quite new to programming – RSSB Jun 01 '18 at 18:25
  • 1
    There is no cause for the compiler to give a warning. It is not called "compiler crashing" by anyone with experience, not least because it is not the compiler that crashes but rather the program written by the user and compiled by the compiler that crashes. The program will crash if you don't pass it a file name to copy from, or if the file specified cannot be opened. The code in `main()` does not properly check for either of these errors. IMO, the program was probably being invoked incorrectly. I don't have my copy of K&R (1st or 2nd) at the office, so I can't check what they wrote. – Jonathan Leffler Jun 01 '18 at 18:39
  • 2
    What you have is not called "compiler crashing". Jonathan (I typed this before his last comment) was saying that *if* the compiler is crashing, there won't be a (new) executable to run. Compilers rarely crash. Occasionally a bug or weakness in the compiler is discovered, but it is very rare. So it is not the compiler crashing, but the code. The compiler is invoked by the IDE you are using. The IDE then runs the code, but it is also unlikely that the IDE is crashing. Put the money on your own code as the culprit. – Weather Vane Jun 01 '18 at 18:46

1 Answers1

2

Diagnosis in other question is bogus

As noted in the comments, the diagnosis in the other question is bogus. In particular, the loop in myfopen() that reads:

for (fp =_iob; fp <_iob + OPEN_MAX; fp++)
    if ((fp->flag & (_READ | _WRITE)) == 0)
        break;

is perfectly correct. It iterates over the elements of the array _iob, and never encounters a null pointer as claimed. The buffer _iob is initialized for the first three elements; the remainder are all zeros.

Probable causes of trouble

The most likely causes of this program crashing are either:

  1. No argument is provided for the name of the file.
  2. The name provided cannot be opened for reading.

The code shown for main() is:

int main(int argc, char *argv[])
{
    myFILE *fp;
   int c;

    if((fp=myfopen(argv[1], "r"))!=NULL)
        write(1, "opened\n", sizeof("opened\n"));

     while((c=getc(fp))!=EOF)
          write(1, &c, sizeof(c));

    return 0;
}

The code does not check for either of these common problems. It should be more like:

int main(int argc, char *argv[])
{
    myFILE *fp;
    int c;

    if (argc != 2)
    {
        static const char usage[] = "Usage: mystdio filename\n";
        write(2, usage, sizeof(usage)-1);
        return 1;
    }

    if ((fp = myfopen(argv[1], "r")) == NULL)
    {
        static const char filenotopened[] = "mystdio: failed to open file ";
        write(2, filenotopened, sizeof(filenotopened)-1);
        write(2, argv[1], strlen(argv[1]));
        write(2, "\n", 1);
        return 1;
    }

    write(1, "opened\n", sizeof("opened\n"));

    while ((c = getc(fp)) != EOF)
        write(1, &c, sizeof(c));

    return 0;
}

You have to add #include <string.h> because this uses strlen(). The error reporting via file descriptor I/O is clumsy, but this code precludes the use of the regular functions from <stdio.h>. The program does include <stdlib.h> so it would be possible to write exit(EXIT_FAILURE); instead of return 1;, but the net result is the same when the current function is main() — though not in functions called (directly or indirectly) from main().

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278