dlopen fails in a library instantiating an object - libstdc++

We have a minimal working example of dlopen that works.
void* lib = dlopen("servlets.so", RTLD_NOW);
void* p = dlsym(lib, "getServlets");
However, if we add another function to the shared library (not even if it is called) then the library does not work (even though the code is never called)
uint32_t count = 0;
Servlet** servlets;
extern "C" {
void generate() {
servlets = new Servlet*[3];
servlets[0] = new Servlet(...);
}
Servlet** getServlets() { return servlets; }
uint32_t getServletNum() { return count; }
}
This must be because the code in the shared object is referencing some symbol that we don't have, but we do not know what.
The code compiles and links without a problem.
Is there any way to find out what the error is? No error is reported, except that the library pointer returns NULL and the library does not load.
How do we link to a library so that dlopen works?

No error is reported, except that the library pointer returns NULL
A library pointer can't return anything. You probably mean dlopen() returns NULL.
If that's what you mean, that is the error being reported. If you want to know more about why the error was returned, use dlerror() to find out.

Related

Associate clsid with Runtime Class for winrt::create_instance Function to Late Bind Runtime Class in External DLL

How can a Guid be associated with a Runtime Class to be used in the function call winrt::create_instance, so a winrt Runtime Class can be late bound? I don't see how in MIDL 3.0--though Interfaces work with uuid and version. Is this the answer to late binding in WinRT?
I still don't know how to use winrt::create_instance, but I took a really deep look into base.h. I found plenty of guts to late bind to a WinRT component dll using def calls and interop. This is my solution to the problem. It works. Choosing the right way to hold IUnknown was important, and there was some specifics I'm still working out; like why I have to wrap the IUnknown in a winrt::impl::abi_t<> (WinRT/COM conversion?). Using the following code you simply load the dll by file name (with qualified path if not in in the executable directory), and call the class according to it's runtime namespace.classname. It is absolutely not necessary to add the activatableclass to the Packackage.appxmanifest or to reference the winmd. A search shows a lot of people looking for this, but there is a general reluctance to point this out. It's just like COM really, with its own quirks.
UINT32 ret = 0;
void* dllHandle = WINRT_IMPL_LoadLibraryW(L"Project.dll");
if (!dllHandle) { throw; };
void* pProc = WINRT_IMPL_GetProcAddress(dllHandle, "DllGetActivationFactory");
auto DllGetActivationFactory = reinterpret_cast<int32_t(__stdcall*)(void* classId, void** factory)>(pProc);
static const WCHAR* cname = L"namespace.classname";
const UINT32 cnamelen = wcslen(cname);
HSTRING hcname = NULL;
HSTRING_HEADER header;
HRESULT hr = WindowsCreateStringReference(cname, cnamelen, &header, &hcname);
com_ptr< winrt::impl::abi_t<winrt::Windows::Foundation::IActivationFactory> > oCOMActivationFactory{ nullptr };
ret = (*DllGetActivationFactory)(&header, oCOMActivationFactory.put_void());
com_ptr< winrt::impl::abi_t<winrt::Windows::Foundation::IUnknown> > iObj{ nullptr };
ret = oCOMActivationFactory.get()->ActivateInstance(iObj.put_void());
winrt::com_ptr<ProxyServer::ImplementationInterface> iImplementationInterface{ nullptr };
winrt::copy_from_abi(iImplementationInterface, iObj.as<ProxyServer::ImplementationInterface>());
iImplementationInterface.get()->MyFunction();
oCOMActivationFactory.detach();
WindowsDeleteString(hcname);

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.

What happens when a copy of a shared pointer is created whose object contains a unique pointer?

