1313#include "utils/builtins.h"
1414#include "utils/json.h"
1515#include "utils/lsyscache.h"
16+ #include "utils/memutils.h"
1617#include "utils/typcache.h"
1718
1819#include "hstore.h"
@@ -439,6 +440,11 @@ hstore_recv(PG_FUNCTION_ARGS)
439440 PG_RETURN_POINTER (out );
440441 }
441442
443+ if (pcount < 0 || pcount > MaxAllocSize / sizeof (Pairs ))
444+ ereport (ERROR ,
445+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
446+ errmsg ("number of pairs (%d) exceeds the maximum allowed (%d)" ,
447+ pcount , (int ) (MaxAllocSize / sizeof (Pairs )))));
442448 pairs = palloc (pcount * sizeof (Pairs ));
443449
444450 for (i = 0 ; i < pcount ; ++ i )
@@ -554,6 +560,13 @@ hstore_from_arrays(PG_FUNCTION_ARGS)
554560 TEXTOID , -1 , false, 'i' ,
555561 & key_datums , & key_nulls , & key_count );
556562
563+ /* see discussion in hstoreArrayToPairs() */
564+ if (key_count > MaxAllocSize / sizeof (Pairs ))
565+ ereport (ERROR ,
566+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
567+ errmsg ("number of pairs (%d) exceeds the maximum allowed (%d)" ,
568+ key_count , (int ) (MaxAllocSize / sizeof (Pairs )))));
569+
557570 /* value_array might be NULL */
558571
559572 if (PG_ARGISNULL (1 ))
@@ -676,6 +689,13 @@ hstore_from_array(PG_FUNCTION_ARGS)
676689
677690 count = in_count / 2 ;
678691
692+ /* see discussion in hstoreArrayToPairs() */
693+ if (count > MaxAllocSize / sizeof (Pairs ))
694+ ereport (ERROR ,
695+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
696+ errmsg ("number of pairs (%d) exceeds the maximum allowed (%d)" ,
697+ count , (int ) (MaxAllocSize / sizeof (Pairs )))));
698+
679699 pairs = palloc (count * sizeof (Pairs ));
680700
681701 for (i = 0 ; i < count ; ++ i )
@@ -807,6 +827,7 @@ hstore_from_record(PG_FUNCTION_ARGS)
807827 my_extra -> ncolumns = ncolumns ;
808828 }
809829
830+ Assert (ncolumns <= MaxTupleAttributeNumber ); /* thus, no overflow */
810831 pairs = palloc (ncolumns * sizeof (Pairs ));
811832
812833 if (rec )
@@ -1224,77 +1245,49 @@ Datum
12241245hstore_to_json_loose (PG_FUNCTION_ARGS )
12251246{
12261247 HStore * in = PG_GETARG_HS (0 );
1227- int buflen ,
1228- i ;
1248+ int i ;
12291249 int count = HS_COUNT (in );
1230- char * out ,
1231- * ptr ;
12321250 char * base = STRPTR (in );
12331251 HEntry * entries = ARRPTR (in );
12341252 bool is_number ;
1235- StringInfo src ,
1253+ StringInfoData tmp ,
12361254 dst ;
12371255
12381256 if (count == 0 )
12391257 PG_RETURN_TEXT_P (cstring_to_text_with_len ("{}" ,2 ));
12401258
1241- buflen = 3 ;
1242-
1243- /*
1244- * Formula adjusted slightly from the logic in hstore_out. We have to take
1245- * account of out treatment of booleans to be a bit more pessimistic about
1246- * the length of values.
1247- */
1248-
1249- for (i = 0 ; i < count ; i ++ )
1250- {
1251- /* include "" and colon-space and comma-space */
1252- buflen += 6 + 2 * HS_KEYLEN (entries , i );
1253- /* include "" only if nonnull */
1254- buflen += 3 + (HS_VALISNULL (entries , i )
1255- ? 1
1256- : 2 * HS_VALLEN (entries , i ));
1257- }
1259+ initStringInfo (& tmp );
1260+ initStringInfo (& dst );
12581261
1259- out = ptr = palloc (buflen );
1260-
1261- src = makeStringInfo ();
1262- dst = makeStringInfo ();
1263-
1264- * ptr ++ = '{' ;
1262+ appendStringInfoChar (& dst , '{' );
12651263
12661264 for (i = 0 ; i < count ; i ++ )
12671265 {
1268- resetStringInfo (src );
1269- resetStringInfo (dst );
1270- appendBinaryStringInfo (src , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1271- escape_json (dst , src -> data );
1272- strncpy (ptr , dst -> data , dst -> len );
1273- ptr += dst -> len ;
1274- * ptr ++ = ':' ;
1275- * ptr ++ = ' ' ;
1276- resetStringInfo (dst );
1266+ resetStringInfo (& tmp );
1267+ appendBinaryStringInfo (& tmp , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1268+ escape_json (& dst , tmp .data );
1269+ appendStringInfoString (& dst , ": " );
12771270 if (HS_VALISNULL (entries , i ))
1278- appendStringInfoString (dst , "null" );
1271+ appendStringInfoString (& dst , "null" );
12791272 /* guess that values of 't' or 'f' are booleans */
12801273 else if (HS_VALLEN (entries , i ) == 1 && * (HS_VAL (entries , base , i )) == 't' )
1281- appendStringInfoString (dst , "true" );
1274+ appendStringInfoString (& dst , "true" );
12821275 else if (HS_VALLEN (entries , i ) == 1 && * (HS_VAL (entries , base , i )) == 'f' )
1283- appendStringInfoString (dst , "false" );
1276+ appendStringInfoString (& dst , "false" );
12841277 else
12851278 {
12861279 is_number = false;
1287- resetStringInfo (src );
1288- appendBinaryStringInfo (src , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
1280+ resetStringInfo (& tmp );
1281+ appendBinaryStringInfo (& tmp , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
12891282
12901283 /*
12911284 * don't treat something with a leading zero followed by another
12921285 * digit as numeric - could be a zip code or similar
12931286 */
1294- if (src -> len > 0 &&
1295- !(src -> data [0 ] == '0' &&
1296- isdigit ((unsigned char ) src -> data [1 ])) &&
1297- strspn (src -> data , "+-0123456789Ee." ) == src -> len )
1287+ if (tmp . len > 0 &&
1288+ !(tmp . data [0 ] == '0' &&
1289+ isdigit ((unsigned char ) tmp . data [1 ])) &&
1290+ strspn (tmp . data , "+-0123456789Ee." ) == tmp . len )
12981291 {
12991292 /*
13001293 * might be a number. See if we can input it as a numeric
@@ -1303,7 +1296,7 @@ hstore_to_json_loose(PG_FUNCTION_ARGS)
13031296 char * endptr = "junk" ;
13041297 long lval ;
13051298
1306- lval = strtol (src -> data , & endptr , 10 );
1299+ lval = strtol (tmp . data , & endptr , 10 );
13071300 (void ) lval ;
13081301 if (* endptr == '\0' )
13091302 {
@@ -1318,30 +1311,24 @@ hstore_to_json_loose(PG_FUNCTION_ARGS)
13181311 /* not an int - try a double */
13191312 double dval ;
13201313
1321- dval = strtod (src -> data , & endptr );
1314+ dval = strtod (tmp . data , & endptr );
13221315 (void ) dval ;
13231316 if (* endptr == '\0' )
13241317 is_number = true;
13251318 }
13261319 }
13271320 if (is_number )
1328- appendBinaryStringInfo (dst , src -> data , src -> len );
1321+ appendBinaryStringInfo (& dst , tmp . data , tmp . len );
13291322 else
1330- escape_json (dst , src -> data );
1323+ escape_json (& dst , tmp . data );
13311324 }
1332- strncpy (ptr , dst -> data , dst -> len );
1333- ptr += dst -> len ;
13341325
13351326 if (i + 1 != count )
1336- {
1337- * ptr ++ = ',' ;
1338- * ptr ++ = ' ' ;
1339- }
1327+ appendStringInfoString (& dst , ", " );
13401328 }
1341- * ptr ++ = '}' ;
1342- * ptr = '\0' ;
1329+ appendStringInfoChar (& dst , '}' );
13431330
1344- PG_RETURN_TEXT_P (cstring_to_text (out ));
1331+ PG_RETURN_TEXT_P (cstring_to_text (dst . data ));
13451332}
13461333
13471334PG_FUNCTION_INFO_V1 (hstore_to_json );
@@ -1350,74 +1337,40 @@ Datum
13501337hstore_to_json (PG_FUNCTION_ARGS )
13511338{
13521339 HStore * in = PG_GETARG_HS (0 );
1353- int buflen ,
1354- i ;
1340+ int i ;
13551341 int count = HS_COUNT (in );
1356- char * out ,
1357- * ptr ;
13581342 char * base = STRPTR (in );
13591343 HEntry * entries = ARRPTR (in );
1360- StringInfo src ,
1344+ StringInfoData tmp ,
13611345 dst ;
13621346
13631347 if (count == 0 )
13641348 PG_RETURN_TEXT_P (cstring_to_text_with_len ("{}" ,2 ));
13651349
1366- buflen = 3 ;
1350+ initStringInfo (& tmp );
1351+ initStringInfo (& dst );
13671352
1368- /*
1369- * Formula adjusted slightly from the logic in hstore_out. We have to take
1370- * account of out treatment of booleans to be a bit more pessimistic about
1371- * the length of values.
1372- */
1353+ appendStringInfoChar (& dst , '{' );
13731354
13741355 for (i = 0 ; i < count ; i ++ )
13751356 {
1376- /* include "" and colon-space and comma-space */
1377- buflen += 6 + 2 * HS_KEYLEN (entries , i );
1378- /* include "" only if nonnull */
1379- buflen += 3 + (HS_VALISNULL (entries , i )
1380- ? 1
1381- : 2 * HS_VALLEN (entries , i ));
1382- }
1383-
1384- out = ptr = palloc (buflen );
1385-
1386- src = makeStringInfo ();
1387- dst = makeStringInfo ();
1388-
1389- * ptr ++ = '{' ;
1390-
1391- for (i = 0 ; i < count ; i ++ )
1392- {
1393- resetStringInfo (src );
1394- resetStringInfo (dst );
1395- appendBinaryStringInfo (src , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1396- escape_json (dst , src -> data );
1397- strncpy (ptr , dst -> data , dst -> len );
1398- ptr += dst -> len ;
1399- * ptr ++ = ':' ;
1400- * ptr ++ = ' ' ;
1401- resetStringInfo (dst );
1357+ resetStringInfo (& tmp );
1358+ appendBinaryStringInfo (& tmp , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1359+ escape_json (& dst , tmp .data );
1360+ appendStringInfoString (& dst , ": " );
14021361 if (HS_VALISNULL (entries , i ))
1403- appendStringInfoString (dst , "null" );
1362+ appendStringInfoString (& dst , "null" );
14041363 else
14051364 {
1406- resetStringInfo (src );
1407- appendBinaryStringInfo (src , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
1408- escape_json (dst , src -> data );
1365+ resetStringInfo (& tmp );
1366+ appendBinaryStringInfo (& tmp , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
1367+ escape_json (& dst , tmp . data );
14091368 }
1410- strncpy (ptr , dst -> data , dst -> len );
1411- ptr += dst -> len ;
14121369
14131370 if (i + 1 != count )
1414- {
1415- * ptr ++ = ',' ;
1416- * ptr ++ = ' ' ;
1417- }
1371+ appendStringInfoString (& dst , ", " );
14181372 }
1419- * ptr ++ = '}' ;
1420- * ptr = '\0' ;
1373+ appendStringInfoChar (& dst , '}' );
14211374
1422- PG_RETURN_TEXT_P (cstring_to_text (out ));
1375+ PG_RETURN_TEXT_P (cstring_to_text (dst . data ));
14231376}
0 commit comments