Permalink
Browse files

Made some changes to the I/O stream library for memory streams.

There were a number of potential problems due to the possibility
of integer overflow.
Changed some integral types to the larger types size_t or ssize_t.
For example, the function mem_resize now takes the buffer size parameter
as a size_t.
Added a new function jas_stream_memopen2, which takes a
buffer size specified as a size_t instead of an int.
This can be used in jas_image_cmpt_create to avoid potential
overflow problems.

Added a new function jas_deprecated to warn about reliance on
deprecated library behavior.
  • Loading branch information...
mdadams committed Nov 6, 2016
1 parent e8f491b commit 634ce8e8a5accc0fa05dd2c20d42b4749d4b2735
@@ -135,3 +135,22 @@ int jas_memdump(FILE *out, void *data, size_t len)
}
return 0;
}
/******************************************************************************\
* Code.
\******************************************************************************/
void jas_deprecated(const char *s)
{
static char message[] =
"WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!\n"
"WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!\n"
"WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!\n"
"YOUR CODE IS RELYING ON DEPRECATED FUNCTIONALTIY IN THE JASPER LIBRARY.\n"
"THIS FUNCTIONALITY WILL BE REMOVED IN THE NEAR FUTURE.\n"
"PLEASE FIX THIS PROBLEM BEFORE YOUR CODE STOPS WORKING!\n"
;
jas_eprintf("%s", message);
jas_eprintf("The specific problem is as follows:\n%s\n", s);
//abort();
}
@@ -347,7 +347,7 @@ static jas_image_cmpt_t *jas_image_cmpt_create(int_fast32_t tlx,
!jas_safe_size_mul(size, cmpt->cps_, &size)) {
goto error;
}
cmpt->stream_ = (inmem) ? jas_stream_memopen(0, size) :
cmpt->stream_ = (inmem) ? jas_stream_memopen2(0, size) :
jas_stream_tmpfile();
if (!cmpt->stream_) {
goto error;
@@ -169,6 +169,10 @@ static jas_stream_t *jas_stream_create()
return stream;
}
#if 0
/* Obsolete code. */
jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
{
jas_stream_t *stream;
@@ -238,6 +242,136 @@ jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
return stream;
}
#else
/*
This function will eventually replace jas_stream_memopen.
If buf is 0 and bufsize > 0:
a buffer is dynamically allocated with size bufsize and this buffer is
not growable.
If buf is 0 and bufsize is 0:
a buffer is dynamically allocated whose size will automatically grow to
accommodate the amount of data written.
If buf is not 0:
bufsize (which, in this case, is not currently allowed to be zero) is
the size of the (nongrowable) buffer pointed to by buf.
*/
jas_stream_t *jas_stream_memopen2(char *buf, size_t bufsize)
{
jas_stream_t *stream;
jas_stream_memobj_t *obj;
JAS_DBGLOG(100, ("jas_stream_memopen2(%p, %zu)\n", buf, bufsize));
assert((buf && bufsize > 0) || (!buf));
if (!(stream = jas_stream_create())) {
return 0;
}
/* A stream associated with a memory buffer is always opened
for both reading and writing in binary mode. */
stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
/* Since the stream data is already resident in memory, buffering
is not necessary. */
/* But... It still may be faster to use buffering anyways. */
jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
/* Select the operations for a memory stream. */
stream->ops_ = &jas_stream_memops;
/* Allocate memory for the underlying memory stream object. */
if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
jas_stream_destroy(stream);
return 0;
}
stream->obj_ = (void *) obj;
/* Initialize a few important members of the memory stream object. */
obj->myalloc_ = 0;
obj->buf_ = 0;
/* If the buffer size specified is nonpositive, then the buffer
is allocated internally and automatically grown as needed. */
if (!bufsize) {
obj->bufsize_ = 1024;
obj->growable_ = 1;
} else {
obj->bufsize_ = bufsize;
obj->growable_ = 0;
}
if (buf) {
obj->buf_ = JAS_CAST(unsigned char *, buf);
} else {
obj->buf_ = jas_malloc(obj->bufsize_);
obj->myalloc_ = 1;
}
if (!obj->buf_) {
jas_stream_close(stream);
return 0;
}
JAS_DBGLOG(100, ("jas_stream_memopen2 buffer buf=%p myalloc=%d\n",
obj->buf_, obj->myalloc_));
if (bufsize > 0 && buf) {
/* If a buffer was supplied by the caller and its length is positive,
make the associated buffer data appear in the stream initially. */
obj->len_ = bufsize;
} else {
/* The stream is initially empty. */
obj->len_ = 0;
}
obj->pos_ = 0;
return stream;
}
/*
NOTE:
The version of the function jas_stream_memopen only exists for backwards
compatibility.
Eventually, it should be replaced by jas_stream_memopen2.
In retrospect, it was a very poor choice to have specified the buffer
size parameter (bufsize) to have type int. On some machines, int may only
be a 16-bit integer. This precludes larger-sized buffer allocations, which
are needed in practice.
If bufsize <= 0, the buffer is growable; otherwise, the buffer has a fixed
size of bufsize.
If buf is 0, the buffer is dynamically allocated with jas_malloc.
If buf is not 0 and bufsize <= 0 (which is not permitted in any
circumstances), bad things will happen (especially if the buf was not
allocated with jas_malloc).
*/
jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
{
char *new_buf;
size_t new_bufsize;
JAS_DBGLOG(100, ("jas_stream_memopen(%p, %d)\n", buf, bufsize));
if (bufsize < 0) {
jas_deprecated("negative buffer size for jas_stream_memopen");
}
if (buf && bufsize <= 0) {
// This was never a valid thing to do with the old API.
jas_eprintf("Invalid use of jas_stream_memopen detected.\n");
jas_deprecated("A user-provided buffer for "
"jas_stream_memopen cannot be growable.\n");
}
if (bufsize <= 0) {
new_bufsize = 0;
new_buf = 0;
} else {
new_bufsize = bufsize;
new_buf = buf;
}
return jas_stream_memopen2(new_buf, new_bufsize);
}
#endif
jas_stream_t *jas_stream_fopen(const char *filename, const char *mode)
{
jas_stream_t *stream;
@@ -520,6 +654,10 @@ int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
int c;
char *bufptr;
if (cnt < 0) {
jas_deprecated("negative count for jas_stream_read");
}
bufptr = buf;
n = 0;
@@ -539,6 +677,10 @@ int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
int n;
const char *bufptr;
if (cnt < 0) {
jas_deprecated("negative count for jas_stream_write");
}
bufptr = buf;
n = 0;
@@ -604,6 +746,9 @@ char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
int jas_stream_gobble(jas_stream_t *stream, int n)
{
int m;
if (n < 0) {
jas_deprecated("negative count for jas_stream_gobble");
}
m = n;
for (m = n; m > 0; --m) {
if (jas_stream_getc(stream) == EOF) {
@@ -616,6 +761,9 @@ int jas_stream_gobble(jas_stream_t *stream, int n)
int jas_stream_pad(jas_stream_t *stream, int n, int c)
{
int m;
if (n < 0) {
jas_deprecated("negative count for jas_stream_pad");
}
m = n;
for (m = n; m > 0; --m) {
if (jas_stream_putc(stream, c) == EOF)
@@ -988,7 +1136,7 @@ long jas_stream_length(jas_stream_t *stream)
static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
{
int n;
ssize_t n;
assert(cnt >= 0);
assert(buf);
@@ -1001,14 +1149,21 @@ static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
return cnt;
}
static int mem_resize(jas_stream_memobj_t *m, int bufsize)
static int mem_resize(jas_stream_memobj_t *m, size_t bufsize)
{
unsigned char *buf;
//assert(m->buf_);
assert(bufsize >= 0);
//assert(bufsize >= 0);
JAS_DBGLOG(100, ("mem_resize(%p, %zu)\n", m, bufsize));
if (!bufsize) {
jas_eprintf(
"mem_resize was not really designed to handle a buffer of size 0\n"
"This may not work.\n"
);
}
JAS_DBGLOG(100, ("mem_resize(%p, %d)\n", m, bufsize));
if (!(buf = jas_realloc2(m->buf_, bufsize, sizeof(unsigned char))) &&
bufsize) {
JAS_DBGLOG(100, ("mem_resize realloc failed\n"));
@@ -1022,11 +1177,11 @@ static int mem_resize(jas_stream_memobj_t *m, int bufsize)
static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
{
int n;
size_t n;
int ret;
jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
long newbufsize;
long newpos;
size_t newbufsize;
size_t newpos;
assert(buf);
assert(cnt >= 0);
@@ -1036,13 +1191,15 @@ static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
if (newpos > m->bufsize_ && m->growable_) {
newbufsize = m->bufsize_;
while (newbufsize < newpos) {
newbufsize <<= 1;
assert(newbufsize >= 0);
//newbufsize <<= 1;
if (!jas_safe_size_mul(newbufsize, 2, &newbufsize)) {
JAS_DBGLOG(100, ("new buffer size would cause overflow\n"));
return -1;
}
}
JAS_DBGLOG(100, ("mem_write resizing from %d to %z\n", m->bufsize_,
JAS_DBGLOG(100, ("mem_write resizing from %d to %zu\n", m->bufsize_,
newbufsize));
JAS_DBGLOG(100, ("mem_write resizing from %d to %ul\n", m->bufsize_,
JAS_CAST(unsigned long, newbufsize)));
assert(newbufsize > 0);
if (mem_resize(m, newbufsize)) {
return -1;
}
@@ -1076,7 +1233,7 @@ static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
static long mem_seek(jas_stream_obj_t *obj, long offset, int origin)
{
jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
long newpos;
size_t newpos;
JAS_DBGLOG(100, ("mem_seek(%p, %ld, %d)\n", obj, offset, origin));
switch (origin) {
@@ -107,6 +107,9 @@ int jas_eprintf(const char *fmt, ...);
/* Dump memory to a stream. */
int jas_memdump(FILE *out, void *data, size_t len);
/* Warn about use of deprecated functionality. */
void jas_deprecated(const char *s);
#ifdef __cplusplus
}
#endif
@@ -267,7 +267,7 @@ typedef struct {
uchar *buf_;
/* The allocated size of the buffer for holding file data. */
int bufsize_;
size_t bufsize_;
/* The length of the file. */
int_fast32_t len_;
@@ -293,6 +293,10 @@ jas_stream_t *jas_stream_fopen(const char *filename, const char *mode);
/* Open a memory buffer as a stream. */
jas_stream_t *jas_stream_memopen(char *buf, int bufsize);
/* Do not use this function.
It will eventually replace jas_stream_memopen. */
jas_stream_t *jas_stream_memopen2(char *buf, size_t bufsize);
/* Open a file descriptor as a stream. */
jas_stream_t *jas_stream_fdopen(int fd, const char *mode);

0 comments on commit 634ce8e

Please sign in to comment.