1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-21 20:20:24 +02:00

string ports: Add overflow checks and other fixes.

* libguile/strports.c (st_resize_port): Check that 'new_size' fits in a
  size_t.
  (st_end_input): Improve code clarity.
  (st_seek): Check for overflow during computation of target position.
  Check for invalid 'whence' argument.  Resize the port when seeking to
  a position beyond the end of the buffer.  Check for overflow during
  computation of new buffer size when resizing the port.
This commit is contained in:
Mark H Weaver 2015-09-06 07:42:07 -04:00
parent 448eb30e3d
commit 133ec4c491

View file

@ -103,6 +103,10 @@ stfill_buffer (SCM port)
static void static void
st_resize_port (scm_t_port *pt, scm_t_off new_size) st_resize_port (scm_t_port *pt, scm_t_off new_size)
{ {
if (new_size < 0 || new_size > SCM_I_SIZE_MAX)
scm_misc_error ("st_resize_port", "new_size overflow", SCM_EOL);
{
SCM old_stream = SCM_PACK (pt->stream); SCM old_stream = SCM_PACK (pt->stream);
const signed char *src = SCM_BYTEVECTOR_CONTENTS (old_stream); const signed char *src = SCM_BYTEVECTOR_CONTENTS (old_stream);
SCM new_stream = scm_c_make_bytevector (new_size); SCM new_stream = scm_c_make_bytevector (new_size);
@ -126,6 +130,7 @@ st_resize_port (scm_t_port *pt, scm_t_off new_size)
pt->write_end = pt->write_buf + pt->write_buf_size; pt->write_end = pt->write_buf + pt->write_buf_size;
pt->read_end = pt->read_buf + pt->read_buf_size; pt->read_end = pt->read_buf + pt->read_buf_size;
} }
}
} }
/* Ensure that `write_pos' < `write_end' by enlarging the buffer when /* Ensure that `write_pos' < `write_end' by enlarging the buffer when
@ -176,7 +181,8 @@ st_end_input (SCM port, int offset)
if (pt->read_pos - pt->read_buf < offset) if (pt->read_pos - pt->read_buf < offset)
scm_misc_error ("st_end_input", "negative position", SCM_EOL); scm_misc_error ("st_end_input", "negative position", SCM_EOL);
pt->write_pos = (unsigned char *) (pt->read_pos = pt->read_pos - offset); pt->read_pos -= offset;
pt->write_pos = (unsigned char *) pt->read_pos;
pt->rw_active = SCM_PORT_NEITHER; pt->rw_active = SCM_PORT_NEITHER;
} }
@ -202,6 +208,8 @@ st_seek (SCM port, scm_t_off offset, int whence)
else else
/* all other cases. */ /* all other cases. */
{ {
scm_t_off base = 0;
if (pt->rw_active == SCM_PORT_WRITE) if (pt->rw_active == SCM_PORT_WRITE)
st_flush (port); st_flush (port);
@ -211,18 +219,24 @@ st_seek (SCM port, scm_t_off offset, int whence)
switch (whence) switch (whence)
{ {
case SEEK_CUR: case SEEK_CUR:
target = pt->read_pos - pt->read_buf + offset; base = pt->read_pos - pt->read_buf;
break; break;
case SEEK_END: case SEEK_END:
target = pt->read_end - pt->read_buf + offset; base = pt->read_end - pt->read_buf;
break; break;
default: /* SEEK_SET */ case SEEK_SET:
target = offset; base = 0;
break; break;
default:
scm_wrong_type_arg_msg ("st_seek", 0, port,
"invalid `whence' argument");
} }
if (offset > SCM_T_OFF_MAX - base)
scm_misc_error ("st_seek", "target would overflow", SCM_EOL);
target = base + offset;
if (target < 0) if (target < 0)
scm_misc_error ("st_seek", "negative offset", SCM_EOL); scm_misc_error ("st_seek", "negative target", SCM_EOL);
if (target >= pt->write_buf_size) if (target >= pt->write_buf_size)
{ {
@ -235,7 +249,9 @@ st_seek (SCM port, scm_t_off offset, int whence)
SCM_EOL); SCM_EOL);
} }
} }
else if (target == pt->write_buf_size) else if (target > SCM_T_OFF_MAX - target)
scm_misc_error ("st_seek", "target * 2 would overflow", SCM_EOL);
else
st_resize_port (pt, target * 2); st_resize_port (pt, target * 2);
} }
pt->read_pos = pt->write_pos = pt->read_buf + target; pt->read_pos = pt->write_pos = pt->read_buf + target;