]> granicus.if.org Git - postgresql/commitdiff
Modify wchar conversion routines to not fetch the next byte past the end
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Mar 2001 00:24:34 +0000 (00:24 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Mar 2001 00:24:34 +0000 (00:24 +0000)
of a counted input string.  Marinos Yannikos' recent crash report turns
out to be due to applying pg_ascii2wchar_with_len to a TEXT object that
is smack up against the end of memory.  This is the second just-barely-
reproducible bug report I have seen that traces to some bit of code
fetching one more byte than it is allowed to.  Let's be more careful
out there, boys and girls.
While at it, I changed the code to not risk a similar crash when there
is a truncated multibyte character at the end of an input string.  The
output in this case might not be the most reasonable output possible;
if anyone wants to improve it further, step right up...

src/backend/utils/mb/mbutils.c
src/backend/utils/mb/wchar.c

index 0d3d8cb69bd175c5e4e47565ffbc92751beafb71..2abae59d62ba557a906450a707482a5d2e200d77 100644 (file)
@@ -3,7 +3,7 @@
  * client encoding and server internal encoding.
  * (currently mule internal code (mic) is used)
  * Tatsuo Ishii
- * $Id: mbutils.c,v 1.15 2001/02/10 02:31:27 tgl Exp $
+ * $Id: mbutils.c,v 1.16 2001/03/08 00:24:34 tgl Exp $
  */
 #include "postgres.h"
 
@@ -230,7 +230,7 @@ pg_mbstrlen_with_len(const unsigned char *mbstr, int limit)
        int                     len = 0;
        int                     l;
 
-       while (*mbstr && limit > 0)
+       while (limit > 0 && *mbstr)
        {
                l = pg_mblen(mbstr);
                limit -= l;
@@ -252,7 +252,7 @@ pg_mbcliplen(const unsigned char *mbstr, int len, int limit)
        int                     clen = 0;
        int                     l;
 
-       while (*mbstr && len > 0)
+       while (len > 0 && *mbstr)
        {
                l = pg_mblen(mbstr);
                if ((clen + l) > limit)
@@ -267,7 +267,7 @@ pg_mbcliplen(const unsigned char *mbstr, int len, int limit)
 }
 
 /*
- * fuctions for utils/init
+ * functions for utils/init
  */
 static int     DatabaseEncoding = MULTIBYTE;
 
index a4bf1131ad2e14a3550f441b46b63ac6ad855046..6d10cad020a35aee49f408d5a288d37a3f8a3a90 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * conversion functions between pg_wchar and multi-byte streams.
  * Tatsuo Ishii
- * $Id: wchar.c,v 1.15 2001/02/11 01:59:22 ishii Exp $
+ * $Id: wchar.c,v 1.16 2001/03/08 00:24:34 tgl Exp $
  *
  * WIN1250 client encoding updated by Pavel Behal
  *
@@ -27,7 +27,7 @@ static int pg_ascii2wchar_with_len
 {
        int cnt = 0;
 
-       while (*from && len > 0)
+       while (len > 0 && *from)
        {
                *to++ = *from++;
                len--;
@@ -52,23 +52,22 @@ static int pg_euc2wchar_with_len
 {
        int cnt = 0;
 
-       while (*from && len > 0)
+       while (len > 0 && *from)
        {
-               if (*from == SS2)
+               if (*from == SS2 && len >= 2)
                {
                        from++;
-                       len--;
                        *to = 0xff & *from++;
-                       len--;
+                       len -= 2;
                }
-               else if (*from == SS3)
+               else if (*from == SS3 && len >= 3)
                {
                        from++;
                        *to = *from++ << 8;
                        *to |= 0x3f & *from++;
                        len -= 3;
                }
-               else if (*from & 0x80)
+               else if ((*from & 0x80) && len >= 2)
                {
                        *to = *from++ << 8;
                        *to |= *from++;
@@ -140,24 +139,23 @@ static int pg_euccn2wchar_with_len
 {
        int cnt = 0;
 
-       while (*from && len > 0)
+       while (len > 0 && *from)
        {
-               if (*from == SS2)
+               if (*from == SS2 && len >= 3)
                {
                        from++;
-                       len--;
                        *to = 0x3f00 & (*from++ << 8);
                        *to = *from++;
-                       len -= 2;
+                       len -= 3;
                }
-               else if (*from == SS3)
+               else if (*from == SS3 && len >= 3)
                {
                        from++;
                        *to = *from++ << 8;
                        *to |= 0x3f & *from++;
                        len -= 3;
                }
-               else if (*from & 0x80)
+               else if ((*from & 0x80) && len >= 2)
                {
                        *to = *from++ << 8;
                        *to |= *from++;
@@ -195,25 +193,24 @@ static int pg_euctw2wchar_with_len
 {
        int cnt = 0;
 
-       while (*from && len > 0)
+       while (len > 0 && *from)
        {
-               if (*from == SS2)
+               if (*from == SS2 && len >= 4)
                {
                        from++;
-                       len--;
                        *to = *from++ << 16;
                        *to |= *from++ << 8;
                        *to |= *from++;
-                       len -= 3;
+                       len -= 4;
                }
-               else if (*from == SS3)
+               else if (*from == SS3 && len >= 3)
                {
                        from++;
                        *to = *from++ << 8;
                        *to |= 0x3f & *from++;
                        len -= 3;
                }
-               else if (*from & 0x80)
+               else if ((*from & 0x80) && len >= 2)
                {
                        *to = *from++ << 8;
                        *to |= *from++;
@@ -261,30 +258,30 @@ pg_utf2wchar_with_len(const unsigned char *from, pg_wchar * to, int len)
                                c3;
        int cnt = 0;
 
-       while (*from && len > 0)
+       while (len > 0 && *from)
        {
                if ((*from & 0x80) == 0)
                {
                        *to = *from++;
                        len--;
                }
-               else if ((*from & 0xe0) == 0xc0)
+               else if ((*from & 0xe0) == 0xc0 && len >= 2)
                {
                        c1 = *from++ & 0x1f;
                        c2 = *from++ & 0x3f;
-                       len -= 2;
                        *to = c1 << 6;
                        *to |= c2;
+                       len -= 2;
                }
-               else if ((*from & 0xe0) == 0xe0)
+               else if ((*from & 0xe0) == 0xe0 && len >= 3)
                {
                        c1 = *from++ & 0x0f;
                        c2 = *from++ & 0x3f;
                        c3 = *from++ & 0x3f;
-                       len -= 3;
                        *to = c1 << 12;
                        *to |= c2 << 6;
                        *to |= c3;
+                       len -= 3;
                }
                else
                {
@@ -326,29 +323,29 @@ pg_mule2wchar_with_len(const unsigned char *from, pg_wchar * to, int len)
 {
        int cnt = 0;
 
-       while (*from && len > 0)
+       while (len > 0 && *from)
        {
-               if (IS_LC1(*from))
+               if (IS_LC1(*from) && len >= 2)
                {
                        *to = *from++ << 16;
                        *to |= *from++;
                        len -= 2;
                }
-               else if (IS_LCPRV1(*from))
+               else if (IS_LCPRV1(*from) && len >= 3)
                {
                        from++;
                        *to = *from++ << 16;
                        *to |= *from++;
                        len -= 3;
                }
-               else if (IS_LC2(*from))
+               else if (IS_LC2(*from) && len >= 3)
                {
                        *to = *from++ << 16;
                        *to |= *from++ << 8;
                        *to |= *from++;
                        len -= 3;
                }
-               else if (IS_LCPRV2(*from))
+               else if (IS_LCPRV2(*from) && len >= 4)
                {
                        from++;
                        *to = *from++ << 16;
@@ -396,9 +393,10 @@ pg_latin12wchar_with_len(const unsigned char *from, pg_wchar * to, int len)
 {
        int cnt = 0;
 
-       while (*from && len-- > 0)
+       while (len > 0 && *from)
        {
                *to++ = *from++;
+               len--;
                cnt++;
        }
        *to = 0;