My question is regarding this question: segmentation fault on c K&R fopen and fillbuf.
- 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?
- 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?
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