Bug #5290

int64_t issues for abs() with c++ out of stdlib.h

Added by Richard PALO over 4 years ago. Updated over 2 years ago.

Status:NewStart date:2014-11-06
Priority:NormalDue date:
Assignee:-% Done:

0%

Category:-
Target version:-
Difficulty:Medium Tags:needs-triage

Description

This is the original issue found is reproduced with the following program:

richard@omnis:/home/richard/src$ cat tabs.cc
#include <stdlib.h>
void tabs(int64_t foo)
{
    int64_t bar = abs(foo);
}
richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/g++ -c tabs.cc
tabs.cc: In function ‘void tabs(int64_t)’:
tabs.cc:4:23: error: call of overloaded ‘abs(int64_t&)’ is ambiguous
  int64_t bar = abs(foo);
                       ^
tabs.cc:4:23: note: candidates are:
In file included from /usr/include/stdlib.h:37:0,
                 from tabs.cc:1:
/usr/include/iso/stdlib_iso.h:165:16: note: long int std::abs(long int)
  inline long   abs(long _l) { return labs(_l); }
                ^
/usr/include/iso/stdlib_iso.h:119:12: note: int std::abs(int)
 extern int abs(int);
            ^
richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/g++ -m64 -c tabs.cc

There is (on i386) a first issue of a problematic definition when uint64_t (here long long) is used.

Then, by simply copying the .cc to a .c and trying again with gcc

richard@omnis:/home/richard/src$ cp tabs.cc tabs.c
richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc -c tabs.c
tabs.c:2:11: error: unknown type name ‘int64_t’
 void tabs(int64_t foo)
           ^
richard@omnis:/home/richard/src$ 
richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc -m64 -c tabs.c
tabs.c:2:11: error: unknown type name ‘int64_t’
 void tabs(int64_t foo)
           ^

Here the ball is completely dropped.

outputting via '-E -dD -o <file>' indicates what is determined by the compiler.

Clang gives informative output as well:

richard@omnis:/home/richard/src$ clang++ -m32 -c tabs.cc
tabs.cc:4:16: error: call to 'abs' is ambiguous
        int64_t bar = abs(foo);
                      ^~~
/usr/include/iso/stdlib_iso.h:119:12: note: candidate function
extern int abs(int);
           ^
/usr/include/iso/stdlib_iso.h:165:16: note: candidate function
        inline long   abs(long _l) { return labs(_l); }
                      ^
1 error generated.
richard@omnis:/home/richard/src$ clang++ -m64 -c tabs.cc
richard@omnis:/home/richard/src$ clang -m32 -c tabs.c
tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long long') but has parameter of type 'int' which may cause truncation of
      value [-Wabsolute-value]
        int64_t bar = abs(foo);
                      ^
tabs.c:4:16: note: use function 'llabs' instead
        int64_t bar = abs(foo);
                      ^~~
                      llabs
1 warning generated.
richard@omnis:/home/richard/src$ clang -m64 -c tabs.c
tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long') but has parameter of type 'int' which may cause truncation of value
      [-Wabsolute-value]
        int64_t bar = abs(foo);
                      ^
tabs.c:4:16: note: use function 'labs' instead
        int64_t bar = abs(foo);
                      ^~~
                      labs
1 warning generated.

tabs.ii (29.1 KB) Alexander Eremin, 2014-11-11 09:24 AM

History

#1 Updated by Richard PALO over 4 years ago

The output when using `-E -dD |egrep 'STDC|LP|LONGLONG|INT64|int64'` is interesting.
Is there also a gcc compiler issue in not defining int64_t that could explain the clang difference with 'c'?

#2 Updated by Richard PALO over 4 years ago

I believe this is relatively recent.
Just tried on oi_151a9 with gcc44:

richard@smicro:~/src$ /opt/gcc/4.4.4/bin/g++ -m32 -c tabs.cc
richard@smicro:~/src$ /opt/gcc/4.4.4/bin/g++ -m64 -c tabs.cc
richard@smicro:~/src$ /opt/gcc/4.4.4/bin/gcc -m32 -c tabs.cc
richard@smicro:~/src$ /opt/gcc/4.4.4/bin/gcc -m64 -c tabs.cc

to compare with omnios bloody and gcc-4.4.4

richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/g++ -m32 -c tabs.cc
richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/g++ -m64 -c tabs.cc
richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/gcc -m32 -c tabs.c
tabs.c:2: error: expected ‘)’ before ‘foo’
richard@omnis:/home/richard/src$ /opt/gcc-4.4.4/bin/gcc -m64 -c tabs.c
tabs.c:2: error: expected ‘)’ before ‘foo’

#3 Updated by Richard PALO over 4 years ago

Still more curiously, gcc 3.4.3 on oi_151a9

richard@smicro:~/src$ gcc -v
Reading specs from /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/specs
Configured with: /home/jt/OIDEV/151A-PRESTABLE9/newbuilds/sfw/usr/src/cmd/gcc/gcc-3.4.3/configure --prefix=/usr/sfw --with-as=/usr/sfw/bin/gas --with-gnu-as --with-ld=/usr/ccs/bin/ld --without-gnu-ld --enable-languages=c,c++,f77,objc --enable-shared
Thread model: posix
gcc version 3.4.3 (csl-sol210-3_4-20050802)
richard@smicro:~/src$ g++ -m32 -c tabs.cc
richard@smicro:~/src$ g++ -m64 -c tabs.cc
richard@smicro:~/src$ gcc -m32 -c tabs.c
tabs.c:2: error: syntax error before "foo" 
tabs.c: In function `tabs':
tabs.c:4: error: `int64_t' undeclared (first use in this function)
tabs.c:4: error: (Each undeclared identifier is reported only once
tabs.c:4: error: for each function it appears in.)
tabs.c:4: error: syntax error before "bar" 
richard@smicro:~/src$ gcc -m64 -c tabs.c
tabs.c:2: error: syntax error before "foo" 
tabs.c: In function `tabs':
tabs.c:4: error: `int64_t' undeclared (first use in this function)
tabs.c:4: error: (Each undeclared identifier is reported only once
tabs.c:4: error: for each function it appears in.)
tabs.c:4: error: syntax error before "bar" 

#4 Updated by Richard PALO over 4 years ago

It appears that the 'long long' defs are missing for a number of functions.

For example, the following gets over the initial issue stated:

richard@omnis:/home/richard/src$ diff -u /usr/include/iso/stdlib_c99.h.orig /usr/include/iso/stdlib_c99.h
--- /usr/include/iso/stdlib_c99.h.orig  mar. sept. 30 07:57:17 2014
+++ /usr/include/iso/stdlib_c99.h       jeu. nov.  6 12:39:43 2014
@@ -69,6 +69,7 @@
 #if defined(_LONGLONG_TYPE)
 extern long long atoll(const char *);
 extern long long llabs(long long);
+inline long long abs(long long _ll) { return llabs(_ll); }
 extern lldiv_t lldiv(long long, long long);
 extern long long strtoll(const char *_RESTRICT_KYWD, char **_RESTRICT_KYWD,
        int);

#5 Updated by Richard PALO over 4 years ago

which, as of now, promptly causes the following problem :


richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc  -m32 -c tabs.c
In file included from /usr/include/stdlib.h:38:0,
                 from tabs.c:1:
/usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for ‘abs’
 inline long long abs(long long _ll) { return llabs(_ll); }
                  ^
tabs.c:2:11: error: unknown type name ‘int64_t’
 void tabs(int64_t foo)
           ^
richard@omnis:/home/richard/src$ /opt/gcc-4.8.1/bin/gcc -D__EXTENSIONS__ -m32 -c tabs.c
In file included from /usr/include/stdlib.h:38:0,
                 from tabs.c:1:
/usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for ‘abs’
 inline long long abs(long long _ll) { return llabs(_ll); }
                  ^

and clang:

richard@omnis:/home/richard/src$ clang  -m32 -c tabs.c
In file included from tabs.c:1:
In file included from /usr/include/stdlib.h:38:
/usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for 'abs'
inline long long abs(long long _ll) { return llabs(_ll); }
                 ^
/usr/include/iso/stdlib_iso.h:119:12: note: previous declaration is here
extern int abs(int);
           ^
tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long long') but has parameter of type 'int' which may cause
      truncation of value [-Wabsolute-value]
        int64_t bar = abs(foo);
                      ^
tabs.c:4:16: note: use function 'llabs' instead
        int64_t bar = abs(foo);
                      ^~~
                      llabs
