Skip to content

Commit fbb1dae

Browse files
committed
Fix incorrect addition, subtraction, and overflow checking in new
inet operators.
1 parent 77bb65d commit fbb1dae

File tree

4 files changed

+374
-263
lines changed

4 files changed

+374
-263
lines changed

src/backend/utils/adt/network.c

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* PostgreSQL type definitions for the INET and CIDR types.
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.64 2006/02/11 03:32:39 momjian Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.65 2006/02/11 20:39:58 tgl Exp $
55
*
66
* Jon Postel RIP 16 Oct 1998
77
*/
@@ -27,7 +27,7 @@ static int32 network_cmp_internal(inet *a1, inet *a2);
2727
static int bitncmp(void *l, void *r, int n);
2828
static bool addressOK(unsigned char *a, int bits, int family);
2929
static int ip_addrsize(inet *inetptr);
30-
static Datum internal_inetpl(inet *ip, int64 iarg);
30+
static inet *internal_inetpl(inet *ip, int64 addend);
3131

3232
/*
3333
* Access macros.
@@ -1292,8 +1292,7 @@ inetand(PG_FUNCTION_ARGS)
12921292
if (ip_family(ip) != ip_family(ip2))
12931293
ereport(ERROR,
12941294
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1295-
errmsg("mismatch in address family (%d) != (%d)",
1296-
ip_family(ip), ip_family(ip2))));
1295+
errmsg("cannot AND inet values of different sizes")));
12971296
else
12981297
{
12991298
int nb = ip_addrsize(ip);
@@ -1327,8 +1326,7 @@ inetor(PG_FUNCTION_ARGS)
13271326
if (ip_family(ip) != ip_family(ip2))
13281327
ereport(ERROR,
13291328
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1330-
errmsg("mismatch in address family (%d) != (%d)",
1331-
ip_family(ip), ip_family(ip2))));
1329+
errmsg("cannot OR inet values of different sizes")));
13321330
else
13331331
{
13341332
int nb = ip_addrsize(ip);
@@ -1350,8 +1348,8 @@ inetor(PG_FUNCTION_ARGS)
13501348
}
13511349

13521350

1353-
static Datum
1354-
internal_inetpl(inet *ip, int64 plus)
1351+
static inet *
1352+
internal_inetpl(inet *ip, int64 addend)
13551353
{
13561354
inet *dst;
13571355

@@ -1365,15 +1363,31 @@ internal_inetpl(inet *ip, int64 plus)
13651363

13661364
while (nb-- > 0)
13671365
{
1368-
pdst[nb] = carry = pip[nb] + plus + carry;
1369-
plus /= 0x100; /* process next byte */
1370-
carry /= 0x100; /* remove low byte */
1371-
/* Overflow on high byte? */
1372-
if (nb == 0 && (plus != 0 || carry != 0))
1373-
ereport(ERROR,
1374-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1375-
errmsg("result out of range")));
1366+
carry = pip[nb] + (int) (addend & 0xFF) + carry;
1367+
pdst[nb] = (unsigned char) (carry & 0xFF);
1368+
carry >>= 8;
1369+
/*
1370+
* We have to be careful about right-shifting addend because
1371+
* right-shift isn't portable for negative values, while
1372+
* simply dividing by 256 doesn't work (the standard rounding
1373+
* is in the wrong direction, besides which there may be machines
1374+
* out there that round the wrong way). So, explicitly clear
1375+
* the low-order byte to remove any doubt about the correct
1376+
* result of the division, and then divide rather than shift.
1377+
*/
1378+
addend &= ~((int64) 0xFF);
1379+
addend /= 0x100;
13761380
}
1381+
/*
1382+
* At this point we should have addend and carry both zero if
1383+
* original addend was >= 0, or addend -1 and carry 1 if original
1384+
* addend was < 0. Anything else means overflow.
1385+
*/
1386+
if (!((addend == 0 && carry == 0) ||
1387+
(addend == -1 && carry == 1)))
1388+
ereport(ERROR,
1389+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1390+
errmsg("result out of range")));
13771391
}
13781392
ip_bits(dst) = ip_bits(ip);
13791393

