BOOST_DLL_ALIAS_SECTIONED missing specified BOOST_DLL_SECTION after performing a strip - boost

I created a shared library using BOOST using the following to specify the factory method:
BOOST_DLL_ALIAS_SECTIONED(
MyPlugin::create, // Plugin's factory method being exported
create_plugin, // Alias for factory method.
MySectionName) // The section name that all factory methods are grouped in.
The create() method returns a shared pointer to the MyPlugin object.
I then load the shared library and try to fetch the particular section using:
boost::dll::library_info inf(shared_library_path);
And then locate the above section with:
std::vector<std::string> sections = inf.sections();
if (std::find(sections.begin(), sections.end(), "MySectionName") == sections.end()) {
// Do something
} else
{
// Error out
}
If the shared library was not stripped, the above allows me to find
MySectionName within its contents and perform actions within the bracket.
If I however strip the shared library (default: strip library_name.so), the
above library info no longer lists the defined section and I hit the error out
condition.
I can protect the particular factory method during strip by specifying
"-Kcreate" flag, but while that works with this simple shared library, more
complex libraries end up with more missing symbols and it almost feels
counterproductive to keep expanding the "-K" flag.
Is here an easier way of using BOOST for plugin creation using the above method
and still allow stripping out debug information without having to expand with
"-K" flag?
Thank you

I couldn't reproduce this with shorter section names:
File test.cpp
#include <boost/dll.hpp>
#include <boost/dll/alias.hpp>
namespace MyPlugin {
struct X{};
static auto create() {
return std::make_shared<X>();
}
}
BOOST_DLL_ALIAS_SECTIONED(
MyPlugin::create,
Factory,
MySect)
File test1.cpp
#include <boost/dll.hpp>
#include <iostream>
int main() {
boost::dll::library_info inf("libsotest.so");
std::vector<std::string> s = inf.sections();
auto found = (std::find(s.begin(), s.end(), "MySect") != s.end());
std::cout << "Found: " << std::boolalpha << found << "\n";
}
Prints:
In fact, I cannot compile it at all when the section name exceeds 9 characters:
test.cpp|11 col 1| error: static assertion failed: Some platforms require section names to be at most 8 bytes
|| 11 | BOOST_DLL_ALIAS_SECTIONED(
Perhaps your problem is related to such restrictions?

Related

Native C extension not finding code used by Ruby core

Based on browsing the Ruby API sources for Array#length and Range#begin I know that macros RARRAY_LEN and RANGE_BEG exist and are used to implement the corresponding methods:
Array#length
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
}
Range#begin
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
However, while the code below has no problems with RARRAY_LEN I have been unable to get RANGE_BEG to work:
test.c
#include "test.h"
VALUE rb_mTest = Qnil;
VALUE rb_cTest = Qnil;
VALUE super_initialize(VALUE self) {
return self;
}
VALUE array_len(VALUE self, VALUE ary) {
Check_Type(ary, T_ARRAY);
return LONG2NUM(RARRAY_LEN(ary)); // this works
}
VALUE range_begin(VALUE self, VALUE rng) {
if (rb_obj_is_kind_of(rng, rb_cRange)) {
// return RANGE_BEG(rng); // doesn't work
return rb_funcall(rng, rb_intern("begin"), 0); // this works
}
return Qnil;
}
void Init_test(void) {
rb_mTest = rb_define_module("RangeTest");
rb_cTest = rb_define_class_under(rb_mTest, "Tester", rb_cObject);
rb_define_method(rb_cTest, "initialize", super_initialize, 0);
rb_define_method(rb_cTest, "array_len", array_len, 1);
rb_define_method(rb_cTest, "begin_value", range_begin, 1);
}
test.h
#ifndef TEST_H
#define TEST_H 1
#include "ruby.h"
VALUE super_initialize(VALUE self);
void Init_test(void);
VALUE range_begin(VALUE self, VALUE rng);
VALUE array_len(VALUE self, VALUE ary);
#endif /* TEST_H */
When the commented line is made active, the compiler generates this error message:
error: implicit declaration of function 'RANGE_BEG' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return RANGE_BEG(rng);
^
1 error generated.
This sounds to me like I'm missing an include, but 1) no additional include is required for RARRAY_LEN; 2) including range.h didn't change anything; and 3) I've failed to find where RANGE_BEG is defined when I tried searching with grep.
As you can see, I have a work-around using rb_funcall but would like to know why one macro found in the Ruby source works while another doesn't. The extension docs I've looked at have also implied that the macro versions are more efficient than function call versions for data access, so using the macro would be preferable.
To sum up, I'm hoping anybody can tell me a suitable incantation to get the compiler to access RANGE_BEG. This is happening on MacOS 12.4 (Monterey) using ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21] installed by HomeBrew, with CPPFLAGS=-I/opt/homebrew/opt/ruby/include and LDFLAGS=-L/opt/homebrew/opt/ruby/lib.
For whatever reason the RANGE_XXX macros are not included in the API headers. They are only defined and used in the internal Ruby implementation itself. It seems they wanted to keep these methods private, probably to ensure backwards and forward compatibility in case the internal implementation changes over time.
However, you get almost identical access through the API by using the provided method rb_range_values:
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp);
You can peek at its implementation here, where you can see it actually makes use of those internal macros.
To use it you simply have to define the returned variables and then call:
VALUE beg;
VALUE end;
int excl;
rb_range_values(range, &beg, &end, &excl);
Although this method does a little bit more than you need, it seeems likely it is still faster than a version using funcall, but you would need to benchmark to make sure.

