diff options
author | Mark H Weaver <mhw@netris.org> | 2019-04-19 00:59:59 -0400 |
---|---|---|
committer | Mark H Weaver <mhw@netris.org> | 2019-06-18 02:05:20 -0400 |
commit | 91ba73b397fcc2a36ae7e434522a924c7a8887d0 (patch) | |
tree | 375d88ff803fa5bed9c6ffbfb10e51d41f5ebea8 /libguile/strports.c | |
parent | 420c2632bb1f48e492a035c1d216f209734f45e6 (diff) | |
download | guile-91ba73b397fcc2a36ae7e434522a924c7a8887d0.tar.gz |
Improve overflow checks in bytevector, string, and I/O operations.
* libguile/bytevectors.c (INTEGER_ACCESSOR_PROLOGUE)
(scm_bytevector_copy_x, bytevector_large_set): Rewrite checks to reliably
detect overflows.
(make_bytevector): Constrain the bytevector length to avoid later
overflows during allocation.
(make_bytevector_from_buffer): Fix indentation.
(scm_bytevector_length): Use 'scm_from_size_t' to convert a 'size_t',
not 'scm_from_uint'.
* libguile/fports.c (fport_seek): Check for overflow before the implicit
conversion of the return value.
* libguile/guardians.c (guardian_print): Use 'scm_from_ulong' to convert
an 'unsigned long', not 'scm_from_uint'.
* libguile/ports.c (scm_unread_string): Change a variable to type 'size_t'.
(scm_seek, scm_truncate_file): Use 'scm_t_off' instead of
'off_t_or_off64_t' to avoid implicit type conversions that could
overflow, because 'ptob->seek' and 'ptob->truncate' use 'scm_t_off'.
* libguile/r6rs-ports.c (bytevector_input_port_seek)
(custom_binary_port_seek, bytevector_output_port_seek): Rewrite offset
calculations to reliably detect overflows. Use 'scm_from_off_t' to
convert a 'scm_t_off', not 'scm_from_long' nor 'scm_from_int'.
(scm_get_bytevector_n_x, scm_get_bytevector_all, scm_unget_bytevector)
(bytevector_output_port_write): Rewrite checks to reliably detect
overflows. Use 'size_t' where appropriate.
(bytevector_output_port_buffer_grow): Rewrite size calculations to
reliably detect overflows. Minor change in the calculation of the new
size: now it is max(min_size, 2*current_size), whereas previously it
would multiply current_size by the smallest power of 2 needed to surpass
min_size.
* libguile/strings.c (make_stringbuf): Constrain the stringbuf length to
avoid later overflows during allocation.
(scm_string_append): Change overflow check to use INT_ADD_OVERFLOW.
* libguile/strports.c (string_port_write): Rewrite size calculations to
reliably detect overflows.
(string_port_seek): Rewrite offset calculations to reliably detect
overflows. Use 'scm_from_off_t' to convert a 'scm_t_off', not
'scm_from_long'.
(string_port_truncate): Use 'scm_from_off_t' to convert a 'scm_t_off',
not 'scm_from_off_t_or_off64_t'.
* libguile/vectors.c (scm_c_make_vector): Change a variable to type
'size_t'.
Diffstat (limited to 'libguile/strports.c')
-rw-r--r-- | libguile/strports.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/libguile/strports.c b/libguile/strports.c index b01282ee1..876a62a86 100644 --- a/libguile/strports.c +++ b/libguile/strports.c @@ -1,5 +1,5 @@ /* Copyright (C) 1995, 1996, 1998-2003, 2005, 2006, 2009-2014, - * 2016-2018 Free Software Foundation, Inc. + * 2016-2019 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -28,6 +28,7 @@ #include <stdio.h> #include <unistd.h> +#include <intprops.h> #include "libguile/bytevectors.h" #include "libguile/eval.h" @@ -82,16 +83,21 @@ string_port_read (SCM port, SCM dst, size_t start, size_t count) static size_t string_port_write (SCM port, SCM src, size_t start, size_t count) +#define FUNC_NAME "string_port_write" { struct string_port *stream = (void *) SCM_STREAM (port); + size_t old_size = SCM_BYTEVECTOR_LENGTH (stream->bytevector); - if (SCM_BYTEVECTOR_LENGTH (stream->bytevector) < stream->pos + count) + if (count > old_size - stream->pos) { SCM new_bv; size_t new_size; - new_size = max (SCM_BYTEVECTOR_LENGTH (stream->bytevector) * 2, - stream->pos + count); + if (INT_ADD_OVERFLOW (stream->pos, count)) + scm_num_overflow (FUNC_NAME); + + /* If (old_size * 2) overflows, it's harmless. */ + new_size = max (old_size * 2, stream->pos + count); new_bv = scm_c_make_bytevector (new_size); memcpy (SCM_BYTEVECTOR_CONTENTS (new_bv), SCM_BYTEVECTOR_CONTENTS (stream->bytevector), @@ -108,27 +114,34 @@ string_port_write (SCM port, SCM src, size_t start, size_t count) return count; } +#undef FUNC_NAME static scm_t_off string_port_seek (SCM port, scm_t_off offset, int whence) #define FUNC_NAME "string_port_seek" { struct string_port *stream = (void *) SCM_STREAM (port); + size_t base; scm_t_off target; if (whence == SEEK_CUR) - target = offset + stream->pos; + base = stream->pos; else if (whence == SEEK_SET) - target = offset; + base = 0; else if (whence == SEEK_END) - target = offset + stream->len; + base = stream->len; else scm_wrong_type_arg_msg (FUNC_NAME, 0, port, "invalid `seek' parameter"); + if (base > SCM_T_OFF_MAX + || INT_ADD_OVERFLOW ((scm_t_off) base, offset)) + scm_num_overflow (FUNC_NAME); + target = (scm_t_off) base + offset; + if (target >= 0 && target <= stream->len) stream->pos = target; else - scm_out_of_range (FUNC_NAME, scm_from_long (offset)); + scm_out_of_range (FUNC_NAME, scm_from_off_t (offset)); return target; } @@ -143,7 +156,7 @@ string_port_truncate (SCM port, scm_t_off length) if (0 <= length && stream->pos <= length && length <= stream->len) stream->len = length; else - scm_out_of_range (FUNC_NAME, scm_from_off_t_or_off64_t (length)); + scm_out_of_range (FUNC_NAME, scm_from_off_t (length)); } #undef FUNC_NAME |