Linking problem due to different size of std::string

Hello!

I’ve found out that one can’t rely on correct linking between nvcc object files and gcc object files, if std::string is used.

Here is what I’m talking about

#include <string>                                                               
#include <cstdio>                                                               
                                                                                
std::string foo;                                                                
                                                                                
int main()                                                                      
{                                                                               
    printf("%ld\n", sizeof(foo));                                               
    return 0;                                                                   
}

Compiling and running:

$ g++ test.cpp && ./a.out
32
$ nvcc test.cpp && ./a.out
8

My environment:

gcc version 6.3.0 20170516 (Debian 6.3.0-18)
Cuda compilation tools, release 8.0, V8.0.44

If some class is compiled by nvcc, and some code using this class is compiled by gcc, and the class anyhow contains std::string, then the linking will be corrupted. There will be no errors or warnings, though. Now any call to the fields after std::string will produce garbage, because in the code using the class an offset of pointers will be incorrectly calculated.

Is this a bug or something? How to avoid such problems?

gcc 6.3.0 is not an officially supported environment for CUDA 8.0.44
Use the same gcc version that is being used by your CUDA 8 host compiler. Make sure your nvcc is using a properly supported host compiler for the version (refer to linux install guide). Then you should see things match.

When I run your experiment on CUDA 9, Ubuntu 14.04, gcc 4.8.4 I get 8 printed out in both cases:

https://stackoverflow.com/questions/34560502/why-is-sizeofstdstring-only-eight-bytes

https://stackoverflow.com/questions/3770781/why-is-sizeofstring-32

txbob, thanks for your answer

I always use -ccbin=g++ in my projects, but now it turns out that it doesn’t work how I expect it to!

$ g++ test.cpp && ./a.out
32
$ nvcc -ccbin=g++ test.cpp && ./a.out
8

However, if I do

$ nvcc -ccbin=g++-6 test.cpp && ./a.out
32

It finally helps.

But where does this difference come from? These two commands should be identical, shouldn’t they? Because on my system g++ is the same as g+±6, take a look

$ g++ -v 2>&1 | tail -1
gcc version 6.3.0 20170516 (Debian 6.3.0-18) 
$ g++-6 -v 2>&1 | tail -1
gcc version 6.3.0 20170516 (Debian 6.3.0-18)

$ which g++
/usr/bin/g++
$ which g++-6
/usr/bin/g++-6

$ ls -la /usr/bin | grep g++-6 | head -1
lrwxrwxrwx  1 root   root           5 апр  8  2017 g++ -> g++-6

So, on my system g++ is just a symbolic link to g+±6, but not for the nvcc.

nvcc from CUDA 8.0.44 should refuse to use g++ 6.x

Have you made modifications to it?

I doubt I would be able to sort this out for you. You apparently have a jumble of configurations on your machine, and the problem you initially indicated in this thread is arising from that.

nvcc from CUDA 8.0.44 should refuse to use g++ 6.x

it does if cuda_runtime.h is included

In file included from /usr/include/cuda_runtime.h:78:0,
                 from <command-line>:0:
/usr/include/host_config.h:119:2: error: #error -- unsupported GNU version! gcc versions later than 5 are not supported!
 #error -- unsupported GNU version! gcc versions later than 5 are not supported!
  ^~~~~

In my little example test.cpp there was no CUDA headers, so compilation was successful.

But it doesn’t matter. The question is why CUDA arbitrarily downgrade gcc version, if “-ccbin=g++” was passed, where “g++” is a symlink for “g+±6” which is not supported?

what happens if you try -ccbin=/usr/bin/g++

what happens if you try -ccbin=/usr/bin/g++
If i do, the binary /usr/bin/g+±6 will be used.

It turned out that nvcc is supplied with its own compiler

$ ls /usr/lib/nvidia-cuda-toolkit/bin
cicc  crt  g++  gcc  libcuinj64.so  nvcc  nvcc.profile  nvprof

And version of that g++ is 4.9

So, when I do “-ccbin=g++”, nvcc first looks at path /usr/lib/nvidia-cuda-toolkit/bin, finds the right one, and stops with 4.9 version of g++.
If I pass anything else, nvcc doesn’t find the match in /usr/lib/nvidia-cuda-toolkit/bin, so it will search further in /usr/bin and finally takes a compiler from there.

My fault was that I wasn’t aware of this behavior and I thought that /usr/bin is always used for name resolution.

The question is closed for me. Thank you txbob