summaryrefslogtreecommitdiff
path: root/libguile/strports.c
diff options
context:
space:
mode:
authorMark H Weaver <mhw@netris.org>2019-04-19 00:59:59 -0400
committerMark H Weaver <mhw@netris.org>2019-06-18 02:05:20 -0400
commit91ba73b397fcc2a36ae7e434522a924c7a8887d0 (patch)
tree375d88ff803fa5bed9c6ffbfb10e51d41f5ebea8 /libguile/strports.c
parent420c2632bb1f48e492a035c1d216f209734f45e6 (diff)
downloadguile-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.c31
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