Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6217053

Browse files
committed
Avoid ERRCODE_INTERNAL_ERROR in oracle_compat.c functions.
repeat() checked for integer overflow during its calculation of the required output space, but it just passed the resulting integer to palloc(). This meant that result sizes between 1GB and 2GB led to ERRCODE_INTERNAL_ERROR, "invalid memory alloc request size" rather than ERRCODE_PROGRAM_LIMIT_EXCEEDED, "requested length too large". That seems like a bit of a wart, so add an explicit AllocSizeIsValid check to make these error cases uniform. Do likewise in the sibling functions lpad() etc. While we're here, also modernize their overflow checks to use pg_mul_s32_overflow() etc instead of expensive divisions. Per complaint from Japin Li. This is basically cosmetic, so I don't feel a need to back-patch. Discussion: https://postgr.es/m/ME3P282MB16676ED32167189CB0462173B6D69@ME3P282MB1667.AUSP282.PROD.OUTLOOK.COM
1 parent de89d87 commit 6217053

File tree

1 file changed

+24
-19
lines changed

1 file changed

+24
-19
lines changed

src/backend/utils/adt/oracle_compat.c

+24-19
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "miscadmin.h"
2121
#include "utils/builtins.h"
2222
#include "utils/formatting.h"
23+
#include "utils/memutils.h"
24+
2325

2426
static text *dotrim(const char *string, int stringlen,
2527
const char *set, int setlen,
@@ -155,7 +157,6 @@ lpad(PG_FUNCTION_ARGS)
155157
int m,
156158
s1len,
157159
s2len;
158-
159160
int bytelen;
160161

161162
/* Negative len is silently taken as zero */
@@ -178,15 +179,16 @@ lpad(PG_FUNCTION_ARGS)
178179
if (s2len <= 0)
179180
len = s1len; /* nothing to pad with, so don't pad */
180181

181-
bytelen = pg_database_encoding_max_length() * len;
182-
183-
/* check for integer overflow */
184-
if (len != 0 && bytelen / pg_database_encoding_max_length() != len)
182+
/* compute worst-case output length */
183+
if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
184+
&bytelen)) ||
185+
unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
186+
unlikely(!AllocSizeIsValid(bytelen)))
185187
ereport(ERROR,
186188
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
187189
errmsg("requested length too large")));
188190

189-
ret = (text *) palloc(VARHDRSZ + bytelen);
191+
ret = (text *) palloc(bytelen);
190192

191193
m = len - s1len;
192194

@@ -253,7 +255,6 @@ rpad(PG_FUNCTION_ARGS)
253255
int m,
254256
s1len,
255257
s2len;
256-
257258
int bytelen;
258259

259260
/* Negative len is silently taken as zero */
@@ -276,15 +277,17 @@ rpad(PG_FUNCTION_ARGS)
276277
if (s2len <= 0)
277278
len = s1len; /* nothing to pad with, so don't pad */
278279

279-
bytelen = pg_database_encoding_max_length() * len;
280-
281-
/* Check for integer overflow */
282-
if (len != 0 && bytelen / pg_database_encoding_max_length() != len)
280+
/* compute worst-case output length */
281+
if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
282+
&bytelen)) ||
283+
unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
284+
unlikely(!AllocSizeIsValid(bytelen)))
283285
ereport(ERROR,
284286
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
285287
errmsg("requested length too large")));
286288

287-
ret = (text *) palloc(VARHDRSZ + bytelen);
289+
ret = (text *) palloc(bytelen);
290+
288291
m = len - s1len;
289292

290293
ptr1 = VARDATA_ANY(string1);
@@ -805,7 +808,7 @@ translate(PG_FUNCTION_ARGS)
805808
tolen,
806809
retlen,
807810
i;
808-
int worst_len;
811+
int bytelen;
809812
int len;
810813
int source_len;
811814
int from_index;
@@ -824,15 +827,16 @@ translate(PG_FUNCTION_ARGS)
824827
* The worst-case expansion is to substitute a max-length character for a
825828
* single-byte character at each position of the string.
826829
*/
827-
worst_len = pg_database_encoding_max_length() * m;
828-
829-
/* check for integer overflow */
830-
if (worst_len / pg_database_encoding_max_length() != m)
830+
if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), m,
831+
&bytelen)) ||
832+
unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
833+
unlikely(!AllocSizeIsValid(bytelen)))
831834
ereport(ERROR,
832835
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
833836
errmsg("requested length too large")));
834837

835-
result = (text *) palloc(worst_len + VARHDRSZ);
838+
result = (text *) palloc(bytelen);
839+
836840
target = VARDATA(result);
837841
retlen = 0;
838842

@@ -1128,7 +1132,8 @@ repeat(PG_FUNCTION_ARGS)
11281132
slen = VARSIZE_ANY_EXHDR(string);
11291133

11301134
if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
1131-
unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)))
1135+
unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)) ||
1136+
unlikely(!AllocSizeIsValid(tlen)))
11321137
ereport(ERROR,
11331138
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
11341139
errmsg("requested length too large")));

0 commit comments

Comments
 (0)