I am having problems understanding the segmentation fault I receive when trying to run icpc-compiled programs.
A simple example consists of the following files:
// Filename: include/lib1.h
#include <string>
namespace Lib1 {
// Template initialization, T: int, double
template< typename T>
T function1( T x, T y );
// Give me the version
std::string VERSION(void);
}
// Filename: include/lib2.h
#include <string>
namespace Lib2 {
// Give me the version
std::string VERSION(void);
}
// Filename: src/main.cpp
#include <iostream>
#include <string>
#include "lib1.h"
#include "lib2.h"
int main( int argc, char* argv[] ) {
std::cout << "Lib1::VERSION() :" << Lib1::VERSION()
<< std::endl;
std::cout << "Lib2::VERSION() :" << Lib2::VERSION()
<< std::endl;
double x = 1., y = 2.;
std::cout << "Lib1::function1(x, y): "
<< Lib1::function1(x, y)
<< std::endl;
return 0;
}
// Filename: src/lib1/lib1.cpp
#include <string>
#include "lib1.h"
template< typename T >
T Lib1::function1( T x, T y ) {
return x * y;
}
std::string Lib1::VERSION(void) {
return std::string("v0.0.2");
}
// Instantiation for dynamic library
template double Lib1::function1(double, double);
template int Lib1::function1(int, int);
// Filename: src/lib2/lib2.cpp
#include <string>
#include "lib2.h"
std::string Lib2::VERSION(void) {
return std::string("v0.0.1");
}
In this simple, stupid example, when I compile the files using
clang++ -Wall -c -fPIC -I include -o liblib1.o src/lib1/lib1.cpp
clang++ -Wall -shared -o liblib1.so liblib1.o
clang++ -Wall -c -fPIC -I include -o liblib2.o src/lib2/lib2.cpp
clang++ -Wall -shared -o liblib2.so liblib2.o
clang++ -Wall -o main.out -I include -L ./ -llib1 -llib2 src/main.cpp
the program runs fine (provided that I modify my LD_LIBRARY_PATH environment variable properly. However, when I use
icpc -Wall -c -fPIC -I include -o liblib1.o src/lib1/lib1.cpp
icpc -Wall -shared -o liblib1.so liblib1.o
icpc -Wall -c -fPIC -I include -o liblib2.o src/lib2/lib2.cpp
icpc -Wall -shared -o liblib2.so liblib2.o
icpc -Wall -o main.out -I include -L ./ -llib1 -llib2 src/main.cpp
then the program gives me:
[1] 27397 segmentation fault (core dumped) LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH ./main.out
I would appreciate if you helped me understand and solve this problem. When I did some research on the web, I came across some sources talking about memory access problems and such, but I am not doing anything fancy right now. Moreover, I tried using ddd (I am not fluent/good in gdb) and running the program there, but the program exists with the segfault immidiately after the program start. I cannot even trace the program (yes, prior to running ddd, I used -debug -g switches).
It happened to be the case that Intel Parallel Studio v16.0.3 has (known) issues for Ubuntu and Arch Linux platforms, and unfortunately these systems are not officially supported, either.
One fast workaround seems to be to downgrade to v16.0.2 for now.
Related
I have two source files: main.cxx and env.cxx. And main.cxx depends on env.cxx
If I compile them with
c++ -fmodules-ts -std=c++20 -Wall -g env.cxx main.cxx, then everything works well.
But if I compile them with
c++ -fmodules-ts -std=c++20 -Wall -g -c env.cxx
c++ -fmodules-ts -std=c++20 -Wall -g -c main.cxx
c++ -fmodules-ts -std=c++20 -Wall -g env.o main.o
I get segmentation fault.
I do not know whether it is a gcc bug or not, because it works well again if I rewrite them in c++17 style, removing the module declarations.
My compiler is gcc 11.1.0 (The newest version up to now)
Here is env.cxx:
module;
#include <cstdlib>
#include <string>
#include <string_view>
#include <stdexcept>
export module env;
export namespace env
{
std::string get_env(const char* name)
{
char* p = ::getenv(name);
if (p == nullptr)
throw std::runtime_error("environment variable not found");
return std::string(p);
}
// These two functions are useless this time.
std::string get_env(const std::string& name)
{
return get_env(name.data());
}
std::string get_env(std::string_view name)
{
std::string s{name};
return get_env(s.data());
}
}
And main.cxx
module;
#include <iostream>
#include <fstream>
import env;
export module main;
int main(int argc, char** argv)
{
std::cout << env::get_env("HOME") << std::endl;
return 0;
}
Can you reproduce this?
Update 2021.06-19 15:44
In fact the two compiling commands above both work well, and the way that produces segfault is actually:
c++ -fmodules-ts -std=c++20 -Wall -g -c env.cxx
c++ -fmodules-ts -std=c++20 -Wall -g -c main.cxx
c++ -fmodules-ts -std=c++20 -Wall -g main.o env.o
Note that the place of main.o and env.o has been changed.
Suppose I have a function in a shared library throwing some object, and a main executable calling that function and attempting to catch that object, e.g.
decl.h
#ifndef DECL_H
#define DECL_H
void pitch();
struct MyException {
MyException();
MyException(const MyException&);
~MyException();
};
#endif
pitch.cpp
#include "decl.h"
MyException::MyException() {}
MyException::MyException(const MyException&) {}
MyException::~MyException() {}
void pitch() {
throw MyException();
}
main.cpp
#include <stdio.h>
#include "decl.h"
int main() {
try { pitch(); }
catch (MyException& e) { printf("MyException()\n"); }
catch (...) { printf("[unknown exception]\n"); }
}
Makefile
all:
$(CXX) -shared -fPIC $(CXXFLAGS) $(LTO) pitch.cpp -o libpitch.so
$(CXX) -g $(CXXFLAGS) $(LTO) main.cpp -L. -lpitch
./a.out
If I compile without link-time optimization, all is well:
CXXFLAGS="-g -O2" LTO="" make
c++ -shared -fPIC -g -O2 pitch.cpp -o libpitch.so
c++ -g -g -O2 main.cpp -L. -lpitch
./a.out
MyException()
But once I turn on link-time optimization, the thrown object is no longer caught:
CXXFLAGS="-g -O2" LTO="-flto" make
c++ -shared -fPIC -g -O2 -flto pitch.cpp -o libpitch.so
c++ -g -g -O2 -flto main.cpp -L. -lpitch
./a.out
[unknown exception]
Is this expected behavior? Is this a problem in my C++ code, or something else? This is on macOS 10.14.5:
$ c++ -v
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
This is not expected behavior.
I tested it on linux (ubuntu) with gcc 4.x, 5.x, 6.x, 7.x and 8.x and with clang 6.0. All work just fine with -O2 -flto.
Unfortunately, since I cannot reproduce it (I don't have a Mac) I can't tell you what is wrong, but it isn't your code imho.
EDIT:
I can't in good conscious say there is "nothing wrong" with your code (although I tested it as shown by you - HOWEVER, I needed to set LD_LIBRARY_PATH="." for ./a.out to work (so perhaps you are loading some other library?)) without showing you how I'd write the above code:
//decl.h:
#pragma once
#include <exception>
void pitch();
struct MyException : public std::exception
{
};
//pitch.cpp:
#include "decl.h"
void pitch()
{
throw MyException();
}
// main.cpp:
#include "decl.h"
#include <iostream>
int main()
{
try
{
pitch();
}
catch (MyException const& e)
{
std::cout << "MyException(): " << e.what() << std::endl;
}
catch (...)
{
std::cerr << "[unknown exception]" << std::endl;
}
}
Consider the following setup consisting of two shared libraries which both use a static library:
static.cpp
#include "static.h"
static int a = 0;
int getA()
{
return a++;
}
static.h
#pragma once
int getA();
shareda.cpp
#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
std::cout << getA() << std::endl;
}
shareda.h
#pragma once
void printA();
sharedb.cpp
#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
std::cout << getA() << std::endl;
}
sharedb.h
#pragma once
void printB();
main.cpp
#include "shareda.h"
#include "sharedb.h"
int main()
{
printA();
printA();
printB();
printA();
printB();
return 0;
}
I compiled and ran these files with the following commands (using Clang 3.8.0, compiled from source, and 64-bit Debian with GNU ld 2.25):
clang++ -c static.cpp -o static.o -fPIC
ar rcs libstatic.a static.o
clang++ -c shareda.cpp -o shareda.o -fPIC
clang++ -shared -o libshareda.so shareda.o libstatic.a
clang++ -c sharedb.cpp -o sharedb.o -fPIC
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
clang++ -L. -lshareda -lsharedb -o main main.cpp
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main
To my surprise, the output was the following:
0
1
2
3
4
My expectation was this:
0
1
0
2
1
Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists. Is there a way to have two instances of a, one for each of the shared libraries?
Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists.
That is incorrect: two instances of a exist, but only one is actually used.
And that is happening because (contrary to your expectations) printB calls the first getA available to it (the one from libshareda.so, not the one from libsharedb.so). That is one major difference between UNIX shared libraries and Windows DLLs. UNIX shared libraries emulate what would have happened if your link was:
clang++ -L. -o main main.cpp shareda.o sharedb.o libstatic.a
So what can you do to "fix" this?
You could link libsharedb.so to prefer its own getA, by using -Bsymbolic.
You could hide getA inside libsharedb.so completely (as if it's a private implementation detail):
clang++ -c -fvisibility=hidden -fPIC static.cpp
ar rcs libstatic.a static.o
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
You could achieve similar result using linker version script.
P.S. Your link command:
clang++ -L. -lshareda -lsharedb -o main main.cpp
is completely backwards. It should be:
clang++ -L. -o main main.cpp -lshareda -lsharedb
The order of sources/object files and libraries on command line matters, and libraries should follow object files that reference them.
Since the definition of template must be put in header file, so I don't like it if the template class is big. so I want to make a normal class with some templated methods. Putting the defintion of templated method into header file, for others, put them into c++ source files. So here is what I am thinking.
// lambda.h
#include <iostream>
class X {
public:
std::function<bool(int)> filter;
template <class F>
void setFilter(F fn) {
filter = fn;
}
void big_function(int x);
};
// cat lambda.cpp
#include <iostream>
#include "lambda.h"
void X::big_function(int x) {
if (filter(x)) std::cout << x << std::endl;
}
// main2.cpp
#include <stdlib.h>
#include "lambda.h"
class Filter {
public:
bool operator()(int x) { return true; }
};
int main() {
X x;
x.setFilter(Filter());
x.big_function(3);
return 0;
}
// cat 2.sh
g++ -c lambda.cpp -ggdb
g++ -c main2.cpp -ggdb -std=c++11
g++ -o main2 main2.o lambda.o -ggdb
this program can compile, but got segment fault during executing (x.big_function(3));
#update
Q1: is my thinking is reasonable? is there any obvious error in my code?
Answer: Yes, it is reasonable, and no obvious error. Thanks to the first 4 comments, I did more test and works.
Q2: actually if I compile with -std=c++11, I will got segment fault. but no segment fault if I don't use std=c++11. ( I tried c++11 yesterday because I used lambda expression rather than function object for "Filter" at beginning). And it my real case, I can't discard c++11 features.
Answer: shame about my fault. fixed the issue by adding -std=c++11 for every compile unit.
zhifan$ sh -x 2.sh
+ g++ -c lambda.cpp -ggdb
+ g++ -c main2.cpp -ggdb
+ g++ -o main2 main2.o lambda.o -ggdb
zhifan$ ./main2
3
zhifan$ vim 2.sh
hifan$ sh -x 2.sh
+ g++ -c lambda.cpp -ggdb **-std=c++11**
+ g++ -c main2.cpp -ggdb -std=c++11
+ g++ -o main2 main2.o lambda.o -ggdb
zhifan$ ./main2
Segmentation fault: 11
zhifan$ g++ -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
I've read multiple posts here relating to dynamic libraries on os x and debugging with gdb. But I still can't figure out why I can't debug a simple test case.
The main issue is that when I start up GDB it never loads any shared libraries.
Update: I've tried this with GDB from macports, from homebrew, and built from source and the behavior is the same.
I have a class that I compile into a library.
Test.hpp
class Test {
public:
void set(int i);
void out() const;
private:
int i;
};
Test.cpp
#include "Test.hpp"
#include <iostream>
void Test::set(int ii) { i = ii; }
void Test::out() const {
auto j = i * 100;
std::cout << i << ", " << j << "\n";
++j;
std::cout << i << ", " << j << "\n";
}
I compile it and create a library with g++. Note: the behavior is the same with macports gcc and the gcc from xcode.
/opt/local/bin/g++-mp-4.8 -O0 -g -ggdb -Wall -c -std=c++11 -o Test.o Test.cpp
/opt/local/bin/g++-mp-4.8 -dynamiclib -o libTest.dylib Test.o
Then I test it with this simple main
#include "Test.hpp"
int main() {
Test t;
auto x = 4;
t.set(x);
t.out();
return 0;
}
This is compiled and linked with
/opt/local/bin/g++-mp-4.8 -O0 -g -ggdb -Wall -c -std=c++11 -o main.o main.cpp
/opt/local/bin/g++-mp-4.8 -L . -o testing main.o -lTest
Everything compiles and runs as expected. But when I try to debug this with gdb (installed from macports, or installed from source, the behavior is the same), I have problems.
As I step through main, if I call info sharedlibrary it always says "No shared libraries loaded at this time.", so it apparently never loads libTest.dylib. Therefore, I can't step into any of the Test member functions or create breakpoints anywhere in libTest.dylib.
Indeed ggdb installed from macports for some reason does not respect the DYLD_LIBRARY_PATH. However, if you "patch" your executable with the correct paths for the .dylibs you should be able to debug with ggdb. Take a look at this question and especially the answer by Akos Cz.