c++condaubsan

fsanitize=undefined causes linker errors


I'm trying to compile a program using -fsanitize=undefined using the conda g++ compiler. I'm running into `__ubsan_handle_type_mismatch' linker errors. I've used the flags in the compiles and the linking as suggested in:

including adding -lubsan to the end of the link and compile commands which I know isn't recommended but I had no success. I've also made sure my LD_LIBRARY_PATH is empty so that there isn't any trouble coming from that aspect.

A minimal example problem including the configuration of my python environment is below

vehicles.h

#include<string>
#include<memory>

#ifndef VEHICLES
#define VEHICLES

class vehicle{

    public:
        vehicle( );

        std::shared_ptr< vehicle > buildVehicle( const std::string & _type );

    protected:

        std::string type;

        unsigned int wheel_count;

};

class truck : public vehicle{

    public:
        truck( );

};

#endif

vehicles.cpp

#include "vehicles.h"

vehicle::vehicle( ){

    return;
}

std::shared_ptr< vehicle > vehicle::buildVehicle( const std::string &_type ){

    if ( _type.compare( "truck" ) ){

        return std::make_shared< vehicle >( );

    }

    return NULL;

}

truck::truck( ){

    type = "truck";
    wheel_count = 4;

}

test.cpp

#include "vehicles.h"
#include<iostream>

int main( ){

    //Build a truck
    std::shared_ptr< vehicle > truck = vehicle( ).buildVehicle( "truck" );

    std::cout << "Built a truck\n";

}

makefile

EXECUTABLE = eval
OBJECTS = test.o vehicles.o
INCS = -I. -I/home/nathan/anaconda3/include
LIBS = -L/home/nathan/anaconda3/lib
FLAGS = -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr

eval: $(OBJECTS)
        $(CXX) $(INCS) $(LIBS) -o $@ $^ $(FLAGS)

test.o: test.cpp vehicles.h
        $(CXX) $(INCS) $(LIBS) -c $< $(FLAGS)

vehicles.o: vehicles.cpp vehicles.h
        $(CXX) $(INCS) $(LIBS) -c $< $(FLAGS)

clean:
        rm -f $(EXECUTABLE)
        rm -f $(OBJECTS)

.PHONY: all clean

My conda environment YAML file is:

name: compile
channels:
  - anaconda
  - conda-forge
  - defaults
dependencies:
  - _libgcc_mutex=0.1=conda_forge
  - _openmp_mutex=4.5=1_gnu
  - binutils=2.32=he1b5a44_3
  - binutils_impl_linux-64=2.31.1=h7fc9f1b_5
  - binutils_linux-64=2.31.1=h6176602_9
  - bzip2=1.0.8=h516909a_3
  - c-ares=1.16.1=h516909a_3
  - c-compiler=1.1.1=h516909a_0
  - ca-certificates=2020.6.20=hecda079_0
  - certifi=2020.6.20=py38h32f6830_0
  - cmake=3.18.2=h5c55442_0
  - cxx-compiler=1.1.1=hc9558a2_0
  - expat=2.2.9=he1b5a44_2
  - gcc_impl_linux-64=7.3.0=habb00fd_1
  - gcc_linux-64=7.3.0=h553295d_9
  - gxx_impl_linux-64=7.3.0=hdf63c60_1
  - gxx_linux-64=7.3.0=h553295d_9
  - hdf5=1.12.0=nompi_h54c07f9_101
  - icu=67.1=he1b5a44_0
  - jpeg=9d=h516909a_0
  - krb5=1.17.1=hfafb76e_3
  - ld_impl_linux-64=2.34=h53a641e_7
  - libcurl=7.71.1=hcdd3856_5
  - libedit=3.1.20191231=he28a2e2_2
  - libev=4.33=h516909a_1
  - libffi=3.2.1=he1b5a44_1007
  - libgcc-ng=9.3.0=h24d8f2e_16
  - libgfortran-ng=7.5.0=hdf63c60_16
  - libgomp=9.3.0=h24d8f2e_16
  - libiconv=1.16=h516909a_0
  - libnghttp2=1.41.0=h8cfc5f6_2
  - libssh2=1.9.0=hab1572f_5
  - libstdcxx-ng=9.3.0=hdf63c60_16
  - libtiff=4.1.0=h2733197_1
  - libuv=1.39.0=h516909a_0
  - libxml2=2.9.10=h68273f3_2
  - lz4-c=1.9.2=he1b5a44_3
  - ncurses=6.2=he1b5a44_1
  - openssl=1.1.1g=h516909a_1
  - pcre=8.44=he1b5a44_0
  - pip=20.2.3=py_0
  - python=3.8.5=h1103e12_7_cpython
  - python_abi=3.8=1_cp38
  - readline=8.0=he28a2e2_2
  - rhash=1.3.6=h14c3975_1001
  - setuptools=49.6.0=py38h32f6830_0
  - sqlite=3.33.0=h4cf870e_0
  - swig=4.0.2=he1b5a44_0
  - tk=8.6.10=hed695b0_0
  - wheel=0.35.1=pyh9f0ad1d_0
  - xz=5.2.5=h516909a_1
  - zlib=1.2.11=h516909a_1009
  - zstd=1.4.4=h6597ccf_3
prefix: /home/nathan/anaconda3/envs/compile

The results of make are:

/home/nathan/anaconda3/envs/compile/bin/x86_64-conda_cos6-linux-gnu-c++ -I. -I/home/nathan/anaconda3/include -L/home/nathan/anaconda3/lib -c test.cpp -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr
/home/nathan/anaconda3/envs/compile/bin/x86_64-conda_cos6-linux-gnu-c++ -I. -I/home/nathan/anaconda3/include -L/home/nathan/anaconda3/lib -c vehicles.cpp -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr
/home/nathan/anaconda3/envs/compile/bin/x86_64-conda_cos6-linux-gnu-c++ -I. -I/home/nathan/anaconda3/include -L/home/nathan/anaconda3/lib -o eval test.o vehicles.o -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o: in function `__gnu_cxx::__exchange_and_add_single(int*, int)':
test.cpp:(.text+0xa8): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.cpp:(.text+0x10d): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.cpp:(.text+0x158): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o: in function `main':
test.cpp:(.text+0x2d4): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o: in function `vehicle::~vehicle()':
test.cpp:(.text._ZN7vehicleD2Ev[_ZN7vehicleD5Ev]+0x2f): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o:test.cpp:(.text._ZN7vehicleD2Ev[_ZN7vehicleD5Ev]+0x5c): more undefined references to `__ubsan_handle_type_mismatch' follow
collect2: error: ld returned 1 exit status
makefile:8: recipe for target 'eval' failed
make: *** [eval] Error 1

EDIT: Re-running with the verbose linker

/home/nathan/anaconda3/envs/compile/bin/x86_64-conda_cos6-linux-gnu-c++ -I. -I/home/nathan/anaconda3/include -L/home/nathan/anaconda3/lib -c test.cpp -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr
/home/nathan/anaconda3/envs/compile/bin/x86_64-conda_cos6-linux-gnu-c++ -I. -I/home/nathan/anaconda3/include -L/home/nathan/anaconda3/lib -c vehicles.cpp -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr
/home/nathan/anaconda3/envs/compile/bin/x86_64-conda_cos6-linux-gnu-c++ -I. -I/home/nathan/anaconda3/include -L/home/nathan/anaconda3/lib -v -o eval test.o vehicles.o -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr
Reading specs from /home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/specs
COLLECT_GCC=/home/nathan/anaconda3/envs/compile/bin/x86_64-conda_cos6-linux-gnu-c++
COLLECT_LTO_WRAPPER=/home/nathan/anaconda3/envs/compile/bin/../libexec/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/lto-wrapper
Target: x86_64-conda_cos6-linux-gnu
Configured with: /home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/.build/x86_64-conda_cos6-linux-gnu/src/gcc/configure --build=x86_64-build_pc-linux-gnu --host=x86_64-build_pc-linux-gnu --target=x86_64-conda_cos6-linux-gnu --prefix=/home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/gcc_built --with-sysroot=/home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/gcc_built/x86_64-conda_cos6-linux-gnu/sysroot --enable-languages=c,c++,fortran,objc,obj-c++ --with-pkgversion='crosstool-NG 1.23.0.449-a04d0' --enable-__cxa_atexit --disable-libmudflap --enable-libgomp --disable-libssp --enable-libquadmath --enable-libquadmath-support --enable-libsanitizer --enable-libmpx --with-gmp=/home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/.build/x86_64-conda_cos6-linux-gnu/buildtools --with-mpfr=/home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/.build/x86_64-conda_cos6-linux-gnu/buildtools --with-mpc=/home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/.build/x86_64-conda_cos6-linux-gnu/buildtools --with-isl=/home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/.build/x86_64-conda_cos6-linux-gnu/buildtools --enable-lto --enable-threads=posix --enable-target-optspace --enable-plugin --enable-gold --disable-nls --disable-multilib --with-local-prefix=/home/rdonnelly/mc/conda-bld/compilers_linux-64_1534865402226/work/gcc_built/x86_64-conda_cos6-linux-gnu/sysroot --enable-long-long --enable-default-pie
Thread model: posix
gcc version 7.3.0 (crosstool-NG 1.23.0.449-a04d0) 
COMPILER_PATH=/home/nathan/anaconda3/envs/compile/bin/../libexec/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/:/home/nathan/anaconda3/envs/compile/bin/../libexec/gcc/:/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/
LIBRARY_PATH=/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/:/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/:/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/lib/../lib/:/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/lib/../lib/:/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/usr/lib/../lib/:/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/lib/:/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/lib/:/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/usr/lib/
COLLECT_GCC_OPTIONS='-I' '.' '-I' '/home/nathan/anaconda3/include' '-L/home/nathan/anaconda3/lib' '-v' '-o' 'eval' '-fsanitize=address' '-fsanitize=undefined' '-fno-sanitize=vptr' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
 /home/nathan/anaconda3/envs/compile/bin/../libexec/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/collect2 -plugin /home/nathan/anaconda3/envs/compile/bin/../libexec/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/liblto_plugin.so -plugin-opt=/home/nathan/anaconda3/envs/compile/bin/../libexec/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccaD6hAv.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o eval /home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/usr/lib/../lib/Scrt1.o /home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/usr/lib/../lib/crti.o /home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/crtbeginS.o -L/home/nathan/anaconda3/lib -L/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0 -L/home/nathan/anaconda3/envs/compile/bin/../lib/gcc -L/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/lib/../lib -L/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/lib/../lib -L/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/usr/lib/../lib -L/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/lib -L/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/lib -L/home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/usr/lib -rpath /home/nathan/anaconda3/envs/compile/lib /home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/lib/../lib/libasan_preinit.o -lasan test.o vehicles.o -lstdc++ -lm -lubsan -lgcc_s -lgcc -lc -lgcc_s -lgcc /home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/crtendS.o /home/nathan/anaconda3/envs/compile/bin/../x86_64-conda_cos6-linux-gnu/sysroot/usr/lib/../lib/crtn.o
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o: in function `__gnu_cxx::__exchange_and_add_single(int*, int)':
test.cpp:(.text+0xa8): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.cpp:(.text+0x10d): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.cpp:(.text+0x158): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o: in function `main':
test.cpp:(.text+0x2d4): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o: in function `vehicle::~vehicle()':
test.cpp:(.text._ZN7vehicleD2Ev[_ZN7vehicleD5Ev]+0x2f): undefined reference to `__ubsan_handle_type_mismatch'
/home/nathan/anaconda3/envs/compile/bin/../lib/gcc/x86_64-conda_cos6-linux-gnu/7.3.0/../../../../x86_64-conda_cos6-linux-gnu/bin/ld: test.o:test.cpp:(.text._ZN7vehicleD2Ev[_ZN7vehicleD5Ev]+0x5c): more undefined references to `__ubsan_handle_type_mismatch' follow
collect2: error: ld returned 1 exit status
makefile:8: recipe for target 'eval' failed
make: *** [eval] Error 1