@@ -1382,27 +1396,27 @@ internal_inetpl(inet *ip, int64 plus)
13821396
((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
13831397
ip_addrsize(dst);
13841398

1385-
PG_RETURN_INET_P(dst);
1399+
return dst;
13861400
}
13871401

13881402

13891403
Datum
13901404
inetpl(PG_FUNCTION_ARGS)
13911405
{
13921406
inet *ip = PG_GETARG_INET_P(0);
1393-
int64 plus = PG_GETARG_INT64(1);
1407+
int64 addend = PG_GETARG_INT64(1);
13941408

1395-
return internal_inetpl(ip, plus);
1409+
PG_RETURN_INET_P(internal_inetpl(ip, addend));
13961410
}
13971411

13981412

13991413
Datum
14001414
inetmi_int8(PG_FUNCTION_ARGS)
14011415
{
14021416
inet *ip = PG_GETARG_INET_P(0);
1403-
int64 plus = PG_GETARG_INT64(1);
1417+
int64 addend = PG_GETARG_INT64(1);
14041418

1405-
return internal_inetpl(ip, -plus);
1419+
PG_RETURN_INET_P(internal_inetpl(ip, -addend));
14061420
}
14071421

14081422

@@ -1416,42 +1430,53 @@ inetmi(PG_FUNCTION_ARGS)
14161430
if (ip_family(ip) != ip_family(ip2))
14171431
ereport(ERROR,
14181432
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1419-
errmsg("mismatch in address family (%d) != (%d)",
1420-
ip_family(ip), ip_family(ip2))));
1433+
errmsg("cannot subtract inet values of different sizes")));
14211434
else
14221435
{
1436+
/*
1437+
* We form the difference using the traditional complement,
1438+
* increment, and add rule, with the increment part being handled
1439+
* by starting the carry off at 1. If you don't think integer
1440+
* arithmetic is done in two's complement, too bad.
1441+
*/
14231442
int nb = ip_addrsize(ip);
14241443
int byte = 0;
14251444
unsigned char *pip = ip_addr(ip);
14261445
unsigned char *pip2 = ip_addr(ip2);
1446+
int carry = 1;
14271447

14281448
while (nb-- > 0)
14291449
{
1430-
/*
1431-
* Error if overflow on last byte. This test is tricky
1432-
* because if the subtraction == 128 and res is negative, or
1433-
* if subtraction == -128 and res is positive, the result
1434-
* would still fit in int64.
1435-
*/
1436-
if (byte + 1 == sizeof(int64) &&
1437-
(pip[nb] - pip2[nb] >= 128 + (res < 0) ||
1438-
pip[nb] - pip2[nb] <= -128 - (res > 0)))
1439-
ereport(ERROR,
1440-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1441-
errmsg("result out of range")));
1442-
if (byte >= sizeof(int64))
1450+
int lobyte;
1451+
1452+
carry = pip[nb] + (~pip2[nb] & 0xFF) + carry;
1453+
lobyte = carry & 0xFF;
1454+
if (byte < sizeof(int64))
14431455
{
1444-
/* Error if bytes beyond int64 length differ. */
1445-
if (pip[nb] != pip2[nb])
1456+
res |= ((int64) lobyte) << (byte * 8);
1457+
}
1458+
else
1459+
{
1460+
/*
1461+
* Input wider than int64: check for overflow. All bytes
1462+
* to the left of what will fit should be 0 or 0xFF,
1463+
* depending on sign of the now-complete result.
1464+
*/
1465+
if ((res < 0) ? (lobyte != 0xFF) : (lobyte != 0))
14461466
ereport(ERROR,
14471467
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
14481468
errmsg("result out of range")));
14491469
}
1450-
else
1451-
res += (int64)(pip[nb] - pip2[nb]) << (byte * 8);
1452-
1470+
carry >>= 8;
14531471
byte++;
14541472
}
1473+
1474+
/*
1475+
* If input is narrower than int64, overflow is not possible, but
1476+
* we have to do proper sign extension.
1477+
*/
1478+
if (carry == 0 && byte < sizeof(int64))
1479+
res |= ((int64) -1) << (byte * 8);
14551480
}
14561481

14571482
PG_RETURN_INT64(res);

