check integer overflow with GCC 4.5.2

S

sailer

Hi,

I have the following code which was used to check whether the result
of (a * b) is larger than the maximum integer value.

ovf(int a, int b, int *r, int *v)
{
*r = a * b;
if (b == 0 || a == *r / b)
*v = 0;
else
*v = 1;

}

int main()
{
int words;
int bytes;
int overflow;

//... whatever
ovf(words, sizeof(int), &bytes, &overflow);
if (overflow)
printf("overflow");

}

It doesn't work with GCC 4.5.2 if enabling -O2 or -O3, asm code
generated by GCC is as follows, call to ovf is eliminated, seems
that
GCC evaluates (a == *r/b) to TRUE at compile time, is there anyway
to
revise ovf to let it satisfy GCC? thanks in advance.

main:
pushl %ebp #
xorl %eax, %eax #
movl %esp, %ebp #,
popl %ebp #
ret
.size main, .-main
.ident "GCC: (GNU) 4.5.2"
.section .note.GNU-stack,"",@progbits
 
T

Tobias Müller

sailer said:
Hi,

I have the following code which was used to check whether the result
of (a * b) is larger than the maximum integer value.

ovf(int a, int b, int *r, int *v)
{
*r = a * b;
if (b == 0 || a == *r / b)
*v = 0;
else
*v = 1;

}

int main()
{
int words;
int bytes;
int overflow;

//... whatever
ovf(words, sizeof(int), &bytes, &overflow);
if (overflow)
printf("overflow");

}

It doesn't work with GCC 4.5.2 if enabling -O2 or -O3, asm code
generated by GCC is as follows, call to ovf is eliminated, seems
that
GCC evaluates (a == *r/b) to TRUE at compile time, is there anyway
to
revise ovf to let it satisfy GCC? thanks in advance.

main:
pushl %ebp #
xorl %eax, %eax #
movl %esp, %ebp #,
popl %ebp #
ret
.size main, .-main
.ident "GCC: (GNU) 4.5.2"
.section .note.GNU-stack,"",@progbits

The possibility of such optimizations is one reasons, why int overflow is
undefined behaviour.

The correctly formulated question (compiler neutral) would then be how to
implement this test without relying on UB. (some people on this list are a
bit picky about that)

You could take unsigned int instead, where overflow is defined:

ovf(int a, int b, unsigned int *r, int *v)
{
*r = (unsigned int)a * b;
if (b == 0 || (a == *r / b && r <= INT_MAX))
*v = 0;
else
*v = 1;
}

This is just to illustrate, notice however that:
- this is really C rather than C++
- it does not work for underflows
- it probably leads to compiler warnings without some more casts
- I have not tested it.
- there are probably more efficient ways of achieving the same thing

Tobi
 
S

sailer

The possibility of such optimizations is one reasons, why int overflow is
undefined behaviour.

The correctly formulated question (compiler neutral) would then be how to
implement this test without relying on UB. (some people on this list are a
bit picky about that)

You could take unsigned int instead, where overflow is defined:

ovf(int a, int b, unsigned int *r, int *v)
{
          *r = (unsigned int)a * b;
          if (b == 0 || (a == *r / b && r <= INT_MAX))
                  *v = 0;
          else
                  *v = 1;

}

This is just to illustrate, notice however that:
- this is really C rather than C++
- it does not work for underflows
- it probably leads to compiler warnings without some more casts
- I have not tested it.
- there are probably more efficient ways of achieving the same thing

Tobi


Tobi,

Really appreciate your replying, it helps much in understanding the
background of the problem.
I gave a try to use unsigned and INT_MAX but failed to address the
issue, happened to find
add "__attribute__ ((noinline))" before ovf solves it.
 
J

Jorgen Grahn

Hi,

I have the following code which was used to check whether the result
of (a * b) is larger than the maximum integer value.
....

You posted the same(?) question to comp.lang.c. Please don't do it that
way; it wastes people's time. Cross-post instead of multi-post.

regards,
/Jorgen
 
T

Tobias Müller

sailer said:
Tobi,

Really appreciate your replying, it helps much in understanding the
background of the problem.
I gave a try to use unsigned and INT_MAX but failed to address the
issue, happened to find
add "__attribute__ ((noinline))" before ovf solves it.

It solves it for now, but compilers will become better and your problem
will reappear...

The optimization can also be applied without inlining, it's just that the
compiler missed that opportunity.

If you are interested, here is a link to a good article about UB on the
llvm/clang compiler Blog (actually a serie 3 articles). It also covers your
case (integer overflow).
http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html

Tobi
 
F

Fred Zwarts \(KVI\)

"sailer" wrote in message
Hi,

I have the following code which was used to check whether the result
of (a * b) is larger than the maximum integer value.

ovf(int a, int b, int *r, int *v)
{
*r = a * b;
if (b == 0 || a == *r / b)
*v = 0;
else
*v = 1;

}

int main()
{
int words;
int bytes;
int overflow;

//... whatever
ovf(words, sizeof(int), &bytes, &overflow);
if (overflow)
printf("overflow");

}

It doesn't work with GCC 4.5.2 if enabling -O2 or -O3, asm code
generated by GCC is as follows, call to ovf is eliminated, seems
that
GCC evaluates (a == *r/b) to TRUE at compile time, is there anyway
to
revise ovf to let it satisfy GCC? thanks in advance.

May be it helps to store the result of the multiplication i n a volatile
variable and use that variable in the division? Wouldn't that inhibit the
optimization?
 
S

sailer

Tobi,

Really appreciate your replying, it helps much in understanding the
background of the problem.
I gave a try to use unsigned and INT_MAX but failed to address the
issue, happened to find
add "__attribute__ ((noinline))" before ovf solves it.

My mistake here, adding the attribute could force compiler to generate
call to 'ovf' but
the if-else code is still optimized out.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top