Question about ECPGset_noind_null() and ECPGis_noind_null()

Started by Boszormenyi Zoltanabout 16 years ago9 messages
#1Boszormenyi Zoltan
zb@cybertec.at

Hi,

my question is that what platform were these
functions developed and tested?

We have come across a value that fails a NOT NULL
constraint upon INSERT under HP-UX/IA64, but not
under x86-64 Linux. The value in question is
1.9999999999999998 assigned to a "double" variable.
Under HP-UX/IA64, testing with risnull() from
the application indeed returns true, but under
Linux/x86-64 returns false.

I will test rsetnull() results on real Informix under
HP-UX/IA64.

Best regards,
Zolt�n B�sz�rm�nyi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

#2Boszormenyi Zoltan
zb@cybertec.at
In reply to: Boszormenyi Zoltan (#1)
1 attachment(s)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Boszormenyi Zoltan �rta:

Hi,

my question is that what platform were these
functions developed and tested?

We have come across a value that fails a NOT NULL
constraint upon INSERT under HP-UX/IA64, but not
under x86-64 Linux. The value in question is
1.9999999999999998 assigned to a "double" variable.
Under HP-UX/IA64, testing with risnull() from
the application indeed returns true, but under
Linux/x86-64 returns false.

I will test rsetnull() results on real Informix under
HP-UX/IA64.

I have tested it under ESQL/C on HP-UX/ia64 and
this happened:
- rsetnull() on a double value creates
FF FF FF FF FF FF FF FF
- the value causing the error above is
3F FF FF FF FF FF FF FF

It seems that this function in ecpglib/misc.c has
an off-by-one bug as it's interpreted by the HP-UX CC:

static bool
_check(unsigned char *ptr, int length)
{
for (; length > 0 && ptr[--length] == 0xff;);
if (length <= 0)
return true;
return false;
}

I suspect that GCC does the "--length" after checking
"length > 0" and before checking the "ptr[...] == 0xff",
but HP CC does it before checking "length > 0".

The attached patch solves the problem.

Best regards,
Zolt�n B�sz�rm�nyi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

Attachments:

risnull-fix-ctxdiff.patchtext/x-patch; name=risnull-fix-ctxdiff.patchDownload
*** pgsql.4/src/interfaces/ecpg/ecpglib/misc.c.old	2009-11-19 19:50:38.000000000 +0100
--- pgsql.4/src/interfaces/ecpg/ecpglib/misc.c	2009-11-19 19:51:23.000000000 +0100
***************
*** 364,373 ****
  static bool
  _check(unsigned char *ptr, int length)
  {
! 	for (; length > 0 && ptr[--length] == 0xff;);
! 	if (length <= 0)
! 		return true;
! 	return false;
  }
  
  bool
--- 364,375 ----
  static bool
  _check(unsigned char *ptr, int length)
  {
! 	int	i;
! 	for (i = 0; i < length && ptr[i] == 0xff; i++)
! 		;
! 	if (i < length)
! 		return false;
! 	return true;
  }
  
  bool
#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Boszormenyi Zoltan (#2)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Boszormenyi Zoltan <zb@cybertec.at> writes:

for (; length > 0 && ptr[--length] == 0xff;);

I suspect that GCC does the "--length" after checking
"length > 0" and before checking the "ptr[...] == 0xff",
but HP CC does it before checking "length > 0".

If it does, that is *unquestionably* a bug in HP's CC and should be
reported to them. However, the code is sufficiently unreadable to
be worth rewriting anyhow. Your suggestion is an improvement but
personally I'd plump for

int i;

for (i = 0; i < length; i++)
if (ptr[i] != 0xff)
return false;
return true;

regards, tom lane

#4Andrew Dunstan
andrew@dunslane.net
In reply to: Tom Lane (#3)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Tom Lane wrote:

Boszormenyi Zoltan <zb@cybertec.at> writes:

for (; length > 0 && ptr[--length] == 0xff;);

I suspect that GCC does the "--length" after checking
"length > 0" and before checking the "ptr[...] == 0xff",
but HP CC does it before checking "length > 0".

If it does, that is *unquestionably* a bug in HP's CC and should be
reported to them.

Wow, I recall fighting HP over a bad compiler bug (although not as bad
as this would be) 15 years ago. Their official response amounted to "we
don't care and we're not going to fix it". Maybe not much has changed.

cheers

andrew

#5Boszormenyi Zoltan
zb@cybertec.at
In reply to: Tom Lane (#3)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Tom Lane �rta:

Boszormenyi Zoltan <zb@cybertec.at> writes:

for (; length > 0 && ptr[--length] == 0xff;);

I suspect that GCC does the "--length" after checking
"length > 0" and before checking the "ptr[...] == 0xff",
but HP CC does it before checking "length > 0".

If it does, that is *unquestionably* a bug in HP's CC and should be
reported to them.

Is it *really* a bug? I recalled a comment from my C teacher
in '92 or '93 about this exact issue, that the prefix/postfix
increment/decrement operators are executed in the
statement in an implementation-defined order, i.e. they
can be freely reordered or placed anywhere in the
expression, provided that the postfix operator's evaluation
is earlier than the usage of the variable it's used on and
evaluation is later than the variable usage in the postfix case.
This means that their usage has to be minimized so the
result is unambiguous. I.e. in the common usage:

str1[pos1++] = str2[pos2++];

these execution orders are possible and all give the same result:

1. evaluate str2[pos2]
increment pos2
assign the above value to str1[pos1]
increment pos1
or
2. evaluate str2[pos2]
assign the above value to str1[pos1]
increment pos2
increment pos1
or
3. evaluate str2[pos2]
assign the above value to str1[pos1]
increment pos1
increment pos2

In the case of
for (; length > 0 && ptr[--length] == 0xff;);
the different evaluation orders may give different
expression results.

But 17 years is a long time, the C language specification
has changed a lot. GCC definitely does the most sensible
order but I didn't know this behaviour is specified in the
C language.

However, the code is sufficiently unreadable to
be worth rewriting anyhow. Your suggestion is an improvement but
personally I'd plump for

int i;

for (i = 0; i < length; i++)
if (ptr[i] != 0xff)
return false;
return true;

Yes, it's better than my version.

Best regards,
Zolt�n B�sz�rm�nyi

regards, tom lane

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

#6Boszormenyi Zoltan
zb@cybertec.at
In reply to: Boszormenyi Zoltan (#5)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Boszormenyi Zoltan �rta:

Tom Lane �rta:

Boszormenyi Zoltan <zb@cybertec.at> writes:

for (; length > 0 && ptr[--length] == 0xff;);

I suspect that GCC does the "--length" after checking
"length > 0" and before checking the "ptr[...] == 0xff",
but HP CC does it before checking "length > 0".

If it does, that is *unquestionably* a bug in HP's CC and should be
reported to them.

Is it *really* a bug? I recalled a comment from my C teacher
in '92 or '93 about this exact issue, that the prefix/postfix
increment/decrement operators are executed in the
statement in an implementation-defined order, i.e. they
can be freely reordered or placed anywhere in the
expression, provided that the postfix operator's evaluation

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Above is the prefix case obviously...

is earlier than the usage of the variable it's used on and
evaluation is later than the variable usage in the postfix case.
This means that their usage has to be minimized so the
result is unambiguous.

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

#7Andrew Dunstan
andrew@dunslane.net
In reply to: Boszormenyi Zoltan (#5)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Boszormenyi Zoltan wrote:

Is it *really* a bug? I recalled a comment from my C teacher
in '92 or '93 about this exact issue, that the prefix/postfix
increment/decrement operators are executed in the
statement in an implementation-defined order,

Not if they come after a short-circuit operator such as && - after all,
that's what short-circuit evaluation implies. If the left hand operand
of && is false the right hand should not be evaluated at all.

cheers

andrew

#8Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andrew Dunstan (#7)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Andrew Dunstan <andrew@dunslane.net> writes:

Boszormenyi Zoltan wrote:

Is it *really* a bug? I recalled a comment from my C teacher
in '92 or '93 about this exact issue, that the prefix/postfix
increment/decrement operators are executed in the
statement in an implementation-defined order,

Not if they come after a short-circuit operator such as && - after all,
that's what short-circuit evaluation implies. If the left hand operand
of && is false the right hand should not be evaluated at all.

Yes. && is a sequence point and the compiler is not allowed to move
side-effects across a sequence point. What your C teacher was warning
you against was things like
a[i] = i++;
'=' is not a sequence point so it's undefined which array index
will be stored into.

regards, tom lane

#9Boszormenyi Zoltan
zb@cybertec.at
In reply to: Tom Lane (#8)
Re: Question about ECPGset_noind_null() and ECPGis_noind_null()

Tom Lane �rta:

Andrew Dunstan <andrew@dunslane.net> writes:

Boszormenyi Zoltan wrote:

Is it *really* a bug? I recalled a comment from my C teacher
in '92 or '93 about this exact issue, that the prefix/postfix
increment/decrement operators are executed in the
statement in an implementation-defined order,

Not if they come after a short-circuit operator such as && - after all,
that's what short-circuit evaluation implies. If the left hand operand
of && is false the right hand should not be evaluated at all.

Yes. && is a sequence point and the compiler is not allowed to move
side-effects across a sequence point. What your C teacher was warning
you against was things like
a[i] = i++;
'=' is not a sequence point so it's undefined which array index
will be stored into.

regards, tom lane

Thanks to both of you, this was really informative.
Actually my C teacher didn't mention such optimization barriers.
It seems I need to look up the raw C language specs...

Best regards,
Zolt�n B�sz�rm�nyi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/