diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-11-27 21:20:27 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-11-27 21:20:27 +0100 |
commit | 6d424674113a6a6dd2566d82ba15f20d2d3090e7 (patch) | |
tree | acf91e8ff2f356e587261333122aa12ce22c6b84 /sys/src/libstdio/_IO_putc.c | |
parent | 0edcb33ca1f01f8e3c18f5ad99442da8aad2091f (diff) |
stdio: fix sclose() buffer overrun when terminating string, realloc() error handling (thanks porlock)
theres a bug is in sclose() where it doesnt check if wp is beyond
the buffer. also wp was not updated after realloc().
bug was reported by porlock on 9fans:
Plan 9's implementation of the standard C functions snprintf and
vsnprintf have a buffer overrun bug.
If the buffer length equals the output length (without the terminating
null), then one too many characters is written to the buffer.
For example,
snprintf(buf, 4, "ABCD");
will write 5 characters to buf.
Diffstat (limited to 'sys/src/libstdio/_IO_putc.c')
-rw-r--r-- | sys/src/libstdio/_IO_putc.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/sys/src/libstdio/_IO_putc.c b/sys/src/libstdio/_IO_putc.c index 4c3a74238..6509963e6 100644 --- a/sys/src/libstdio/_IO_putc.c +++ b/sys/src/libstdio/_IO_putc.c @@ -18,7 +18,8 @@ int _IO_putc(int c, FILE *f){ case CLOSED: return EOF; case OPEN: - _IO_setvbuf(f); + if(_IO_setvbuf(f)!=0) + return EOF; /* fall through */ case RDWR: case END: @@ -38,18 +39,20 @@ int _IO_putc(int c, FILE *f){ if(f->flags&STRING){ f->rp=f->buf+f->bufl; if(f->wp==f->rp){ - if(f->flags&BALLOC) - f->buf=realloc(f->buf, f->bufl+BUFSIZ); - else{ + if(f->flags&BALLOC){ + char *t = realloc(f->buf, f->bufl+BUFSIZ); + if(t==NULL){ + f->state=ERR; + return EOF; + } + f->buf=t; + f->wp=t+f->bufl; + f->bufl+=BUFSIZ; + f->rp=t+f->bufl; + }else{ f->state=ERR; return EOF; } - if(f->buf==NULL){ - f->state=ERR; - return EOF; - } - f->rp=f->buf+f->bufl; - f->bufl+=BUFSIZ; } *f->wp++=c; } |