I have been messing about with SFML, figuring out how a simple 2D game could be built. I just noticed this behaviour and couldn't figure out what's going on. Sample code for what is confusing me:
struct Unique {};
class Shared {
public:
Shared() {
p = make_unique<Unique>();
}
unique_ptr<Unique> p;
};
void SharedCopyTest() {
Shared foo;
//Shared copy = foo; // Error: function "Shared::Shared(const Shared &)"
// (declared implicitly) cannot be referenced
// -- it is a deleted function
shared_ptr<Shared> sharedPtr = make_shared<Shared>();
shared_ptr<Shared> ptrCopy = sharedPtr; // No error
}
At this point, &sharedPtr->p == &ptrCopy->p; but how is it possible, if p is of type unique_ptr<T>?
The semantics of std::shared_ptr is that no copies are made of the pointed-to object. Instead it's the std::shared_ptr object itself that is copied, and it increases the use-counter of the shared pointer.
That why it works, because you're not actually making a copy of the Shared object.
This can be easily verified by using the shared pointers get function to get the "raw" pointer:
sharedPtr.get() == ptrCopy.get()

Clang does not allow static_cast to parent class with template, while g++ and icc allow

I am trying my C++11 code to see if all recent major compiler supports the features I used, and the following shortened code
#include <valarray>
struct T
{
double vv[3];
};
class V : public std::valarray<T>
{
public:
auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this)))
{
return std::begin(static_cast<std::valarray<T>>(*this));
}
};
int main(void)
{
}
would compile with g++ 4.8.1(from Debian sid repository), Intel C++ compiler 13.1.1 20130313, but not Clang 3.3-2(from Debian sid repository).
The given error is:
test.cpp:11:73: error: no viable conversion from 'V' to 'std::valarray<T>'
auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this)))
^~~~~
However, code like this
namespace std
{
auto begin(V& vv) -> decltype(std::begin(static_cast<V::parent_t>(vv)))
{
return std::begin(static_cast<V::parent_t>(vv));
}
}
would compile by all three compilers.
My question is: is the code itself allowed by the language standard, just Clang miscompiled it, or it is only supported by g++/icc extension? Or it is undefined behavior?
The code very dangerous and needs to be fixed even for GCC and ICC.
You're doing a static_cast to a value type, not a reference or pointer. That creates a new temporary valarray object, so the const overload of begin gets called (probably not what you intended), and the iterator returned by begin() refers to the temporary which goes out of scope immediately, so the returned iterator is invalid and dereferencing it is undefined behaviour.
The code will compile like this:
auto begin()->decltype(std::begin(std::declval<std::valarray<T>&>()))
{
return std::begin(static_cast<std::valarray<T>&>(*this));
/* cast to reference type! ^^^^^^^^^^^^^^^^^ */
}
The decltype doesn't need to cast this, it just needs to know the type of calling std::begin on a valarray<T>, so it doesn't matter if the type is incomplete because you don't need a cast.
In the body of the function the type is considered complete anyway, so the cast is valid.

LoadString with numeric idetifier

i have problem with this code:
int
WINAPI
Getdesc(IN WORD wcode,
OUT LPWSTR lpBuf)
{
WCHAR szDescription[256];
int res = LoadStringW(NULL,wcode,szDescription,256);
if(res == 0)
{
wcscpy(lpBuf, L"Undefined");
return 0;
}
else
{
wcscpy(lpBuf,szDescription);
return 0;
}
}
The function is placed in a DLL, and when i access it, it always returns "Undefined",
I think there is problem in my LoadString call, but i can't figure it out.
I'm new to windows programming, any help would be appreciated
The problem is that you are passing NULL as the HINSTANCE parameter. That means that you look for the resource in the executable host and not the DLL. You'll have to pass the module handle of the DLL. You are provided with that instance handle as the first parameter passed to your DllMain function.
If you are compiling with MSVC then you could use __ImageBase to obtain the module handle. Personally I would suggest that making a note of the value passed to DllMain is a cleaner approach. It avoids taking a dependency on one specific compiler.
Note also that you can call GetLastError in case LoadString fails to obtain more information about the reason for the error. It's quite possible that would have helped you identify the fault.

Resources