The first inexplicable thing happens during fgets(), which fails for no good reason. perror prints "EOF: Success". The loop quits early due to this mysterious failure, and when wrap_free() is called, the program dies with "*** Error in `./a.out': munmap_chunk(): invalid pointer: 0x0000000000c8f030 ***", where c8f030 was a valid pointer to wrap.
This does not happen at all when buf[] doesn't reside inside the structure. Everything is happy in that case. Clearly an overflow is happening, but I have no idea why or where.
I am not overflowing the bounds of the array. I checked that, and 100 bytes can't be overflowing 4K anyway.
I am definitely allocating enough memory. sizeof(wrap) is larger than 4096 bytes.
The values of wrap and wrap->fp are not being corrupted.
No mysterious properties of ungetc are crashing it. It still dies without it.
Splint 3.1.2 --- 20 Feb 2009
one.c: (in function wrap_open)
one.c:12:13: Arrow access from possibly null pointer wrap: wrap->fp
A possibly null pointer is dereferenced. Value is either the result of a
function which may return null (in which case, code should check it is not
null), or a global, parameter or structure field declared with the null
qualifier. (Use -nullderef to inhibit warning)
one.c:11:20: Storage wrap may become null
one.c:12:9: Dependent storage assigned to implicitly only:
wrap->fp = fopen(file, "r")
Dependent storage is transferred to a non-dependent reference. (Use
-dependenttrans to inhibit warning)
one.c:13:26: Possibly null storage wrap->fp passed as non-null param:
fgetc (wrap->fp)
A possibly null pointer is passed as a parameter corresponding to a formal
parameter with no /*@null@*/ annotation. If NULL may be used for this
parameter, add a /*@null@*/ annotation to the function parameter declaration.
(Use -nullpass to inhibit warning)
one.c:12:18: Storage wrap->fp may become null
one.c:14:9: Return value (type int) ignored: ungetc(wrap->typ...
Result returned by function call is not used. If this is intended, can cast
result to (void) to eliminate message. (Use -retvalint to inhibit warning)
one.c:15:15: Returned storage *wrap contains 1 undefined field: buf
Storage derivable from a parameter, return value or global is not defined.
Use /*@out@*/ to denote passed or returned storage which need not be defined.
(Use -compdef to inhibit warning)
one.c: (in function wrap_close)
one.c:20:25: Return value (type int) ignored: fclose(d->fp)
one.c:21:14: Only storage d->fp (type FILE *) derived from released storage is
not released (memory leak): d
A storage leak due to incomplete deallocation of a structure or deep pointer
is suspected. Unshared storage that is reachable from a reference that is
being deallocated has not yet been deallocated. Splint assumes when an object
is passed as an out only void pointer that the outer object will be
deallocated, but the inner objects will not. (Use -compdestroy to inhibit
warning)
one.c:21:14: Implicitly temp storage d passed as only param: free (d)
Temp storage (associated with a formal parameter) is transferred to a
non-temporary reference. The storage may be released or new aliases created.
(Use -temptrans to inhibit warning)
one.c: (in function main)
one.c:45:21: Operand of ! is non-boolean (int): !wrap_read(d)
The operand of a boolean operator is not a boolean. Use +ptrnegate to allow !
to be used on pointers. (Use -boolops to inhibit warning)
one.c:47:20: Return value (type int) ignored: wrap_close(d)
one.c:48:19: Fresh storage d not released before return
A memory leak has been detected. Storage allocated locally is not released
before the last reference to it is lost. (Use -mustfreefresh to inhibit
warning)
one.c:41:9: Fresh storage d created
one.c:10:7: Function exported but not used outside one: wrap_open
A declaration is exported, but not used outside this module. Declaration can
use static qualifier. (Use -exportlocal to inhibit warning)
one.c:16:1: Definition of wrap_open
one.c:18:5: Function exported but not used outside one: wrap_close
one.c:23:1: Definition of wrap_close
one.c:25:5: Function exported but not used outside one: wrap_read
one.c:33:1: Definition of wrap_read
Finished checking --- 14 code warnings
Same compile command on each? Any optimizations? Can you add code to print out the actual value of the pointer right after allocation and right before freeing it?
Or you can valgrind it.
And what exact version(s) of GCC, Linux, etc. are you using? Along with the two architectures.
I've tested and found that memset(d->buf, 100,0); instead of fgets does not crash. It's not the act of setting those 100 bytes that causes the crash, it may be related to the file pointer somehow.