Solution

  • There could be a few possible issues.

    Channel Mixing

    Missing references in shared objects is a typical symptom of mixing package builds that come from different channels. This is because different channels use different build stacks and so symbols may have different names in shared objects compiled under those stacks.

    Try to source as many of the packages you use from a single channel. Since most people often need at least one package that is only on conda-forge, the most generic solution is to give conda-forge priority when creating the environment, i.e., try

    channels:
      - conda-forge
      - defaults
    

    in the YAML (note anaconda is a subset of defaults, so it isn't needed).

    Inconsistent Flags

    Currently, the INCS and LIBS environment variables are set to point to the base environment. This could also lead to a channel mixing issue, since base is often dominated by package builds from defaults channel.

    Instead, it would make more sense for those variables to point to the compile environment.

    INCS = -I. -I/home/nathan/anaconda3/envs/compile/include
    LIBS = -L/home/nathan/anaconda3/envs/compile/lib
    

    Overwriting Environment Flags

    The Conda build stacks that come from installing metapackages like cxx-compiler include packages with activation scripts that automatically manipulate the compiler and linker environment variables. For example, check under anaconda3/envs/compile/etc/conda/activate.d/. That is, the environment may already have a default configuration that correctly configures the paths to headers and runtime dependencies when activated.

    It is possible that those are getting overwritten or interfered with by setting INCS and/or LIBS, so it might be sufficient to completely omit such manual specifications.