summaryrefslogtreecommitdiff
path: root/libguile/strings.c
diff options
context:
space:
mode:
authorMark H Weaver <mhw@netris.org>2019-05-06 21:11:26 -0400
committerAndy Wingo <wingo@pobox.com>2019-05-23 17:51:36 +0200
commitbd50407d1f9adc3eedd6687c9a84aa7a503b7ce1 (patch)
treef192426504933a93f0fca52afebd1e8ea67244fe /libguile/strings.c
parent2bfa4f73f188e4ad2bde22594d5173e71c1d3d2f (diff)
downloadguile-bd50407d1f9adc3eedd6687c9a84aa7a503b7ce1.tar.gz
Strings, i18n: Limit the use of alloca to approximately 8 kilobytes.
* libguile/i18n.c (SCM_MAX_ALLOCA): New macro. (SCM_STRING_TO_U32_BUF): Accept an additional variable to remember whether we used malloc to allocate the buffer. Use malloc if the allocation size is greater than SCM_MAX_ALLOCA. (SCM_CLEANUP_U32_BUF): New macro. (compare_u32_strings, compare_u32_strings_ci, str_to_case): Adapt. * libguile/strings.c (SCM_MAX_ALLOCA): New macro. (normalize_str, unistring_escapes_to_r6rs_escapes): Use malloc if the allocation size is greater than SCM_MAX_ALLOCA. * test-suite/tests/i18n.test, test-suite/tests/strings.test: Add tests.
Diffstat (limited to 'libguile/strings.c')
-rw-r--r--libguile/strings.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/libguile/strings.c b/libguile/strings.c
index e6ae5cbd5..8f6a47e29 100644
--- a/libguile/strings.c
+++ b/libguile/strings.c
@@ -50,6 +50,10 @@
#include "strings.h"
+#ifndef SCM_MAX_ALLOCA
+# define SCM_MAX_ALLOCA 4096 /* Max bytes per string to allocate via alloca */
+#endif
+
/* {Strings}
@@ -1813,6 +1817,7 @@ static void
unistring_escapes_to_r6rs_escapes (char *buf, size_t *lenp)
{
char *before, *after;
+ int malloc_p;
size_t i, j;
/* The worst case is if the input string contains all 4-digit hex escapes.
"\uXXXX" (six characters) becomes "\xXXXX;" (seven characters) */
@@ -1820,7 +1825,8 @@ unistring_escapes_to_r6rs_escapes (char *buf, size_t *lenp)
size_t nzeros, ndigits;
before = buf;
- after = alloca (max_out_len);
+ malloc_p = (max_out_len > SCM_MAX_ALLOCA);
+ after = malloc_p ? malloc (max_out_len) : alloca (max_out_len);
i = 0;
j = 0;
while (i < *lenp)
@@ -1878,6 +1884,8 @@ unistring_escapes_to_r6rs_escapes (char *buf, size_t *lenp)
}
*lenp = j;
memcpy (before, after, j);
+ if (malloc_p)
+ free (after);
}
char *
@@ -2318,28 +2326,37 @@ normalize_str (SCM string, uninorm_t form)
{
SCM ret;
uint32_t *w_str;
+ uint32_t *w_norm_str;
scm_t_wchar *cbuf;
- size_t rlen, len = scm_i_string_length (string);
+ int malloc_p;
+ size_t norm_len, len = scm_i_string_length (string);
if (scm_i_is_narrow_string (string))
{
- size_t i;
+ size_t i, bytes;
const char *buf = scm_i_string_chars (string);
-
- w_str = alloca (sizeof (scm_t_wchar) * (len + 1));
-
+
+ bytes = (len + 1) * sizeof (scm_t_wchar);
+ malloc_p = (bytes > SCM_MAX_ALLOCA);
+ w_str = malloc_p ? malloc (bytes) : alloca (bytes);
+
for (i = 0; i < len; i ++)
w_str[i] = (unsigned char) buf[i];
w_str[len] = 0;
}
- else
- w_str = (uint32_t *) scm_i_string_wide_chars (string);
+ else
+ {
+ malloc_p = 0;
+ w_str = (uint32_t *) scm_i_string_wide_chars (string);
+ }
- w_str = u32_normalize (form, w_str, len, NULL, &rlen);
-
- ret = scm_i_make_wide_string (rlen, &cbuf, 0);
- u32_cpy ((uint32_t *) cbuf, w_str, rlen);
- free (w_str);
+ w_norm_str = u32_normalize (form, w_str, len, NULL, &norm_len);
+
+ ret = scm_i_make_wide_string (norm_len, &cbuf, 0);
+ u32_cpy ((uint32_t *) cbuf, w_norm_str, norm_len);
+ free (w_norm_str);
+ if (malloc_p)
+ free (w_str);
scm_i_try_narrow_string (ret);