pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: movead.li@highgo.ca <movead.li@highgo.ca>
To: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Cc: pgsql-hackers <pgsql-hackers@lists.postgresql.org>
Cc: ashutosh.bapat <ashutosh.bapat@2ndquadrant.com>
Subject: Re: Re: A bug when use get_bit() function for a long bytea string
Date: Fri, 13 Mar 2020 11:18:47 +0800
Message-ID: <20200313111842791351178@highgo.ca> (raw)
References: <20200312115135445367128@highgo.ca>
	<CAExHW5vUSi4-oPvgMdFWvzuyaTmMtbY=JgdZ+u3T7ZdzQmubig@mail.gmail.com>

Thanks for the reply.

>Why have you used size? Shouldn't we use int64?
Yes, thanks for the point, I have changed the patch.
 
>If get_bit()/set_bit() accept the second argument as int32, it can not
>be used to set bits whose number does not fit 32 bits. I think we need
>to change the type of the second argument as well.
Because int32 can cover the length of bytea that PostgreSQL support,
and I have decided to follow your next point 'not use 64bit int for len',
so I think the second argument can keep int32.

>Also, I think declaring len to be int is fine since 1G would fit an
>int, but what does not fit is len * 8, when performing that
>calculation, we have to widen the result. So, instead of changing the
>datatype of len, it might be better to perform the calculation as
>(int64)len * 8. If we use int64, we could also use INT64_FORMAT
>instead of using %ld.
Have followed and changed the patch.
 
>Since this is a bug it shouldn't wait another commitfest, but still
>add this patch to the commitfest so that it's not forgotten.
Will do.



Highgo Software (Canada/China/Pakistan) 
URL : www.highgo.ca 
EMAIL: mailto:movead(dot)li(at)highgo(dot)ca


Attachments:

  [application/octet-stream] long_bytea_string_bug_fix_ver2.patch (4.8K, ../20200313111842791351178@highgo.ca/3-long_bytea_string_bug_fix_ver2.patch)
  download | inline diff:
diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c
index b8d9ec7e00..e56ebd707d 100644
--- a/src/backend/utils/adt/encode.c
+++ b/src/backend/utils/adt/encode.c
@@ -20,7 +20,7 @@
 
 struct pg_encoding
 {
-	unsigned	(*encode_len) (const char *data, unsigned dlen);
+	int64		(*encode_len) (const char *data, unsigned dlen);
 	unsigned	(*decode_len) (const char *data, unsigned dlen);
 	unsigned	(*encode) (const char *data, unsigned dlen, char *res);
 	unsigned	(*decode) (const char *data, unsigned dlen, char *res);
@@ -40,8 +40,8 @@ binary_encode(PG_FUNCTION_ARGS)
 	text	   *result;
 	char	   *namebuf;
 	int			datalen,
-				resultlen,
 				res;
+	int64		resultlen;
 	const struct pg_encoding *enc;
 
 	datalen = VARSIZE_ANY_EXHDR(data);
@@ -60,7 +60,7 @@ binary_encode(PG_FUNCTION_ARGS)
 	res = enc->encode(VARDATA_ANY(data), datalen, VARDATA(result));
 
 	/* Make this FATAL 'cause we've trodden on memory ... */
-	if (res > resultlen)
+	if ((int64)res > resultlen)
 		elog(FATAL, "overflow - encode estimate too small");
 
 	SET_VARSIZE(result, VARHDRSZ + res);
@@ -76,8 +76,8 @@ binary_decode(PG_FUNCTION_ARGS)
 	bytea	   *result;
 	char	   *namebuf;
 	int			datalen,
-				resultlen,
 				res;
+	unsigned	resultlen;
 	const struct pg_encoding *enc;
 
 	datalen = VARSIZE_ANY_EXHDR(data);
@@ -184,10 +184,10 @@ hex_decode(const char *src, unsigned len, char *dst)
 	return p - dst;
 }
 
-static unsigned
+static int64
 hex_enc_len(const char *src, unsigned srclen)
 {
-	return srclen << 1;
+	return (int64)(srclen << 1);
 }
 
 static unsigned
@@ -331,11 +331,11 @@ pg_base64_decode(const char *src, unsigned len, char *dst)
 }
 
 
