[Bug sanitizer/81986] sanitizer detects negation of large number in string.c

2017-08-29 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81986

--- Comment #3 from Jakub Jelinek  ---
(In reply to Vittorio Zecca from comment #2)
> I do not know if this is a libgfortran or a sanitizer bug.
> 
> What I do know is that changing string.c:199 from
> 
> t = - n;
> 
> into
> 
> t = -(GFC_UINTEGER_LARGEST)n;

This is of course the right fix, negation of smallest signed number is UB in C,
while it is well defined when the negation is performed in corresponding
unsigned type.

[Bug sanitizer/81986] sanitizer detects negation of large number in string.c

2017-08-28 Thread zeccav at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81986

--- Comment #2 from Vittorio Zecca  ---
I do not know if this is a libgfortran or a sanitizer bug.

What I do know is that changing string.c:199 from

t = - n;

into

t = -(GFC_UINTEGER_LARGEST)n;

as it should be, the sanitizer message disappears and the whole original test
case 
pr66311.f90 runs smoothly.

[Bug sanitizer/81986] sanitizer detects negation of large number in string.c

2017-08-25 Thread kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81986

kargl at gcc dot gnu.org changed:

   What|Removed |Added

 CC||dodji at gcc dot gnu.org,
   ||dvyukov at gcc dot gnu.org,
   ||jakub at gcc dot gnu.org,
   ||kcc at gcc dot gnu.org,
   ||marxin at gcc dot gnu.org
  Component|libfortran  |sanitizer

--- Comment #1 from kargl at gcc dot gnu.org ---
(In reply to Vittorio Zecca from comment #0)
> ! from test case pr66311.f90
> ! must be compiled and run
> ! libgfortran/runtime/string.c:199:11: runtime error: negation of
> 0x8000 cannot be represented in type '__int128';
> cast to an unsigned type to negate this value to itself
>   character(len=100) :: buffer
>   write(buffer,*) -huge(0_16)-1
>   end

Doesn't look like a gfortran problem other than gfortran uses GCC's
__int128 type and its middle/backend machinery.  If you compile
your code with -fdump-tree-original, you get in a.f90.003t.original

{
  static integer(kind=16) C.3427 = -0x8000;

  _gfortran_transfer_integer_write (_parm.0, , 16);
}

Changing your code to

  character(len=100) :: buffer
  write(buffer,*) -huge(0_4)-1
  print '(A,Z8)', trim(buffer)// ' 0x', -huge(0_4)-1
  end

where I added the print statement gives

troutmask:sgk[264] gfortran6 -static -o z -fdump-tree-original a.f90 && ./z
 -2147483648 0x8000

and a.f90.003t.original contains

{
  static integer(kind=4) C.3427 = -2147483648;

  _gfortran_transfer_integer_write (_parm.0, , 4);
}

Note the difference between using a decimal representation for the
constant and the hexidecimal representation in the *.original file.

But, a more interesting result occurs for

int
main(void)
{
   __int128 i,j;
   i =   ((__int128)1)  << 127;
   j = (-((__int128)1)) << 127;
   return 0;
}

% /usr/local/bin/gcc6 -fdump-tree-original -c a.c
%/ cat a.c.003t.original

;; Function main (null)
;; enabled by -tree-original

{
  __int128 i;
  __int128 j;

__int128 i;
__int128 j;
  i = -0x8000;
  j = -0x8000;
}
return 0;

Why is this interesting?  Well, consider the simpler case 

int
main(void)
{
   int i,j;
   i =   ((int)1) << 31;
   j = -(((int)1) << 31);
   return 0;
}

/usr/local/bin/gcc6 -fdump-tree-original -c a.c
a.c: In function 'main':
a.c:9:8: warning: integer overflow in expression [-Woverflow]
j = -(((int)1)<<31);
^

%cat a.c.003t.original

;; Function main (null)
;; enabled by -tree-original


{
  int i;
  int j;

int i;
int j;
  i = -2147483648;
  j = -2147483648(OVF);
  return 0;
}

Note, both the warning that GCC issues and the (OVF) annotation.

So, in summary, not a gfortran.  Someone needs to teach the sanitizers
about GCC's __int128 or someone needs to fix the handling of __int128
to mirror the behavior observed for a plain old int.