MacOS gcc dylib and clang app - exception handling issue - c++

For a legacy project I have to compile our code into a dylib with gcc which is then linked into a clang app starting with Intel-based macOS 10.15 (Catalina). I work with Big Sur 11.4 on a Mac Mini 2020 M1.
For testing purposes, I have created a small C++ project with header
foo.h
#pragma once
class Foo
{
public:
Foo();
virtual ~Foo();
void throw_runtime_error(const char* msg);
int bar(int a);
};
and code foo.cpp
#include <iostream>
#include <stdexcept>
#include "foo.h"
using namespace std;
Foo::Foo()
{
cout << "Foo:Foo() called" << endl;
}
Foo::~Foo()
{
cout << "Foo:~Foo() called" << endl;
}
void Foo::throw_runtime_error(const char* msg)
{
cout << "throwing runtime_error " << msg << endl;
throw runtime_error( msg );
}
int Foo::bar(int a)
{
cout << "Foo::bar(" << a << ") called" << endl;
return a + 1;
}
To create the dylib in a build subdir, I use the homebrewn g++ 10.2 with
g++-10 -arch x86_64 -fexceptions -dynamiclib -I../include ../src/foo.cpp -o ../bin/libMyDylib.dylib
For testing, how to be used along with clang 12.2.0 I have created a main.cpp in the bin subdir
#include "../include/foo.h"
#include <iostream>
#include <stdexcept>
int main()
{
Foo foo;
try
{
foo.throw_runtime_error("Hello you ugly little creatures!");
}
catch( const std::runtime_error &r )
{
std::cout << "Caught foo runtime_error, what = " << r.what() << std::endl;
}
catch( const std::exception &x )
{
std::cout << "Caught foo exception, what = " << x.what() << std::endl;
}
catch(...)
{
std::cout << "Caught foo exception, but without what()" << std::endl;
}
return foo.bar(42);
}
Now, if I use gcc-10 to compile main.cpp and link it with libMyDylib.dylib via g++-10 -arch x86_64 -L/Users/macos/bin -lMyDylib main.cpp -o main the exception handler in main.cpp catches the std::runtime_error properly.
If I use clang 12.2 along with g++ -arch x86_64 -L/Users/macos/bin -lMyDylib main.cpp -o main
then the output shows that only the catch (...) handler is triggered.
./main
Foo:Foo() called
throwing runtime_error Hello you ugly little creatures!
Caught foo exception, but without what()
Foo::bar(42) called
Foo:~Foo() called
So, can someone please give me a hint, what I am missing, in order to get 'cross-compiler' exceptions properly handled?
Thnxalot

Related

openssl error "EVP_DigestInit_ex:initialization error" using EVP-library

I have a problem with openssl and the EVP-functions:
When I execute the following code
#include <openssl/evp.h>
#include <openssl/engine.h>
#include <array>
#include <iostream>
void hash(ENGINE* eng) {
EVP_MD_CTX *_mdctx(EVP_MD_CTX_create());
int ret = EVP_DigestInit_ex(_mdctx, EVP_sha512(), eng);
EVP_MD_CTX_destroy(_mdctx);
if(1 == ret) {
std::cout << "Finished successfully (with eng=" << eng << ")" << std::endl;
return;
} else {
std::array<char, 256> err_str;
ERR_error_string_n(ERR_get_error(), err_str.data(), err_str.size());
std::cout << "Error at Digest (engine: " << ENGINE_get_id(eng) << "): " << err_str.data() << std::endl;
}
}
int main(void) {
ENGINE_load_builtin_engines();
hash(nullptr);
for(ENGINE *eng = ENGINE_get_first(); eng != nullptr; eng = ENGINE_get_next(eng)) {
hash(eng);
}
}
I get the following output:
Finished successfully (with eng=0)
Error at Digest (engine: rdrand): error:260BA093:engine routines:ENGINE_get_digest:unimplemented digest
Error at Digest (engine: dynamic): error:06080086:digital envelope routines:EVP_DigestInit_ex:initialization error
I understand, that rdrand doesn't support digest, but why do I get an initialization error, when I use the dynamic engine? In particular why does it work, when I call EVP_DigestInit_ex with eng=nullptr?
The code can be compiled with g++ example.cpp -std=c++17 -Wall -Wextra -Werror -pedantic -O2 -lssl -lcrypto. I am using g++, version 6.3.0 and openssl 1.1.0f.

Exceptions from boost::async() lose type