why the output of the auto variable displays something not related to type?

I tried a example on Auto for variable initialization and STL in C++. For normal variable, type was printed using : typeid(var_name).name() to print i (integer) / d(float) / pi(pointer) which works fine.
But while working on STL,
`#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<string> st;
st.push_back("geeks");
st.push_back("for");
for (auto it = st.begin(); it != st.end(); it++)
cout << typeid(it).name() << "\n";
return 0;
}
`
which gives output like,
`N9__gnu_cxx17__normal_iteratorIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIS6_SaIS6_EEEE
N9__gnu_cxx17__normal_iteratorIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIS6_SaIS6_EEEE`
and I am unable to understand the output logic behind it, can anyone explain why it is giving output like this? and thanks in advance
That's the "name mangled" version of the name of the type of it. typeinfo::name() is not required by the standard to return a name in human-readable format (a shortcoming IMHO) and GCC doesn't do so.
To get the actual, human-readable name, you need to call the abi::__cxa_demangle() function provided by GCC, but note that this is non-portable so if your project needs to work on different compilers you'll need to wrap it appropriately.

Why does making this virtual destructor inline fix a linker issue?

If I have a pure virtual class InterfaceA that consists solely of a pure virtual destructor, why do I have to define the destructor as inline? I I don't I get an error when I try to link it.
Below is an admittedly contrived example, however it illustrates the point. The point does not compile for me using cmake and g++. However, if I change the InterfaceA destructor definition as follows - inline InterfaceA::~InterfaceA(){}; then it compiles.
Why is this? What does the inline keyword do?
// InterfaceA.h, include guards ommitted for clarity
class InterfaceA
{
public:
virtual ~InterfaceA() = 0;
};
InterfaceA::~InterfaceA(){};
// A.h, include guards ommitted for clarity
#include "InterfaceA.h"
class A : public InterfaceA
{
public:
A(int val)
: myVal(val){};
~A(){};
int myVal;
};
// AUser.h, include guards ommitted for clarity
#include "InterfaceA.h"
class AUser
{
public:
AUser(InterfaceA& anA)
: myA(anA){};
~AUser(){};
int getVal() const;
private:
InterfaceA& myA;
};
// AUser.cpp
#include "AUser.h"
#include "A.h"
int AUser::getVal() const
{
A& anA = static_cast<A&>(myA);
return anA.myVal;
}
// main.cpp
#include "AUser.h"
#include "A.h"
#include <iostream>
int main(){
A anA(1);
AUser user(anA);
std::cout << "value = " << user.getVal() << std::endl;
return 0;
}
You have to use the inline keyword when defining functions in header files. If you do not, and the file is included in more than one translation unit, the function will be defined twice (or more times).
The linker error is probably something like "Symbol ... is multiply defined" right?
If you defined the member function in the body of the class, it would be implicitly inline and it would also work.
See this answer
To answer the question "What does the inline keyword do?":
In the old days it would be used to ask the compiler to inline functions i.e. insert the code whenever the function is used instead of adding a function call. Eventually it turned into a simple suggestion since compiler optimizers became more knowledgeable about which functions were inline candidates. These days it is used almost exclusively to define functions in header files that must have external linkage.
inline means that compiler is allowed to add code directly to where the function was called. It also removes function from external linkage, so both your compile units would have local version of.. pure destructor.
// InterfaceA.h, include guards ommitted for clarity
class InterfaceA
{
public:
virtual ~InterfaceA() = 0;
};
You declare destructor virtual, so compiler almost never would make it inline. Why? because virtual functions are called through vtable - a internal working of virtual functions system, vtable most likely implemented as an array of pointers to member functions. If function is inlined, it would have no address, no legal pointer. If attempt to get address of function is taken, then compiler silently disregards inline keyword. The other effect will be still in place: inlined destructor stops to be visible to linker.
It may look like declaring pure virtual destructor looks like oxymoron , but it isn't. The pure destructor is kind of destructor that would be always called without causing UB. Its presence would make class abstract, but the implicit call in sequence of destructor calls would still happen. If you didn't declare destructor body, it would lead to an UB, e.g. purecall exception on Windows.
If you don't need an abstract base class, then inline definition will suffice:
class InterfaceA
{
public:
virtual ~InterfaceA() {}
};
that is treated by compiler as inline as well, but mixing inline definition and pure member declaration is not allowed.