1 warning and 1 error generated.
richard@omnis:/home/richard/src$ clang -D__EXTENSIONS__ -m32 -c tabs.c
In file included from tabs.c:1:
In file included from /usr/include/stdlib.h:38:
/usr/include/iso/stdlib_c99.h:72:18: error: conflicting types for 'abs'
inline long long abs(long long _ll) { return llabs(_ll); }
                 ^
/usr/include/iso/stdlib_iso.h:119:12: note: previous declaration is here
extern int abs(int);
           ^
tabs.c:4:16: warning: absolute value function 'abs' given an argument of type 'int64_t' (aka 'long long') but has parameter of type 'int' which may cause
      truncation of value [-Wabsolute-value]
        int64_t bar = abs(foo);
                      ^
tabs.c:4:16: note: use function 'llabs' instead
        int64_t bar = abs(foo);
                      ^~~
                      llabs
1 warning and 1 error generated.

So the solution may not be so rudimentary...

#6 Updated by Richard PALO over 4 years ago

So far, the most portable "workaround " found seems to be
resorting to c++ includes cstdlib + cmath as in the following:

#include <stdlib.h>

#if defined(__sun) && defined(__cplusplus)
#include        <cstdlib>
#include        <cmath>
#endif

void tabs(int64_t foo)
{
        int64_t bar = abs(foo);
}

This pulls in:

# 173 "/opt/gcc-4.8.1/include/c++/4.8.1/cstdlib" 3
  inline long long
  abs(long long __x) { return __builtin_llabs (__x); }

That's enough from me now, hopefully the math masters have a durable solution
that works for both i386 and x86_64 out of the box.

#7 Updated by Igor Kozhukhov over 4 years ago

i have no problems with first proposed test on my env with gcc-4.8.3 64bit build:
  1. /usr/gcc/4.8/bin/g++ -c tabs.cc
  1. gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/gcc/4.8/lib/gcc/x86_64-pc-solaris2.11/4.8.3/lto-wrapper
    Target: x86_64-pc-solaris2.11
    Configured with: /myshare/builds/jenkins/src/du/dilos-userland-review/components/gcc48/gcc-4.8.3/configure --prefix=/usr/gcc/4.8 --mandir=/usr/gcc/4.8/share/man --bindir=/usr/gcc/4.8/bin --libdir=/usr/gcc/4.8/lib --sbindir=/usr/gcc/4.8/sbin --infodir=/usr/share/info --with-gnu-as --with-as=/usr/bin/gas --build=x86_64-pc-solaris2.11 --target=x86_64-pc-solaris2.11 --enable-targets=i386-pc-solaris2.11 --infodir=/usr/gcc/4.8/share/info --libexecdir=/usr/gcc/4.8/lib --enable-languages=c,c++,fortran,objc --enable-shared --enable-tls --enable-threads=posix --without-gnu-ld --with-ld=/usr/bin/ld
    Thread model: posix
    gcc version 4.8.3 (GCC)
build failed with 32bit:
  1. /usr/gcc/4.8/bin/g++ -m32 -c tabs.cc
    tabs.cc: In function ‘void tabs(int64_t)’:
    tabs.cc:4:26: error: call of overloaded ‘abs(int64_t&)’ is ambiguous
    int64_t bar = abs(foo);
    ^
    tabs.cc:4:26: note: candidates are:
    In file included from /usr/include/stdlib.h:37:0,
    from tabs.cc:1:
    /usr/include/iso/stdlib_iso.h:165:16: note: long int std::abs(long int)
    inline long abs(long _l) { return labs(_l); }
    ^
    /usr/include/iso/stdlib_iso.h:119:12: note: int std::abs(int)
    extern int abs(int);
    ^
and not failed with 64bit build:
  1. /usr/gcc/4.8/bin/g++ -m64 -c tabs.cc
    root@srv115:/myshare/builds/dilos-userland/dilos-userland-review/components/2#

#8 Updated by Rich Lowe over 4 years ago

This looks from a distance like the kind of thing that fix-includes may affect. If you're going to do comparitive testing, you should make certain that you're always using our headers, only.

That would involve deleting or moving aside the include-fixed directories of the various compilers.

#9 Updated by Richard PALO over 4 years ago

PM: clang doesn't use gnu-c's fix-includes as far as I know. Also, I very quickly checked /opt/gcc-4.8.1/lib/gcc/i386-pc-solaris2.11/4.8.1/include-fixed (as well as the others used) to see if something might have come up...

#10 Updated by Richard PALO over 4 years ago

