I’ve found what I consider to be a stream IO bug. The
code below can be compiled with g++ to easily illustrate the problem. Here’s
what’s happening:
- Open a file for writing (using
fopen(…, “w”) ) and write some data to the file
- Flush the writer using fflush()
- Open a second stream to the
file for reading only using fopen(…., “r”)
- Read some bytes using fseek()
& fread() to confirm the reader can see the data written in step 1
- Have the writer update 1 byte
using fwrite()
- Flush the writer using fflush()
- Using the read stream, read the
byte written by the writer in step 5 using fseek() / fread()
- You will get the wrong answer
here. The read should return the byte written in step 5 but instead
returns the old value written in step 1.
Is this is a bug in Darwin?
Are there any work arounds?
Here’s my test case code. BTW, it passes on
Solaris.
Norm Green
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
int main(int argc, char *argv[]) {
const char *fileName = "/tmp/testfile";
FILE *writer = fopen(fileName, "w");
if (writer == NULL) {
perror("Failed opening
the writer");
exit(1);
}
const char *myString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n";
int length = strlen(myString);
// write the string to the file 20
times
for (int i = 0; i < 20; i++) {
fwrite(myString, 1, length, writer);
if (ferror(writer)) {
perror("Failed when
calling fwrite()");
exit(1);
}
}
// flush the writer
if (fflush(writer) != 0) {
perror("fflush()
failed on the writer");
exit(1);
}
// open a read stream on the same
file
FILE *reader = fopen(fileName, "r");
if (reader == NULL) {
perror("Failed opening
the reader");
exit(1);
}
// position the reader to 2nd char of
10th line
if (fseek(reader, 630, SEEK_SET)) {
perror("Failed seeking
the reader");
exit(1);
}
char dest[80];
memset(dest, 0, sizeof(dest));
// read the first 2 bytes of the
line, which should be "ab"
int res = fread(dest, 1, 2, reader);
if (res != 2) {
perror("Failed when
calling fread() on the reader");
exit(1);
}
if (dest[0] != 'a' || dest[1] != 'b') {
printf("Unexpected
results from read. Expected 'ab', found '%s'\n", dest);
exit(1);
}
// Now have the writer update 1 byte
at position 631
if (fseek(writer, 631, SEEK_SET)) {
perror("Failed seeking
the writer");
exit(1);
}
// change 'b' to 'B'
if (fwrite("B", 1, 1, writer) != 1) {
perror("Failed writing
1 byte");
exit(1);
}
// flush the writer
if (fflush(writer) != 0) {
perror("fflush()
failed on the writer");
exit(1);
}
// Now read it back using the reader
if (fseek(reader, 631, SEEK_SET)) {
perror("Failed seeking
the reader");
exit(1);
}
memset(dest, 0, sizeof(dest));
res = fread(dest, 1, 1, reader);
if (res != 1) {
printf("Failed when
calling fread() on the reader. Expected 1, found %d", res);
exit(1);
}
if (dest[0] != 'B') {
// where did the 'B' go that was
written?
printf("Wrong answer
found by reader. Expected 'B', found '%s'\n", dest);
exit(1);
}
printf("Test
passed\n");
exit(0);