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

kargl at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Sat Aug 26 16:36:00 GMT 2017


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
> 0x80000000000000000000000000000000 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 = -0x80000000000000000000000000000000;

      _gfortran_transfer_integer_write (&dt_parm.0, &C.3427, 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 0x80000000

and a.f90.003t.original contains

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

      _gfortran_transfer_integer_write (&dt_parm.0, &C.3427, 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 = -0x80000000000000000000000000000000;
  j = -0x80000000000000000000000000000000;
}
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.


More information about the Gcc-bugs mailing list