For info: I updated the test program just a tad and filed a gnu c++ issue to get a response for an eventual compiler issue... https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63789

#11 Updated by Richard PALO over 4 years ago

Richard PALO wrote:

Still more curiously, gcc 3.4.3 on oi_151a9
[...]

just for completeness, adding #include <stdint.h> fixes the build on 3.4.3.
I needed the same for FreeBSD, that is why the test program is updated as follows:

#include <stdint.h>
#include <stdlib.h>

int64_t tabs(int64_t foo)
{
    return    abs(foo);
}

#12 Updated by Richard PALO over 4 years ago

Can anybody answer this?:

 Marc Glisse 2014-11-09 11:55:02 UTC

long long (or int64_t) is not part of C++03, so solaris headers don't provide the overload. 
We complete the set of overloads in c* headers, but there is a well known bug that we don't
provide wrappers for the *.h headers. It would be interesting to see how Oracle is updating
the solaris headers for C++11.

#13 Updated by Richard PALO over 4 years ago

Can anybody post the tabs.ii output on latest Or*cle solaris for:(preferably gcc4[8-9])
`g++ -c tabs.cc -save-temps` where tabs.cc is from https://www.illumos.org/issues/5290#note-11

#14 Updated by Alexander Eremin over 4 years ago

Richard PALO wrote:

Can anybody post the tabs.ii output on latest Or*cle solaris for:(preferably gcc4[8-9])
`g++ -c tabs.cc -save-temps` where tabs.cc is from https://www.illumos.org/issues/5290#note-11

S11.2 has same output for gcc4.8, tabs.ii is attached.

#15 Updated by Richard PALO over 2 years ago

I finally got annoyed enough to try something, anybody willing to take a look/try?

diff --git a/usr/src/head/iso/stdlib_iso.h b/usr/src/head/iso/stdlib_iso.h
index 90af2de..cc00933 100644
--- a/usr/src/head/iso/stdlib_iso.h
+++ b/usr/src/head/iso/stdlib_iso.h
@@ -138,6 +138,9 @@ extern _NORETURN_KYWD void exit(int)
 extern void free(void *);
 extern char *getenv(const char *);
 extern long int labs(long);
+#ifdef _LONGLONG_TYPE
+extern long long int llabs(long long);
+#endif
 extern ldiv_t ldiv(long, long);
 extern void *malloc(size_t);
 extern int mblen(const char *, size_t);
@@ -165,6 +168,9 @@ extern size_t wcstombs(char *_RESTRICT_KYWD, const wchar_t *_RESTRICT_KYWD,
 #if __cplusplus >= 199711L
 extern "C++" {
        inline long   abs(long _l) { return labs(_l); }
+#ifdef _LONGLONG_TYPE
+       inline long long abs(long long _ll) { return llabs(_ll); }
+#endif
        inline ldiv_t div(long _l1, long _l2) { return ldiv(_l1, _l2); }
 }
 #endif /* __cplusplus */

#16 Updated by Richard PALO over 2 years ago

except this isn't quite right since iso/stdlib_c99.h defines already llabs() correctly, but
scoping rules would prevent the abs() overload from working since stdlib_iso.h is included
prior to stdlib_{c99,c11}.h

Perhaps it is possible to legally rearrange things?

#17 Updated by Richard PALO over 2 years ago

This may work, though:

---- a/usr/src/head/iso/stdlib_c99.h
+++ b/usr/src/head/iso/stdlib_c99.h
@@ -84,6 +84,16 @@ extern long long strtoll(const char *_RESTRICT_KYWD, char **_RESTRICT_KYWD,
        int);
 extern unsigned long long strtoull(const char *_RESTRICT_KYWD,
        char **_RESTRICT_KYWD, int);
+
+#if __cplusplus >= 201103L
+extern "C++" {
+       inline long long abs(long long _ll) { return (llabs(_ll)); }
+       inline lldiv_t div(long long _ll1, long long _ll2) {
+           return (lldiv(_ll1, _ll2));
+       }
+}
+#endif /* __cplusplus */
+
 #endif /* defined(_LONGLONG_TYPE) */

 #endif  /* (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) ... */

added div() for good measure.

#18 Updated by Richard PALO over 2 years ago

  • Subject changed from int64_t issues out of stdlib.h to int64_t issues for abs() with c++ out of stdlib.h

Also available in: Atom