/* Apparently, a buffered write operation after an ungetc() call puts a stream into a bad state, eventually resulting in a segfault. While this should result in undefined behavior according to ANSI/ISO C99, it is not in keeping with stated glibc policy. From the glibc manual: As you can see, `+' requests a stream that can do both input and output. The ISO standard says that when using such a stream, you must call `fflush' (*note Stream Buffering::) or a file positioning function such as `fseek' (*note File Positioning::) when switching from reading to writing or vice versa. Otherwise, internal buffers might not be emptied properly. The GNU C library does not have this limitation; you can do arbitrary reading and writing operations on a stream in whatever order. OUTPUT: /a.out dump: feof=0 ferror=0 ftell=0 initial hello world succeeded dump: feof=0 ferror=0 ftell=12 rewind succeeded dump: feof=0 ferror=0 ftell=0 fgetc succeeded dump: feof=0 ferror=0 ftell=1 ungetc succeeded dump: feof=0 ferror=0 ftell=0 ouch succeeded dump: feof=0 ferror=0 ftell=5 Segmentation fault */ #define _ISOC99_SOURCE #include #include #include #include #include static void dump(FILE *fp) { fprintf(stderr, " dump: feof=%d ferror=%d ftell=%ld\n", feof(fp), ferror(fp), (long) ftell(fp)); } int main(void) { FILE *fp; int r; if (!(fp = fopen("tungetc.test", "w+"))) { fprintf(stderr, "fopen failed!\n"); return EXIT_FAILURE; } dump(fp); r = fputs("hello world\n", fp); fprintf(stderr, "initial hello world %s\n", (r<0) ? "failed" : "succeeded"); dump(fp); rewind(fp); fprintf(stderr, "rewind %s\n", (ferror(fp)) ? "failed" : "succeeded"); dump(fp); r = fgetc(fp); fprintf(stderr, "fgetc %s\n", (ferror(fp)) ? "failed" : "succeeded"); dump(fp); r = ungetc(' ', fp); fprintf(stderr, "ungetc %s\n", (r<0) ? "failed" : "succeeded"); dump(fp); r = fputs("ouch\n", fp); fprintf(stderr, "ouch %s\n", (r<0) ? "failed" : "succeeded"); dump(fp); #if 1 rewind(fp); fprintf(stderr, "rewind %s\n", (ferror(fp)) ? "failed" : "succeeded"); dump(fp); #elif 1 r = fseek(fp, 0, SEEK_CUR); fprintf(stderr, "fseek %s\n", (r<0) ? "failed" : "succeeded"); dump(fp); #else fprintf(stderr, "fclose %s\n", (fclose(fp)) ? "failed" : "succeeded"); #endif return EXIT_SUCCESS; }