diff options
author | Mark H Weaver <mhw@netris.org> | 2013-04-01 03:37:36 -0400 |
---|---|---|
committer | Mark H Weaver <mhw@netris.org> | 2013-04-01 03:47:09 -0400 |
commit | 2f13a46672a347be0f7bb1b360a213f6d6ce0288 (patch) | |
tree | 981d6308378b0287aa48fc7e9b26189d046c2093 | |
parent | 3b80c3585221a899c9a6b87e742d267655bb0abc (diff) | |
download | guile-2f13a46672a347be0f7bb1b360a213f6d6ce0288.tar.gz |
Make 'string-append' more efficient and robust.
* libguile/strings.c (scm_string_append): Check for numerical overflow
while computing the length of the result. Double-check that we don't
overflow the result string, and that it is the correct length in the
end (in case another thread changed the list). When copying a narrow
string to a wide result, avoid calling 'scm_i_string_length' and
'scm_i_string_chars' on each character.
-rw-r--r-- | libguile/strings.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/libguile/strings.c b/libguile/strings.c index 5d0db2301..1b241e52c 100644 --- a/libguile/strings.c +++ b/libguile/strings.c @@ -1401,7 +1401,8 @@ SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1, #define FUNC_NAME s_scm_string_append { SCM res; - size_t len = 0; + size_t total = 0; + size_t len; int wide = 0; SCM l, s; size_t i; @@ -1416,15 +1417,18 @@ 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); + len = scm_i_string_length (s); + if (((size_t) -1) - total < len) + scm_num_overflow (s_scm_string_append); + total += len; if (!scm_i_is_narrow_string (s)) wide = 1; } data.narrow = NULL; if (!wide) - res = scm_i_make_string (len, &data.narrow, 0); + res = scm_i_make_string (total, &data.narrow, 0); else - res = scm_i_make_wide_string (len, &data.wide, 0); + res = scm_i_make_wide_string (total, &data.wide, 0); for (l = args; !scm_is_null (l); l = SCM_CDR (l)) { @@ -1432,6 +1436,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 (len > total) + SCM_MISC_ERROR ("list changed during string-append", SCM_EOL); if (!wide) { memcpy (data.narrow, scm_i_string_chars (s), len); @@ -1441,16 +1447,20 @@ SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1, { if (scm_i_is_narrow_string (s)) { - for (i = 0; i < scm_i_string_length (s); i++) - data.wide[i] = (unsigned char) scm_i_string_chars (s)[i]; + const char *src = scm_i_string_chars (s); + for (i = 0; i < len; i++) + data.wide[i] = (unsigned char) src[i]; } else u32_cpy ((scm_t_uint32 *) data.wide, (scm_t_uint32 *) scm_i_string_wide_chars (s), len); data.wide += len; } + total -= len; scm_remember_upto_here_1 (s); } + if (total != 0) + SCM_MISC_ERROR ("list changed during string-append", SCM_EOL); return res; } #undef FUNC_NAME |