Boost version: 1.61, GCC version 6.2.0, C++14
Exceptions inside a boost::async() call seem to lose their type, while it works correctly with std::async. Is there a fundamental difference between std::async and boost::async I'm missing?
The following code works (using std::async):
#include <iostream>
#include <stdexcept>
#include <future>
using namespace std;
struct MyException : std::exception {
const char* what() const noexcept override { return "message"; }
};
int main() {
try {
auto future = std::async(std::launch::async, [] { throw MyException(); });
future.get();
} catch (const MyException& e) {
cout << "MyException caught. Message: " << e.what() << endl;
} catch (const std::exception& e) {
cout << "std::exception caught. Message: " << e.what() << endl;
}
}
and outputs
$ g++ test.cpp -std=c++14 -lpthread -lboost_thread -lboost_system && ./a.out
MyException caught. Message: message
However, the following code (it's the same, just using boost::async instead of std::async) does not work as expected:
#include <iostream>
#include <stdexcept>
#include <boost/thread/future.hpp>
using namespace std;
struct MyException : std::exception {
const char* what() const noexcept override { return "message"; }
};
int main() {
try {
auto future = boost::async(boost::launch::async, [] { throw MyException(); });
future.get();
} catch (const MyException& e) {
cout << "MyException caught. Message: " << e.what() << endl;
} catch (const std::exception& e) {
cout << "std::exception caught. Message: " << e.what() << endl;
}
}
It outputs:
$ g++ test.cpp -std=c++14 -lpthread -lboost_thread -lboost_system && ./a.out
std::exception caught. Message: std::exception
It also doesn't work for boost::future::then continuations:
#include <iostream>
#include <stdexcept>
#define BOOST_THREAD_VERSION 4
#include <boost/thread/future.hpp>
using namespace std;
struct MyException : std::exception {
const char* what() const noexcept override { return "message"; }
};
int main() {
try {
auto future = boost::make_ready_future(3).then([](boost::future<int>) -> int { throw MyException(); });
future.get();
} catch (const MyException& e) {
cout << "MyException caught. Message: " << e.what() << endl;
} catch (const std::exception& e) {
cout << "std::exception caught. Message: " << e.what() << endl;
}
}
outputs:
$ g++ test.cpp -std=c++14 -lpthread -lboost_thread -lboost_system && ./a.out
std::exception caught. Message: std::exception
So the concrete type of the exception seems to be lost when crossing the thread boundary. However, it doesn't seem to be connected to threading, because according to my tests, the same is true for std::launch::deferred (which works fine) and boost::launch::deferred (which loses the exception type).

ios_base::failure has no code()

I tried the code from cppreference.com but it seems e.code() is not there:
#include <iostream>
#include <system_error> // std::make_error_condition, std::ios_errc
int main () {
std::cin.exceptions (std::ios::failbit|std::ios::badbit);
try {
std::cin.rdbuf(nullptr); // throws
} catch (std::ios::failure& e) {
std::cerr << "Fehler: ";
if (e.code() == // <<< ERROR: no e.code() ???
std::make_error_condition(std::io_errc::stream))
std::cerr << "stream\n";
else
std::cerr << "other\n";
}
}
My g++-6.2 and g++-5 and clang-3.9 (on linux) all say the same:
error: ‘class std::ios_base::failure’ has no member named ‘code’
if (e.code() == std::make_error_condition(std::io_errc::stream))
^~~~
Even the unchanged example does not compile for me
#include <iostream>
#include <fstream>
int main()
{
std::ifstream f("doesn't exist");
try {
f.exceptions(f.failbit);
} catch (const std::ios_base::failure& e)
{
std::cout << "Caught an ios_base::failure.\n"
<< "Explanatory string: " << e.what() << '\n'
<< "Error code: " << e.code() << '\n';
}
}
with
$ g++-6 etest.cpp -o etest.x
etest.cpp: In function ‘int main()’:
etest.cpp:12:42: error: ‘const class std::ios_base::failure’ has no member named ‘code’
<< "Error code: " << e.code() << '\n';
I tried g++-6, g++-5, adding -std=c++1y, -std=c++98, same result. (the latter is ok, though, I believe).
Which is really odd, because the online compiler on the site does compile it.
The single hint I have from a run with -E (preprocessor):
class ios_base
{
# 246 "/usr/include/c++/6/bits/ios_base.h" 3
public:
# 276 "/usr/include/c++/6/bits/ios_base.h" 3
class failure : public exception
{
public:
This looks as if failure does indeed not derive from system_error, which would explain why there is no code(). But why? Its plain Ubuntu g++, its g++-6, its C++14... I have no compiler tweaks, links, hacks...
There seems to be some use of
#if _GLIBCXX_USE_CXX11_ABI
in the vicinity. But does that interfere? If so, how to do I make it un-interfere?
Does anyone have any idea what might be going on here?

Why tcmalloc don't print function name, which provided via dlopen

I have next some project:
main.cpp
#include <iostream>
#include <cstddef>
#include <dlfcn.h>
int main()
{
void* handle = dlopen("./shared_libs/libshared.so", RTLD_LAZY);
if (NULL == handle)
{
std::cerr << "Cannot open library: " << dlerror() << '\n';
return -1;
}
typedef int (*foo_t)(const std::size_t);
foo_t foo = reinterpret_cast<foo_t>(dlsym(handle, "foo"));
const char* dlsym_error = dlerror();
if (dlsym_error)
{
std::cerr << "Cannot load symbol 'foo': " << dlsym_error << '\n';
dlclose(handle);
return -2;
}
std::cout << "call foo" << std::endl;
foo(10);
dlclose(handle);
return 0;
}
shared.cpp:
#include <cstddef>
#include <iostream>
extern "C"
{
int foo(const std::size_t size)
{
int b = size / size;
int* a = new int[size];
std::cout << "leaky code here" << std::endl;
}
}
and Makefile:
all:
g++ -fPIC -g -c shared.cpp
g++ -shared -o shared_libs/libshared.so -g shared.o
g++ -L shared_libs/ -g main.cpp -ldl
I use tcmalloc for debug this test program, which load dynamically libshared.so:foo and execute it.run command:
LD_PRELOAD=/usr/local/lib/libtcmalloc.so HEAPCHECK=normal ./a.out
The 1 largest leaks:
Using local file ./a.out.
Leak of 40 bytes in 1 objects allocated from:
# 7fe3460bd9ba 0x00007fe3460bd9ba
# 400b43 main
# 7fe346c33ec5 __libc_start_main
# 400999 _start
# 0 _init
Why I get address 0x00007fe3460bd9ba instead of line in foo function?
please help
P.s. I tried to use gdb with LD_PRELOAD=.../tcmalloc.so, but I get:
"Someone is ptrace()ing us; will turn itself off Turning perftools heap leak checking off"
Try removing dlclose call.
It's known issue that heap checker & profilers can't handle unloaded
shared objects.

Why is my exception caught on some configurations and on others is not?

I have a program throwing an exception that is caught on some configurations (Suse Linux, g++ version 4.4.1) as expected but is obviously not caught on another, here: SunOS 5.10, g++ version 3.3.2. Following is the implementation of my exception class:
CException.hpp:
#ifndef _CEXCEPTION_HPP
#define _CEXCEPTION_HPP
#include <string>
#include <sstream>
#include <exception>
#include <stdlib.h>
#include <iostream>
class CException : public std::exception {
public:
CException();
CException(const std::string& error_msg);
CException( const std::stringstream& error_msg );
CException( const std::ostringstream& error_msg );
virtual ~CException() throw();
const char* what() const throw();
static void myTerminate()
{
std::cout << "unhandled CException" << std::endl;
exit(1);
};
private:
std::string m_error_msg;
};
CException.cpp:
#include "CException.hpp"
#include <string>
#include <sstream>
CException::CException()
{
std::set_terminate(myTerminate);
m_error_msg = "default exception";
}
CException::CException(const std::string& error_msg)
{
std::set_terminate(myTerminate);
m_error_msg = error_msg;
}
CException::CException(const std::stringstream& error_msg)
{
std::set_terminate(myTerminate);
m_error_msg = error_msg.str();
}
CException::CException(const std::ostringstream& error_msg)
{
std::set_terminate(myTerminate);
m_error_msg = error_msg.str();
}
CException::~CException() throw()
{
}
const char* CException::what() const throw()
{
return m_error_msg.c_str();
}
#endif /* _CEXCEPTION_HPP */
Unfortunately, I've not been able to create a simple program to reproduce the issue, but I will try to outline the code.
The exception is thrown in a function foo() in some file Auxiliary.cpp:
std::ostringstream errmsg;
//...
errmsg << "Error occured.";
throw CException( errmsg );
Function foo() is used in the main program:
#include Auxiliary.hpp
//...
int main( int argc, char** argv )
{
try {
//...
foo();
} catch ( CException e ) {
std::cout << "Caught CException" << std::endl;
std::cout << "This is the error: " << e.what( ) << std::endl;
} catch ( std::exception& e ) {
std::cout << "std exception: " << e.what( ) << std::endl;
} catch ( ... ) {
std::cout << "unknown exception: " << std::endl;
}
I can see that the exception isn't caught as the program exits with printing unhandled CException which is defined by myTerminate().
I've tried the -fexceptions option to the GNU compiler without success. The compiler options are actually the same on both systems.
At the moment I just can't figure out what the problem is. Any ideas are appreciated. Thanks!
I've found out that the problem is caused by the use of a Fortran95 compiler. It is used as a linker when building the program on a Sun machine, on other machines g++ is used. I have no idea what exactly the problem is but I think I'll just switch to g++ on the Sun machines as well.