box
box

Reputation: 3246

why stdout can't be substituted?

for educational purposes, i'm trying to substitute the standard streams stdout, stdin, and stderr. i first looked up the data type of the streams, which i traced back to the struct _IO_FILE with the following members (gdb ptype _IO_FILE):

type = struct _IO_FILE {
    int _flags;
    char *_IO_read_ptr;
    char *_IO_read_end;
    char *_IO_read_base;
    char *_IO_write_base;
    char *_IO_write_ptr;
    char *_IO_write_end;
    char *_IO_buf_base;
    char *_IO_buf_end;
    char *_IO_save_base;
    char *_IO_backup_base;
    char *_IO_save_end;
    struct _IO_marker *_markers;
    struct _IO_FILE *_chain;
    int _fileno;
    int _flags2;
    __off_t _old_offset;
    short unsigned int _cur_column;
    signed char _vtable_offset;
    char _shortbuf[1];
    _IO_lock_t *_lock;
    __off64_t _offset;
    void *__pad1;
    void *__pad2;
    void *__pad3;
    void *__pad4;
    size_t __pad5;
    int _mode;
    char _unused2[20];
}

then i tried to duplicate the memory content of the stdout pointer:

_IO_FILE f1 = {._flags = -72540028, ._offset = -1, ._old_offset = -1, ._fileno = 1, ._chain = stdin, ._lock = stdout->_lock, .__pad2 = stdout->__pad2 };
_IO_FILE *f2 = stdout;
_IO_FILE *f3 = malloc(sizeof(_IO_FILE));
memcpy(f3, stdout, sizeof(_IO_FILE));

fprintf(&f1, "f1\n"); // doesn't work 
fprintf(f2, "f2\n"); // works
fprintf(f3, "f3\n"); // doesn't work

however, only the pointer assignment doesn't crash. i compared the memory content via gdb and all share the same struct member content.

although this question is likely platform-dependent: do fprintf and the other library functions just compare the pointer to the standard streams?

edit: i suspected, that this is an implementation or platform dependent issue and since all opinions suggest, that it is, i accepted the answer which suggests one possible cause of the problem.

edit2: to narrow down the scope of the problem: i am using a 64 bit ubuntu with version 12.04 and an EGLIBC version of 2.15.

Upvotes: 3

Views: 260

Answers (1)

Eric Postpischil
Eric Postpischil

Reputation: 224310

Per a comment from Corvus, on a Linus system, a lock is associated with the stream, so copying the FILE data structure interferes with lock semantics.

(I suggest this answer not be accepted immediately, to give Corvus time to enter an answer.)


Old hypothesis:

I suspect, in your C implementation, the location of a FILE object is used as part of its meaning. E.g., there may be an array of them, and a pointer to the first element of the array is subtracted from the pointer to a FILE object to find its index in the array. Then this index is used as the file number in system calls such as write.

When you allocate new space, it is not in this array, and the pointer arithmetic gives the wrong result.

Upvotes: 1

Related Questions