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

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.
This commit is contained in:
Mark H Weaver 2013-04-01 03:37:36 -04:00
parent 3b80c35852
commit 2f13a46672

View file

@ -1401,7 +1401,8 @@ SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1,
#define FUNC_NAME s_scm_string_append #define FUNC_NAME s_scm_string_append
{ {
SCM res; SCM res;
size_t len = 0; size_t total = 0;
size_t len;
int wide = 0; int wide = 0;
SCM l, s; SCM l, s;
size_t i; size_t i;
@ -1416,15 +1417,18 @@ SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1,
{ {
s = SCM_CAR (l); s = SCM_CAR (l);
SCM_VALIDATE_STRING (SCM_ARGn, s); 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)) if (!scm_i_is_narrow_string (s))
wide = 1; wide = 1;
} }
data.narrow = NULL; data.narrow = NULL;
if (!wide) if (!wide)
res = scm_i_make_string (len, &data.narrow, 0); res = scm_i_make_string (total, &data.narrow, 0);
else 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)) 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); s = SCM_CAR (l);
SCM_VALIDATE_STRING (SCM_ARGn, s); SCM_VALIDATE_STRING (SCM_ARGn, s);
len = scm_i_string_length (s); len = scm_i_string_length (s);
if (len > total)
SCM_MISC_ERROR ("list changed during string-append", SCM_EOL);
if (!wide) if (!wide)
{ {
memcpy (data.narrow, scm_i_string_chars (s), len); 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)) if (scm_i_is_narrow_string (s))
{ {
for (i = 0; i < scm_i_string_length (s); i++) const char *src = scm_i_string_chars (s);
data.wide[i] = (unsigned char) scm_i_string_chars (s)[i]; for (i = 0; i < len; i++)
data.wide[i] = (unsigned char) src[i];
} }
else else
u32_cpy ((scm_t_uint32 *) data.wide, u32_cpy ((scm_t_uint32 *) data.wide,
(scm_t_uint32 *) scm_i_string_wide_chars (s), len); (scm_t_uint32 *) scm_i_string_wide_chars (s), len);
data.wide += len; data.wide += len;
} }
total -= len;
scm_remember_upto_here_1 (s); scm_remember_upto_here_1 (s);
} }
if (total != 0)
SCM_MISC_ERROR ("list changed during string-append", SCM_EOL);
return res; return res;
} }
#undef FUNC_NAME #undef FUNC_NAME