Calling object destructor whose type is nested inside of a class?

Suppose a class contains a type defined by a nested using whose destructor needs to be explicitly invoked. Is it necessary to use using to create a local type that doesn't include the namespace separator (::)?
In this contrived example, I want to call A::WeakPtr's destructor, like:
wp->~A::WeakPtr();
instead of like:
using AWeakPtr = A::WeakPtr;
wp->~AWeakPtr()
Is this doable? Here's a complete example.
#include <cstdlib>
#include <iostream>
#include <memory>
struct A : std::enable_shared_from_this<A> {
using SharedPtr = std::shared_ptr<A>;
using WeakPtr = std::weak_ptr<A>;
A() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
~A() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
int
main() {
{
std::unique_ptr<A::WeakPtr, void(*)(void*)>
uwp(static_cast<A::WeakPtr*>(std::malloc(sizeof(A::WeakPtr))), std::free);
A::WeakPtr* wp = uwp.get();
{
auto sp = std::make_shared<A>();
new(wp) A::WeakPtr(sp);
if (wp->lock())
std::cout << "Locked\n";
else
std::cout << "Unlocked\n";
}
if (wp->lock())
std::cerr << "EUNPOSSIBLE\n";
else
std::cout << "Unable to obtain lock\n";
// Need the following 'using' statement because the following is invalid syntax:
// wp->~A::WeakPtr();
using AWeakPtr = A::WeakPtr;
wp->~AWeakPtr();
// Is there a way to call A::WeakPtr without the using statement?
}
std::cout << "memory held by uwp has been free(3)'ed\n";
}
It seems like there should be a way to defeat the :: namespace separator with a typename scattered in there somewhere, but it doesn't look like it's possible. Obviously it's not the end of the world if it's not possible, but my curio is getting the better of me.
UPDATE
As suggested by #DanielFrey and #DyP's fantastic answer, the correct syntax is indeed
wp->A::WeakPtr::~WeakPtr();
but this doesn't work and is a bug (#12350) in clang++ (as of 2013-09-28).
Are you looking for
wp->A::WeakPtr::~WeakPtr();
?
The destructor call using a qualified-id here must consist of:
postfix-expression -> nested-name-specifier ~ class-name ()
The postfix-expression here is wp, and the part after -> forms a single qualified-id (w/o the parens).
Grammatically, the following is also possible:
postfix-expression -> nested-name-specifier ~ decltype-specifier ()
However, this second form is forbidden explicitly in [expr.prim.general]/9:
The form ~ decltype-specifier also denotes the destructor, but it shall not be used as the unqualified-id in a qualified-id.
The class-name in the first form can also be a typedef-name [class.name]/5:
A typedef-name (7.1.3) that names a class type, or a cv-qualified version thereof, is also a class-name.
For the lookup of this class-name after the ~, there's a special name lookup rule in [basic.lookup.qual]/5:
Similarly, in a qualified-id of the form:
nested-name-specifieropt class-name :: ~ class-name
the second class-name is looked up in the same scope as the first.
This means that the second WeakPtr in A::WeakPtr :: ~WeakPtr should be found. It is a typedef-name naming a class, therefore a class-name, and it's looked up in the scope of A. gcc follows this rule, clang++3.4 does not.
Therefore, wp->A::WeakPtr :: ~WeakPtr(); as suggested by Daniel Frey (and my first, deleted comment/guess) should work.
Alternative approaches:
Using a helper function:
template<class T>
void destroy(T& t)
{ t.~T(); }
Using a decltype-specifier w/o a qualified-id. This one is tricky, as the type of decltype(*wp) is A::WeakPtr&, as *wp yields an lvalue. However, we can convert the the expression to a prvalue to get rid of the reference:
wp->~decltype((A::WeakPtr)*wp)();
// alternatively, w/o explicitly mentioning the type:
wp->~decltype((std::remove_pointer<decltype(wp)>::type)*wp)();
// simpler, using a helper function again:
template<class T> T helper(T const&);
wp->~decltype(helper(*wp))();
Production:
Begin with the function call [expr.post]/1:
postfix-expression ( expression-listopt )
Where the postfix-expression here is produced via:
postfix-expression -> templateopt id-expression
This postfix-expression here maps to wp (in wp->~something()).
The id-expression contains the destructor "name" [expr.prim.general]:
id-expression:
unqualified-id
qualified-id
We do need a qualified-id here, so [expr.prim.general]/8:
qualified-id:
nested-name-specifier templateopt unqualified-id
:: identifier
:: operator-function-id
:: literal-operator-id
:: template-id
Only the first one is of interest, so we look at unqualified-id s:
unqualified-id:
identifier
operator-function-id
conversion-function-id
literal-operator-id
~ class-name
~ decltype-specifier
template-id
Where the two with a ~ can be used to call a destructor.

scoped_lock doesn't work on file?

According to the link below, I wrote a small test case. But it doesn't work. Any idea is appreciated!
Reference:
http://www.cppprog.com/boost_doc/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_careful_iostream
#include <iostream>
#include <fstream>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
using namespace std;
using namespace boost::interprocess;
int main()
{
ofstream file_out("fileLock.txt");
file_lock f_lock("fileLock.txt");
{
scoped_lock<file_lock> e_lock(f_lock); // it works if I comment this out
file_out << 10;
file_out.flush();
file_out.close();
}
return 0;
}
Running the test on Linux produces your desired output. I notice these two warnings:
The page you reference has this warning: "If you are using a std::fstream/native file handle to write to the file while using file locks on that file, don't close the file before releasing all the locks of the file."
Boost::file_lock apparently uses LockFileEx on Windows. MSDN has this to say: "If the locking process opens the file a second time, it cannot access the specified region through this second handle until it unlocks the region."
It seems like, on Windows at least, the file lock is per-handle, not per-file. As near as I can tell, that means that your program is guaranteed to fail under Windows.
Your code appears to be susceptible to this long-standing bug on the boost trac site: https://svn.boost.org/trac/boost/ticket/2796
The title of that bug is "interprocess::file_lock has incorrect behavior when win32 api is enabled".
Here is a workaround to append in a file with a file locking based on Boost 1.44.
#include "boost/format.hpp"
#include "boost/interprocess/detail/os_file_functions.hpp"
namespace ip = boost::interprocess;
namespace ipc = boost::interprocess::detail;
void fileLocking_withHandle()
{
static const string filename = "fileLocking_withHandle.txt";
// Get file handle
boost::interprocess::file_handle_t pFile = ipc::create_or_open_file(filename.c_str(), ip::read_write);
if ((pFile == 0 || pFile == ipc::invalid_file()))
{
throw runtime_error(boost::str(boost::format("File Writer fail to open output file: %1%") % filename).c_str());
}
// Lock file
ipc::acquire_file_lock(pFile);
// Move writing pointer to the end of the file
ipc::set_file_pointer(pFile, 0, ip::file_end);
// Write in file
ipc::write_file(pFile, (const void*)("bla"), 3);
// Unlock file
ipc::release_file_lock(pFile);
// Close file
ipc::close_file(pFile);
}

Resources