-static unsigned
+static int64
 pg_base64_enc_len(const char *src, unsigned srclen)
 {
 	/* 3 bytes will be converted to 4, linefeed after 76 chars */
-	return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
+	return (int64)((srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4));
 }
 
 static unsigned
@@ -448,11 +448,11 @@ esc_decode(const char *src, unsigned srclen, char *dst)
 	return len;
 }
 
-static unsigned
+static int64
 esc_enc_len(const char *src, unsigned srclen)
 {
 	const char *end = src + srclen;
-	int			len = 0;
+	int64		len = 0;
 
 	while (src < end)
 	{
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 907b5ab7b0..b8b06d5e32 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -388,7 +388,7 @@ byteaout(PG_FUNCTION_ARGS)
 	{
 		/* Print traditional escaped format */
 		char	   *vp;
-		int			len;
+		int64		len;
 		int			i;
 
 		len = 1;				/* empty string has 1 char */
@@ -3463,11 +3463,11 @@ byteaGetBit(PG_FUNCTION_ARGS)
 
 	len = VARSIZE_ANY_EXHDR(v);
 
-	if (n < 0 || n >= len * 8)
+	if (n < 0 || (int64)n >= (int64)len * 8)
 		ereport(ERROR,
 				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
-				 errmsg("index %d out of valid range, 0..%d",
-						n, len * 8 - 1)));
+				 errmsg("index %d out of valid range, 0.."INT64_FORMAT,
+						n, (int64)len * 8 - 1)));
 
 	byteNo = n / 8;
 	bitNo = n % 8;
@@ -3534,11 +3534,11 @@ byteaSetBit(PG_FUNCTION_ARGS)
 
 	len = VARSIZE(res) - VARHDRSZ;
 
-	if (n < 0 || n >= len * 8)
+	if (n < 0 || (int64)n >= (int64)len * 8)
 		ereport(ERROR,
 				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
-				 errmsg("index %d out of valid range, 0..%d",
-						n, len * 8 - 1)));
+				 errmsg("index %d out of valid range, 0.."INT64_FORMAT,
+						n, (int64)len * 8 - 1)));
 
 	byteNo = n / 8;
 	bitNo = n % 8;
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index a1fab7ebcb..f7fda19b97 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -656,6 +656,22 @@ SELECT set_bit(B'0101011000100100', 15, 1);
 
 SELECT set_bit(B'0101011000100100', 16, 1);	-- fail
 ERROR:  bit index 16 out of valid range (0..15)
+SELECT get_bit(
+       set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 0)
+       ,0);
+ get_bit 
+---------
+       0
+(1 row)
+
+SELECT get_bit(
+       set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 1)
+       ,0);
+ get_bit 
+---------
+       1
+(1 row)
+
 -- Overlay
 SELECT overlay(B'0101011100' placing '001' from 2 for 3);
   overlay   
diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql
index 7681d4ab4d..89323d98e8 100644
--- a/src/test/regress/sql/bit.sql
+++ b/src/test/regress/sql/bit.sql
@@ -200,6 +200,13 @@ DROP TABLE VARBIT_SHIFT_TABLE;
 SELECT get_bit(B'0101011000100', 10);
 SELECT set_bit(B'0101011000100100', 15, 1);
 SELECT set_bit(B'0101011000100100', 16, 1);	-- fail
+SELECT get_bit(
+       set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 0)
+       ,0);
+SELECT get_bit(
+       set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 1)
+       ,0);
+
 
 -- Overlay
 SELECT overlay(B'0101011100' placing '001' from 2 for 3);


view thread (27+ messages)  latest in thread

Message-ID: <20200313111842791351178@highgo.ca>
Permalink:  ../20200313111842791351178@highgo.ca/
Also on:    postgresql.org/message-id/20200313111842791351178@highgo.ca

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: movead.li@highgo.ca, ashutosh.bapat.oss@gmail.com, pgsql-hackers@lists.postgresql.org, ashutosh.bapat@2ndquadrant.com
  Subject: Re: Re: A bug when use get_bit() function for a long bytea string
  In-Reply-To: <20200313111842791351178@highgo.ca>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox