From f1298df3676b29354423d4975c57ece7bd3b6dc9 Mon Sep 17 00:00:00 2001 From: Arne Goedeke <el@laramies.com> Date: Wed, 2 Jul 2014 18:43:19 +0200 Subject: [PATCH] Strings: correctly store character ranges Character ranges of strings are stored in two unsigned chars. For wide strings, the values between 0 and 255 represent blocks of 255 and (1<<24) characters, respectively. The previous code had several issues: 1) After calculating the actual min/max values of the character range, these value were rounded up, which could lead to an overflow. The result was that both min and max could end up being 0. An example is the string (string)({ (1<<16)-1 }). 2) The 32 bit case used blocks of 16 bit instead of 24 bit. --- src/stralloc.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/stralloc.c b/src/stralloc.c index 262c3f7d56..71d0aa4048 100644 --- a/src/stralloc.c +++ b/src/stralloc.c @@ -102,16 +102,31 @@ PMOD_EXPORT void check_string_range( struct pike_string *str, { if( str->flags & STRING_CONTENT_CHECKED ) { - s_min = str->min; - s_max = str->max; - - if( str->size_shift ) - { - s_min <<= 8 * str->size_shift; - s_max <<= 8 * str->size_shift; - if( s_min ) - s_min -= (1<<(8*str->size_shift))-1; - s_max += str->size_shift == 1 ? 255 : 65535; + switch (str->size_shift) { + case eightbit: + s_min = str->min; + s_max = str->max; + break; + case sixteenbit: + s_min = str->min; + s_max = str->max; + s_min *= 256; + s_max *= 256; + s_max += 255; + break; + case thirtytwobit: { + unsigned INT32 tmp; + + tmp = str->min; + tmp *= (1 << 24); + s_min = tmp; + + tmp = str->max; + tmp *= (1 << 24); + tmp += (1 << 24) - 1; + s_max = tmp; + break; + } } } else @@ -167,8 +182,8 @@ PMOD_EXPORT void check_string_range( struct pike_string *str, if( *p < s_min ) s_min = *p; } } - str->min = (s_min+255) >> 8; - str->max = (s_max+255) >> 8; + str->min = s_min / 256; + str->max = s_max / 256; break; case 2: @@ -180,8 +195,8 @@ PMOD_EXPORT void check_string_range( struct pike_string *str, if( *p < s_min ) s_min = *p; } } - str->min = (s_min+65535) >> 16; - str->max = (s_max+65535) >> 16; + str->min = (unsigned INT32)s_min / (1 << 24); + str->max = (unsigned INT32)s_max / (1 << 24); break; } } -- GitLab