pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: a.imamov@postgrespro.ru
To: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: Potential issue in ecpg-informix decimal converting functions
Date: Thu, 22 Feb 2024 19:54:37 +0300
Message-ID: <54d2b53327516d9454daa5fb2f893bdc@postgrespro.ru> (raw)

Hi, everyone!

I found a potential bug in dectoint() and dectolong() functions from
informix.c. "Informix Compatibility Mode" doc chapter says that
ECPG_INFORMIX_NUM_OVERFLOW is returned if an overflow occurred. But
check this line in dectoint() or dectolong() (it is present in both):
if (ret == PGTYPES_NUM_OVERFLOW) - condition is always
false because PGTYPESnumeric_to_int() and PGTYPESnumeric_to_long()
functions return only 0 or -1. So ECPG_INFORMIX_NUM_OVERFLOW can never
be returned.

I think dectoint(), dectolong() and PGTYPESnumeric_to_int() functions
should be a little bit different like in proposing patch.
What do you think?

The flaw was catched with the help of Svace static analyzer.
https://svace.pages.ispras.ru/svace-website/en/

Thank you!

Attachments:

informix_convert_from_decimal.patch (text/x-diff, 5.7K) download diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml index 73351a9136..8390a61cf4 100644 --- a/doc/src/sgml/ecpg.sgml +++ b/doc/src/sgml/ecpg.sgml @@ -8882,7 +8882,7 @@ int dectodbl(decimal *np, double *dblp); <term><function>dectoint</function></term> <listitem> <para> - Convert a variable to type decimal to an integer. + Convert a variable of type decimal to an integer. <synopsis> int dectoint(decimal *np, int *ip); </synopsis> @@ -8892,8 +8892,9 @@ int dectoint(decimal *np, int *ip); </para> <para> On success, 0 is returned and a negative value if the conversion - failed. If an overflow occurred, <literal>ECPG_INFORMIX_NUM_OVERFLOW</literal> - is returned. + failed. If overflow or underflow occurred, the function returns + <literal>ECPG_INFORMIX_NUM_OVERFLOW</literal> or + <literal>ECPG_INFORMIX_NUM_UNDERFLOW</literal> respectively. </para> <para> Note that the ECPG implementation differs from the <productname>Informix</productname> @@ -8908,7 +8909,7 @@ int dectoint(decimal *np, int *ip); <term><function>dectolong</function></term> <listitem> <para> - Convert a variable to type decimal to a long integer. + Convert a variable of type decimal to a long integer. <synopsis> int dectolong(decimal *np, long *lngp); </synopsis> @@ -8918,8 +8919,9 @@ int dectolong(decimal *np, long *lngp); </para> <para> On success, 0 is returned and a negative value if the conversion - failed. If an overflow occurred, <literal>ECPG_INFORMIX_NUM_OVERFLOW</literal> - is returned. + failed. If overflow or underflow occurred, the function returns + <literal>ECPG_INFORMIX_NUM_OVERFLOW</literal> or + <literal>ECPG_INFORMIX_NUM_UNDERFLOW</literal> respectively. </para> <para> Note that the ECPG implementation differs from the <productname>Informix</productname> diff --git a/src/interfaces/ecpg/compatlib/informix.c b/src/interfaces/ecpg/compatlib/informix.c index 80d40aa3e0..73e84bc6e3 100644 --- a/src/interfaces/ecpg/compatlib/informix.c +++ b/src/interfaces/ecpg/compatlib/informix.c @@ -435,6 +435,7 @@ dectoint(decimal *np, int *ip) { int ret; numeric *nres = PGTYPESnumeric_new(); + int errnum = 0; if (nres == NULL) return ECPG_INFORMIX_OUT_OF_MEMORY; @@ -445,11 +446,18 @@ dectoint(decimal *np, int *ip) return ECPG_INFORMIX_OUT_OF_MEMORY; } + errno = 0; ret = PGTYPESnumeric_to_int(nres, ip); + errnum = errno; PGTYPESnumeric_free(nres); - if (ret == PGTYPES_NUM_OVERFLOW) - ret = ECPG_INFORMIX_NUM_OVERFLOW; + if (ret) + { + if (errnum == PGTYPES_NUM_UNDERFLOW) + ret = ECPG_INFORMIX_NUM_UNDERFLOW; + else if (errnum == PGTYPES_NUM_OVERFLOW) + ret = ECPG_INFORMIX_NUM_OVERFLOW; + } return ret; } @@ -459,6 +467,7 @@ dectolong(decimal *np, long *lngp) { int ret; numeric *nres = PGTYPESnumeric_new(); + int errnum = 0; if (nres == NULL) return ECPG_INFORMIX_OUT_OF_MEMORY; @@ -469,11 +478,18 @@ dectolong(decimal *np, long *lngp) return ECPG_INFORMIX_OUT_OF_MEMORY; } + errno = 0; ret = PGTYPESnumeric_to_long(nres, lngp); + errnum = errno; PGTYPESnumeric_free(nres); - if (ret == PGTYPES_NUM_OVERFLOW) - ret = ECPG_INFORMIX_NUM_OVERFLOW; + if (ret) + { + if (errnum == PGTYPES_NUM_UNDERFLOW) + ret = ECPG_INFORMIX_NUM_UNDERFLOW; + else if (errnum == PGTYPES_NUM_OVERFLOW) + ret = ECPG_INFORMIX_NUM_OVERFLOW; + } return ret; } diff --git a/src/interfaces/ecpg/pgtypeslib/numeric.c b/src/interfaces/ecpg/pgtypeslib/numeric.c index 35e7b92da4..52b49e1ce9 100644 --- a/src/interfaces/ecpg/pgtypeslib/numeric.c +++ b/src/interfaces/ecpg/pgtypeslib/numeric.c @@ -1502,7 +1502,12 @@ PGTYPESnumeric_to_int(numeric *nv, int *ip) /* silence compilers that might complain about useless tests */ #if SIZEOF_LONG > SIZEOF_INT - if (l < INT_MIN || l > INT_MAX) + if (l < INT_MIN) + { + errno = PGTYPES_NUM_UNDERFLOW; + return -1; + } + else if(l > INT_MAX) { errno = PGTYPES_NUM_OVERFLOW; return -1; diff --git a/src/interfaces/ecpg/test/expected/compat_informix-dec_test.stdout b/src/interfaces/ecpg/test/expected/compat_informix-dec_test.stdout index 1f8675b3f3..71a5afa4a7 100644 --- a/src/interfaces/ecpg/test/expected/compat_informix-dec_test.stdout +++ b/src/interfaces/ecpg/test/expected/compat_informix-dec_test.stdout @@ -3,8 +3,8 @@ (no errno set) - dec[0,3]: r: -1, * (no errno set) - dec[0,4]: r: -1, * dec[0,5]: r: 0, 0.00 -(errno == PGTYPES_NUM_OVERFLOW) - dec[0,6]: 0 (r: -1) -(errno == PGTYPES_NUM_OVERFLOW) - dec[0,8]: 0 (r: -1) +(errno == PGTYPES_NUM_OVERFLOW) - dec[0,6]: 0 (r: -1200) +(errno == PGTYPES_NUM_OVERFLOW) - dec[0,8]: 0 (r: -1200) (errno == PGTYPES_NUM_OVERFLOW) - dec[0,10]: 0 (r: -1) dec[1,1]: r: 0, -2 @@ -45,8 +45,8 @@ dec[4,2]: r: 0, 592490000000000000000000 dec[4,3]: r: 0, 592490000000000000000000.0 dec[4,4]: r: 0, 592490000000000000000000.00 dec[4,5]: r: 0, 0.00 -(errno == PGTYPES_NUM_OVERFLOW) - dec[4,6]: 0 (r: -1) -(errno == PGTYPES_NUM_OVERFLOW) - dec[4,8]: 0 (r: -1) +(errno == PGTYPES_NUM_OVERFLOW) - dec[4,6]: 0 (r: -1200) +(errno == PGTYPES_NUM_OVERFLOW) - dec[4,8]: 0 (r: -1200) dec[4,10]: 5.9249e+23 (r: 0) dec[5,1]: r: 0, -328400 @@ -141,8 +141,8 @@ dec[13,2]: r: 0, 1234567890123456789012345679 dec[13,3]: r: 0, 1234567890123456789012345678.9 dec[13,4]: r: 0, 1234567890123456789012345678.91 dec[13,5]: r: 0, 0.00 -(errno == PGTYPES_NUM_OVERFLOW) - dec[13,6]: 0 (r: -1) -(errno == PGTYPES_NUM_OVERFLOW) - dec[13,8]: 0 (r: -1) +(errno == PGTYPES_NUM_OVERFLOW) - dec[13,6]: 0 (r: -1200) +(errno == PGTYPES_NUM_OVERFLOW) - dec[13,8]: 0 (r: -1200) dec[13,10]: 1.23457e+27 (r: 0) (errno == PGTYPES_NUM_OVERFLOW) - dec[14,0]: r: -1200

view thread (12+ messages)  latest in thread

Message-ID: <54d2b53327516d9454daa5fb2f893bdc@postgrespro.ru>
Permalink:  ../54d2b53327516d9454daa5fb2f893bdc@postgrespro.ru/
Also on:    postgresql.org/message-id/54d2b53327516d9454daa5fb2f893bdc@postgrespro.ru

 ·  · 

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: a.imamov@postgrespro.ru, pgsql-hackers@lists.postgresql.org
  Subject: Re: Potential issue in ecpg-informix decimal converting functions
  In-Reply-To: <54d2b53327516d9454daa5fb2f893bdc@postgrespro.ru>

* 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