src/include/catalog/pg_proc.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.395 2006/02/11 03:32:39 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.396 2006/02/11 20:39:58 tgl Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -2297,7 +2297,7 @@ DESCR("bitwise or");
22972297
DATA(insert OID = 1675 ( bitxor PGNSP PGUID 12 f f t f i 2 1560 "1560 1560" _null_ _null_ _null_ bitxor - _null_ ));
22982298
DESCR("bitwise exclusive or");
22992299
DATA(insert OID = 1676 ( bitnot PGNSP PGUID 12 f f t f i 1 1560 "1560" _null_ _null_ _null_ bitnot - _null_ ));
2300-
DESCR("bitwise negation");
2300+
DESCR("bitwise not");
23012301
DATA(insert OID = 1677 ( bitshiftleft PGNSP PGUID 12 f f t f i 2 1560 "1560 23" _null_ _null_ _null_ bitshiftleft - _null_ ));
23022302
DESCR("bitwise left shift");
23032303
DATA(insert OID = 1678 ( bitshiftright PGNSP PGUID 12 f f t f i 2 1560 "1560 23" _null_ _null_ _null_ bitshiftright - _null_ ));
@@ -2423,28 +2423,28 @@ DATA(insert OID = 1715 ( cidr PGNSP PGUID 12 f f t f i 1 650 "869" _null_ _n
24232423
DESCR("coerce inet to cidr");
24242424

24252425
DATA(insert OID = 2196 ( inet_client_addr PGNSP PGUID 12 f f f f s 0 869 "" _null_ _null_ _null_ inet_client_addr - _null_ ));
2426-
DESCR("INET address of the client");
2426+
DESCR("inet address of the client");
24272427
DATA(insert OID = 2197 ( inet_client_port PGNSP PGUID 12 f f f f s 0 23 "" _null_ _null_ _null_ inet_client_port - _null_ ));
24282428
DESCR("client's port number for this connection");
24292429
DATA(insert OID = 2198 ( inet_server_addr PGNSP PGUID 12 f f f f s 0 869 "" _null_ _null_ _null_ inet_server_addr - _null_ ));
2430-
DESCR("INET address of the server");
2430+
DESCR("inet address of the server");
24312431
DATA(insert OID = 2199 ( inet_server_port PGNSP PGUID 12 f f f f s 0 23 "" _null_ _null_ _null_ inet_server_port - _null_ ));
24322432
DESCR("server's port number for this connection");
24332433

24342434
DATA(insert OID = 2627 ( inetnot PGNSP PGUID 12 f f t f i 1 869 "869" _null_ _null_ _null_ inetnot - _null_ ));
2435-
DESCR("binary NOT");
2435+
DESCR("bitwise not");
24362436
DATA(insert OID = 2628 ( inetand PGNSP PGUID 12 f f t f i 2 869 "869 869" _null_ _null_ _null_ inetand - _null_ ));
2437-
DESCR("binary AND");
2437+
DESCR("bitwise and");
24382438
DATA(insert OID = 2629 ( inetor PGNSP PGUID 12 f f t f i 2 869 "869 869" _null_ _null_ _null_ inetor - _null_ ));
2439-
DESCR("binary OR");
2439+
DESCR("bitwise or");
24402440
DATA(insert OID = 2630 ( inetpl PGNSP PGUID 12 f f t f i 2 869 "869 20" _null_ _null_ _null_ inetpl - _null_ ));
2441-
DESCR("add integer to INET value");
2442-
DATA(insert OID = 2631 ( int8pl_inet PGNSP PGUID 14 f f t f i 2 869 "20 869" _null_ _null_ _null_ "select $2 + $1" - _null_ ));
2443-
DESCR("add integer to INET value");
2441+
DESCR("add integer to inet value");
2442+
DATA(insert OID = 2631 ( int8pl_inet PGNSP PGUID 14 f f t f i 2 869 "20 869" _null_ _null_ _null_ "select $2 + $1" - _null_ ));
2443+
DESCR("add integer to inet value");
24442444
DATA(insert OID = 2632 ( inetmi_int8 PGNSP PGUID 12 f f t f i 2 869 "869 20" _null_ _null_ _null_ inetmi_int8 - _null_ ));
2445-
DESCR("subtract integer from INET value");
2445+
DESCR("subtract integer from inet value");
24462446
DATA(insert OID = 2633 ( inetmi PGNSP PGUID 12 f f t f i 2 20 "869 869" _null_ _null_ _null_ inetmi - _null_ ));
2447-
DESCR("subtract INET values");
2447+
DESCR("subtract inet values");
24482448

24492449
DATA(insert OID = 1686 ( numeric PGNSP PGUID 12 f f t f i 1 1700 "25" _null_ _null_ _null_ text_numeric - _null_ ));
24502450
DESCR("(internal)");

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy