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 | |
parent | 420c2632bb1f48e492a035c1d216f209734f45e6 (diff) |
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'.
-rw-r--r-- | libguile/bytevectors.c | 27 | ||||
-rw-r--r-- | libguile/fports.c | 10 | ||||
-rw-r--r-- | libguile/guardians.c | 6 | ||||
-rw-r--r-- | libguile/ports.c | 17 | ||||
-rw-r--r-- | libguile/r6rs-ports.c | 101 | ||||
-rw-r--r-- | libguile/strings.c | 20 | ||||
-rw-r--r-- | libguile/strports.c | 31 | ||||
-rw-r--r-- | libguile/vectors.c | 6 |
8 files changed, 142 insertions, 76 deletions
diff --git a/libguile/bytevectors.c b/libguile/bytevectors.c index e42a48c4e..0ac5ea6a6 100644 --- a/libguile/bytevectors.c +++ b/libguile/bytevectors.c @@ -84,7 +84,8 @@ c_len = SCM_BYTEVECTOR_LENGTH (bv); \ c_bv = (_sign char *) SCM_BYTEVECTOR_CONTENTS (bv); \ \ - if (SCM_UNLIKELY (c_index + ((_len) >> 3UL) - 1 >= c_len)) \ + if (SCM_UNLIKELY (c_len < c_index \ + || (c_len - c_index < (_len) / 8))) \ scm_out_of_range (FUNC_NAME, index); #define INTEGER_GETTER_PROLOGUE(_len, _sign) \ @@ -206,12 +207,17 @@ make_bytevector (size_t len, scm_t_array_element_type element_type) size_t c_len; if (SCM_UNLIKELY (element_type > SCM_ARRAY_ELEMENT_TYPE_LAST - || scm_i_array_element_type_sizes[element_type] < 8 - || len >= (((size_t) -1) - / (scm_i_array_element_type_sizes[element_type]/8)))) + || scm_i_array_element_type_sizes[element_type] < 8)) /* This would be an internal Guile programming error */ abort (); + /* Make sure that the total allocation size will not overflow size_t, + with ~30 extra bytes to spare to avoid an overflow within the + allocator. */ + if (SCM_UNLIKELY (len >= (((size_t) -(SCM_BYTEVECTOR_HEADER_BYTES + 32)) + / (scm_i_array_element_type_sizes[element_type]/8)))) + scm_num_overflow ("make-bytevector"); + if (SCM_UNLIKELY (len == 0 && element_type == SCM_ARRAY_ELEMENT_TYPE_VU8 && SCM_BYTEVECTOR_P (scm_null_bytevector))) ret = scm_null_bytevector; @@ -252,7 +258,7 @@ make_bytevector_from_buffer (size_t len, void *contents, size_t c_len; ret = SCM_PACK_POINTER (scm_gc_malloc (SCM_BYTEVECTOR_HEADER_BYTES, - SCM_GC_BYTEVECTOR)); + SCM_GC_BYTEVECTOR)); c_len = len * (scm_i_array_element_type_sizes[element_type] / 8); @@ -510,7 +516,7 @@ SCM_DEFINE (scm_bytevector_length, "bytevector-length", 1, 0, 0, "Return the length (in bytes) of @var{bv}.") #define FUNC_NAME s_scm_bytevector_length { - return scm_from_uint (scm_c_bytevector_length (bv)); + return scm_from_size_t (scm_c_bytevector_length (bv)); } #undef FUNC_NAME @@ -595,9 +601,11 @@ SCM_DEFINE (scm_bytevector_copy_x, "bytevector-copy!", 5, 0, 0, c_source_len = SCM_BYTEVECTOR_LENGTH (source); c_target_len = SCM_BYTEVECTOR_LENGTH (target); - if (SCM_UNLIKELY (c_source_start + c_len > c_source_len)) + if (SCM_UNLIKELY (c_source_len < c_source_start + || (c_source_len - c_source_start < c_len))) scm_out_of_range (FUNC_NAME, source_start); - if (SCM_UNLIKELY (c_target_start + c_len > c_target_len)) + if (SCM_UNLIKELY (c_target_len < c_target_start + || (c_target_len - c_target_start < c_len))) scm_out_of_range (FUNC_NAME, target_start); memmove (c_target + c_target_start, @@ -915,7 +923,8 @@ bytevector_large_set (char *c_bv, size_t c_size, int signed_p, size_t. */ \ if (SCM_UNLIKELY (c_size == 0 || c_size >= (SIZE_MAX >> 3))) \ scm_out_of_range (FUNC_NAME, size); \ - if (SCM_UNLIKELY (c_index + c_size > c_len)) \ + if (SCM_UNLIKELY (c_len < c_index \ + || (c_len - c_index < c_size))) \ scm_out_of_range (FUNC_NAME, index); #define GENERIC_INTEGER_GETTER_PROLOGUE(_sign) \ diff --git a/libguile/fports.c b/libguile/fports.c index ee6ac0bf1..5de08d319 100644 --- a/libguile/fports.c +++ b/libguile/fports.c @@ -1,6 +1,5 @@ -/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - * 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, - * 2014, 2015, 2017 Free Software Foundation, Inc. +/* Copyright (C) 1995-2004, 2006-2015, 2017, 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 @@ -621,6 +620,11 @@ fport_seek (SCM port, scm_t_off offset, int whence) if (result == -1) scm_syserror ("fport_seek"); + /* Check to make sure the result fits in scm_t_off, + which might be smaller than off_t_or_off64_t. */ + if (result > SCM_T_OFF_MAX) + scm_num_overflow ("fport_seek"); + return result; } diff --git a/libguile/guardians.c b/libguile/guardians.c index cd4d9f3e2..2c63b580d 100644 --- a/libguile/guardians.c +++ b/libguile/guardians.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1998,1999,2000,2001, 2006, 2008, 2009, 2011, - * 2012, 2013 Free Software Foundation, Inc. +/* Copyright (C) 1998-2001, 2006, 2008, 2009, 2011-2013, 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 @@ -89,7 +89,7 @@ guardian_print (SCM guardian, SCM port, scm_print_state *pstate SCM_UNUSED) scm_uintprint ((scm_t_bits) g, 16, port); scm_puts (" (reachable: ", port); - scm_display (scm_from_uint (g->live), port); + scm_display (scm_from_ulong (g->live), port); scm_puts (" unreachable: ", port); scm_display (scm_length (g->zombies), port); scm_puts (")", port); diff --git a/libguile/ports.c b/libguile/ports.c index bb257041a..900de67e3 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1995-2001, 2003-2004, 2006-2017 - * Free Software Foundation, Inc. +/* Copyright (C) 1995-2001, 2003-2004, 2006-2017, 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 @@ -2236,7 +2236,8 @@ SCM_DEFINE (scm_unread_string, "unread-string", 2, 0, 0, "@var{port} is not supplied, the current-input-port is used.") #define FUNC_NAME s_scm_unread_string { - int n; + size_t n; + SCM_VALIDATE_STRING (1, str); if (SCM_UNBNDP (port)) port = scm_current_input_port (); @@ -3734,8 +3735,8 @@ SCM_DEFINE (scm_seek, "seek", 3, 0, 0, { scm_t_port *pt = SCM_PORT (fd_port); scm_t_port_type *ptob = SCM_PORT_TYPE (fd_port); - off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset); - off_t_or_off64_t rv; + scm_t_off off = scm_to_off_t (offset); + scm_t_off rv; if (ptob->seek && how == SEEK_CUR && off == 0) { @@ -3749,7 +3750,7 @@ SCM_DEFINE (scm_seek, "seek", 3, 0, 0, scm_dynwind_end (); rv -= scm_port_buffer_can_take (pt->read_buf, &tmp); rv += scm_port_buffer_can_take (pt->write_buf, &tmp); - return scm_from_off_t_or_off64_t (rv); + return scm_from_off_t (rv); } if (!ptob->seek || !pt->rw_random) @@ -3770,7 +3771,7 @@ SCM_DEFINE (scm_seek, "seek", 3, 0, 0, scm_i_clear_pending_eof (fd_port); - return scm_from_off_t_or_off64_t (rv); + return scm_from_off_t (rv); } else /* file descriptor?. */ { @@ -3855,7 +3856,7 @@ SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0, } else if (SCM_OPOUTPORTP (object)) { - off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length); + scm_t_off c_length = scm_to_off_t (length); scm_t_port_type *ptob = SCM_PORT_TYPE (object); if (!ptob->truncate) diff --git a/libguile/r6rs-ports.c b/libguile/r6rs-ports.c index 16c148090..90387e82c 100644 --- a/libguile/r6rs-ports.c +++ b/libguile/r6rs-ports.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2009, 2010, 2011, 2013-2015, 2018 Free Software Foundation, Inc. +/* Copyright (C) 2009-2011, 2013-2015, 2018, 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 @@ -24,6 +25,7 @@ #include <string.h> #include <stdio.h> #include <assert.h> +#include <intprops.h> #include "libguile/_scm.h" #include "libguile/bytevectors.h" @@ -130,21 +132,27 @@ bytevector_input_port_seek (SCM port, scm_t_off offset, int whence) #define FUNC_NAME "bytevector_input_port_seek" { struct bytevector_input_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 + SCM_BYTEVECTOR_LENGTH (stream->bytevector); + base = SCM_BYTEVECTOR_LENGTH (stream->bytevector); 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 <= SCM_BYTEVECTOR_LENGTH (stream->bytevector)) 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; } @@ -224,6 +232,9 @@ custom_binary_port_seek (SCM port, scm_t_off offset, int whence) /* We just want to know the current position. */ break; + if (INT_ADD_OVERFLOW (offset, c_result)) + scm_num_overflow (FUNC_NAME); + offset += c_result; /* Fall through. */ } @@ -231,7 +242,7 @@ custom_binary_port_seek (SCM port, scm_t_off offset, int whence) case SEEK_SET: { if (SCM_LIKELY (scm_is_true (stream->set_position_x))) - result = scm_call_1 (stream->set_position_x, scm_from_int (offset)); + result = scm_call_1 (stream->set_position_x, scm_from_off_t (offset)); else scm_wrong_type_arg_msg (FUNC_NAME, 0, port, "seekable R6RS custom binary port"); @@ -454,7 +465,8 @@ SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 0, 0, c_len = SCM_BYTEVECTOR_LENGTH (bv); - if (SCM_UNLIKELY (c_start + c_count > c_len)) + if (SCM_UNLIKELY (c_len < c_start + || (c_len - c_start < c_count))) scm_out_of_range (FUNC_NAME, count); if (SCM_LIKELY (c_count > 0)) @@ -511,7 +523,7 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0, #define FUNC_NAME s_scm_get_bytevector_all { SCM result; - unsigned c_len, c_count; + size_t c_len, c_count; size_t c_read, c_total; SCM_VALIDATE_BINARY_INPUT_PORT (1, port); @@ -522,10 +534,14 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 1, 0, 0, do { - if (c_total + c_read > c_len) + if (c_read > c_len - c_total) { /* Grow the bytevector. */ SCM prev = result; + + if (INT_ADD_OVERFLOW (c_len, c_len)) + scm_num_overflow (FUNC_NAME); + result = scm_c_make_bytevector (c_len * 2); memcpy (SCM_BYTEVECTOR_CONTENTS (result), SCM_BYTEVECTOR_CONTENTS (prev), @@ -593,20 +609,17 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0, if (!scm_is_eq (start, SCM_UNDEFINED)) { c_start = scm_to_size_t (start); + if (SCM_UNLIKELY (c_start > c_len)) + scm_out_of_range (FUNC_NAME, start); if (!scm_is_eq (count, SCM_UNDEFINED)) { c_count = scm_to_size_t (count); - if (SCM_UNLIKELY (c_start + c_count > c_len)) + if (SCM_UNLIKELY (c_count > c_len - c_start)) scm_out_of_range (FUNC_NAME, count); } else - { - if (SCM_UNLIKELY (c_start > c_len)) - scm_out_of_range (FUNC_NAME, start); - else - c_count = c_len - c_start; - } + c_count = c_len - c_start; } else c_start = 0, c_count = c_len; @@ -636,20 +649,17 @@ SCM_DEFINE (scm_unget_bytevector, "unget-bytevector", 2, 2, 0, if (!scm_is_eq (start, SCM_UNDEFINED)) { c_start = scm_to_size_t (start); + if (SCM_UNLIKELY (c_start > c_len)) + scm_out_of_range (FUNC_NAME, start); if (!scm_is_eq (count, SCM_UNDEFINED)) { c_count = scm_to_size_t (count); - if (SCM_UNLIKELY (c_start + c_count > c_len)) + if (SCM_UNLIKELY (c_count > c_len - c_start)) scm_out_of_range (FUNC_NAME, count); } else - { - if (SCM_UNLIKELY (c_start > c_len)) - scm_out_of_range (FUNC_NAME, start); - else - c_count = c_len - c_start; - } + c_count = c_len - c_start; } else c_start = 0, c_count = c_len; @@ -722,17 +732,20 @@ bytevector_output_port_buffer_grow (scm_t_bytevector_output_port_buffer *buf, char *new_buf; size_t new_size; - for (new_size = buf->total_len - ? buf->total_len : SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER_INITIAL_SIZE; - new_size < min_size; - new_size *= 2); - if (buf->buffer) - new_buf = scm_gc_realloc ((void *) buf->buffer, buf->total_len, - new_size, SCM_GC_BYTEVECTOR_OUTPUT_PORT); + { + if (INT_ADD_OVERFLOW (buf->total_len, buf->total_len)) + scm_num_overflow ("bytevector_output_port_buffer_grow"); + new_size = max (min_size, buf->total_len * 2); + new_buf = scm_gc_realloc ((void *) buf->buffer, buf->total_len, + new_size, SCM_GC_BYTEVECTOR_OUTPUT_PORT); + } else - new_buf = scm_gc_malloc_pointerless (new_size, - SCM_GC_BYTEVECTOR_OUTPUT_PORT); + { + new_size = max (min_size, SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER_INITIAL_SIZE); + new_buf = scm_gc_malloc_pointerless (new_size, + SCM_GC_BYTEVECTOR_OUTPUT_PORT); + } buf->buffer = new_buf; buf->total_len = new_size; @@ -763,13 +776,18 @@ make_bytevector_output_port (void) /* Write octets from WRITE_BUF to the backing store. */ static size_t bytevector_output_port_write (SCM port, SCM src, size_t start, size_t count) +#define FUNC_NAME "bytevector_output_port_write" { scm_t_bytevector_output_port_buffer *buf; buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port); - if (buf->pos + count > buf->total_len) - bytevector_output_port_buffer_grow (buf, buf->pos + count); + if (count > buf->total_len - buf->pos) + { + if (INT_ADD_OVERFLOW (buf->pos, count)) + scm_num_overflow (FUNC_NAME); + bytevector_output_port_buffer_grow (buf, buf->pos + count); + } memcpy (buf->buffer + buf->pos, SCM_BYTEVECTOR_CONTENTS (src) + start, count); @@ -778,29 +796,36 @@ bytevector_output_port_write (SCM port, SCM src, size_t start, size_t count) return count; } +#undef FUNC_NAME static scm_t_off bytevector_output_port_seek (SCM port, scm_t_off offset, int whence) #define FUNC_NAME "bytevector_output_port_seek" { scm_t_bytevector_output_port_buffer *buf; + size_t base; scm_t_off target; buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port); if (whence == SEEK_CUR) - target = offset + buf->pos; + base = buf->pos; else if (whence == SEEK_SET) - target = offset; + base = 0; else if (whence == SEEK_END) - target = offset + buf->len; + base = buf->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 <= buf->len) buf->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; } diff --git a/libguile/strings.c b/libguile/strings.c index e5c7f87d6..9497a3fe1 100644 --- a/libguile/strings.c +++ b/libguile/strings.c @@ -31,6 +31,7 @@ #include <unistr.h> #include <uniconv.h> #include <c-strcase.h> +#include <intprops.h> #include "striconveh.h" @@ -124,6 +125,12 @@ make_stringbuf (size_t len) lenhist[1000]++; #endif + /* Make sure that the total allocation size will not overflow size_t, + with ~30 extra bytes to spare to avoid an overflow within the + allocator. */ + if (INT_ADD_OVERFLOW (len, STRINGBUF_HEADER_BYTES + 32)) + scm_num_overflow ("make_stringbuf"); + buf = SCM_PACK_POINTER (scm_gc_malloc_pointerless (STRINGBUF_HEADER_BYTES + len + 1, "string")); @@ -150,9 +157,16 @@ make_wide_stringbuf (size_t len) lenhist[1000]++; #endif + /* Make sure that the total allocation size will not overflow size_t, + with ~30 extra bytes to spare to avoid an overflow within the + allocator. */ + if (len > (((size_t) -(STRINGBUF_HEADER_BYTES + 32 + sizeof (scm_t_wchar))) + / sizeof (scm_t_wchar))) + scm_num_overflow ("make_wide_stringbuf"); + raw_len = (len + 1) * sizeof (scm_t_wchar); buf = SCM_PACK_POINTER (scm_gc_malloc_pointerless (STRINGBUF_HEADER_BYTES + raw_len, - "string")); + "string")); SCM_SET_CELL_TYPE (buf, STRINGBUF_TAG | STRINGBUF_F_WIDE); SCM_SET_CELL_WORD_1 (buf, (scm_t_bits) len); @@ -1388,8 +1402,8 @@ SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1, s = SCM_CAR (l); SCM_VALIDATE_STRING (SCM_ARGn, s); len = scm_i_string_length (s); - if (((size_t) -1) - total < len) - scm_num_overflow (s_scm_string_append); + if (INT_ADD_OVERFLOW (total, len)) + scm_num_overflow (FUNC_NAME); total += len; if (!scm_i_is_narrow_string (s)) wide = 1; 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 diff --git a/libguile/vectors.c b/libguile/vectors.c index 328cf6f5f..acdda5dcd 100644 --- a/libguile/vectors.c +++ b/libguile/vectors.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2006, 2008, 2009, 2010, - * 2011, 2012, 2014 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996, 1998-2001, 2006, 2008-2012, 2014, 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 @@ -245,7 +245,7 @@ scm_c_make_vector (size_t k, SCM fill) #define FUNC_NAME s_scm_make_vector { SCM vector; - unsigned long int j; + size_t j; SCM_ASSERT_RANGE (1, scm_from_size_t (k), k <= VECTOR_MAX_LENGTH); |