In the attached example, calling fgetc followed by ungetc to snoop a character from the input stream and then put it back corrupts the return value of a subsequent fread call. Specifically, the return value of fread is a large, apparently random number after requesting one item of one byte. As the example demonstrates, the problem does not happen unless you call fgetc/ungetc first.
For ease of reading, I'm including the reproducer inline below in addition to the attachment.
$ cc/vers HP C V7.3-020 on OpenVMS IA64 V8.4 $ type ungetc_bug.c #include <unistd.h> #include <stdio.h> #include <stdlib.h> is(int ok, char *test, int got, int expected) { static int test_count = 0; test_count++; printf("%sok %d - %s\n", ok ? "" : "NOT ", test_count, test); if (!ok) printf(" got: %d\nexpected: %d\n", got, expected); } main() { static const char test_file[] = "ungetc_bug.tmp"; int char_borrowed, char_returned, test_count = 0; size_t num_items; FILE *f; char c; if ((f = fopen(test_file, "w")) == NULL) { perror("fopen() for write error"); exit(44); } num_items = fwrite("abcdefg\n", sizeof("abcdefg\n"), 1, f); if (num_items == (size_t)EOF) perror("fwrite() error"); fclose(f); /* Now open it again for read. */ if ((f = fopen(test_file, "r")) == NULL) { perror("fopen() for read error"); exit(44); } /* Read one byte and verify that's all we got */ num_items = fread(&c, 1, 1, f); if (num_items == (size_t)EOF) { perror("fread() error"); exit(44); } is(num_items == 1, "Before fgetc/ungetc, asked fread for one item of one byte", (int)num_items, 1); /* Pop off a character from the stream... */ char_borrowed = fgetc(f); if (char_borrowed == EOF) perror("fgetc() error"); /* ... and push it back on. */ char_returned = ungetc(char_borrowed, f); if (char_returned == EOF) perror("ungetc() error"); is(char_returned == char_borrowed, "ungetc returns same character as fgetc", char_returned, char_borrowed); /* Now ask for another byte and see how many we get. */ num_items = fread(&c, 1, 1, f); if (num_items == (size_t)EOF) perror("fread() error"); is(num_items == 1, "After fgetc/ungetc, asked fread for one item of one byte", (int)num_items, 1); is(char_borrowed == (int)c, "fread gets the same character we snooped and put back", (int)c, char_borrowed); fclose(f); unlink(test_file); } $ cc ungetc_bug $ link ungetc_bug $ run ungetc_bug ok 1 - Before fgetc/ungetc, asked fread for one item of one byte ok 2 - ungetc returns same character as fgetc NOT ok 3 - After fgetc/ungetc, asked fread for one item of one byte got: 412737 expected: 1 ok 4 - fread gets the same character we snooped and put back $
Hi,
Thanks for reporting the issue. We are able to reproduce the problem using the given
C program when compiled with default optimization level. But the problem is not seen
when compiled with /NOOPT qualifier.
Currently we are trying to add traces to the portion of CRTL code where we are
suspecting the problem and analyze.
We will keep you updated with the progress.
Thanks,
Murali
I can reproduce the problem when compiling the example with /NOOPT. Or did you mean running against a version of the CRTL compiled with /NOOPT?
On Oct 31, 2013, at 7:06 AM, Chippagiri Murali Krishna chippagiri@users.sf.net wrote:
Craig A. Berry
mailto:craigberry@mac.com
"... getting out of a sonnet is much more
difficult than getting in."
Brad Leithauser
Related
Tickets: #72
Hi Craig,
You are right, the problem is seen even with /NOOPT compiler qualifier. Actually we
observed that the fread is returning correct value while debugging which is compiled
with noopt; now we have observed this also not consistent i.e. return value varies
system to system in debug mode. Probably some buffer corruption/override issue which
is leading to this issue. Sorry for misleading you and Thanks for the information.
We will look into it.
Thanks,
Murali
Analysis:
CRTL fread() function has to read the characters from the file stream. If ungetc() is used
before fread() to push the character in to the input stream, then first fread() would read
the character pushed by the ungetc() call, followed by the main buffer.
OpenVMS CRTL maintains some local members to calculate and return the number of items read
using fread() call; there are some instances where these local members would have some
garbage values which leads fread() to return wrong values.
We have modified the CRTL code to fix the reported problem; currently performing the
testing.
Thanks,
Murali
It looks like this one was fixed in VMS84I_ACRTL-V0300 so I think this ticket can be closed.