To use in different threads a non-reentrant DLL, I'm copying it in 4 different folders. It's ugly but mandatory...
This DLL is manually loaded by my application and uses another sublib (which is implicitly linked to the other). So I have something like this :
folder1/
lib1.dll
sublib.dll
folder2/
lib2.dll
sublib.dll
I managed to load the different versions of lib.dll (lib1 and lib2) but the loaded sublib.dll remains the same for both.
I tried the SetDllDirectory and, AddDllDirectory but it's not loading multiple sublib.dll.
for (size_t i { 1 }; i <= threadsCount; ++i)
{
SetDllDirectoryA(nullptr); // Reset.
//SetDllDirectoryA(""); // Plug "binary planting" security hole. `
SetDllDirectoryA(dirPath(i).c_str()); // folderX
HMODULE module = LoadLibraryExA(libPath(i).c_str(), nullptr, LOAD_LIBRARY_SEARCH_USER_DIRS);
if (!module )
{
std::cout << "error loading dll" << std::endl;
return false;
}
// Used after
// FooPrototype foo = (FooPrototype) GetProcAddress(module, "foo");
}
// Run threads with the different 'foo'
Is it possible to load 2 instances of sublib.dll ??
Thanks !
Related
I have a simple program that loads a DLL from the current path
#include <iostream>
#include <windows.h>
using namespace std;
auto loaddll(const char * library) {
auto dllModule = LoadLibrary(library);
if(dllModule == NULL)
throw "Can't load dll";
return dllModule;
}
int main() {
try {
auto Handle = loaddll("ISab.dll");
} catch(const char * error) {
cerr << "An Unexpected error :" << error << endl;
cerr << "Get Last Error : " << GetLastError();
}
}
the load library fails for every DLL in the current path but succeeds for DLL like User.dll
if I ran it output will be like
An Unexpected error :Can't load dll
Get Last Error : 0
this also fails if i specify full path to dll
When a Win32 API call fails, and sets the error code, you must call GetLastError before calling any other Win32 API function. You don't do that.
Raising an exception, streaming to cerr etc. are all liable to call other Win32 API functions and so reset the error code.
Your code must look like this:
auto dllModule = LoadLibrary(library);
if (dllModule == NULL)
auto err = GetLastError();
Once you have the error code you should be better placed to understand why the module could not be loaded. Common error codes for LoadLibrary include:
ERROR_MOD_NOT_FOUND which means that the module, or one of its dependencies, cannot be located by the DLL search.
ERROR_BAD_EXE_FORMAT which invariably means a 32/64 bit mismatch, either with the module you load, or one of its dependencies.
I need to write c++ program which sets path using system() function:
system("set PATH=%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64");
system("nvcc -x cu -o cudapair cudapair.c");
But it doesnt work. It throws error, because path wasn't set. What's the problem?
I need to write c++ program which sets path using system() function
I'm assuming what you actually need to do is write a C++ program that
sets the PATH for the environment in which it will then execute
nvcc -x cu -o cudapair cudapair.c
You think you need to make that environment setting with
the system function, but in fact you don't.
You should understand that a process cannot change its own environment.
A process inherits its environment from its parent process, and it
can change the environment that is inherited by its child processes.
That's why your posted attempt does not work.
system("set PATH=%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64");
executes a child process of your program. That child process gets the same environment settings
as your program, and can't change them. What does that child process do? It invokes the
Windows shell to run the commandline:
set PATH=%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64");
This would change the environment settings of any more child processes that were started
by this commandline. But there aren't any. The commandline makes an environment setting
that no process uses. Your system call returns. That environment setting no longer
exists anywhere. Nothing has changed.
You then call:
system("nvcc -x cu -o cudapair cudapair.c");
which starts a second child process, again with the same environment settings that your
program started with.
What you should do
Get the value of PATH from the environment that your program inherits.
Using that value, create the new value of PATH that you want to pass to your child process.
Put that new value of PATH into the environment your child process will inherit.
Run your child process.
You use system only to do 4.
To do 1, use the Microsoft C library function getenv_s
(It is a secure variant of the Standard C++ std::getenv)
To do 3, use the Microsoft C library function _putenv_s (Note the leading underscore.)
Here is an illustrative program for Visual C++:
#include <iostream>
#include <string>
#include <cstdlib>
const std::size_t ENV_BUF_SIZE = 1024; // Enough for your PATH?
int main()
{
char buf[ENV_BUF_SIZE];
std::size_t bufsize = ENV_BUF_SIZE;
int e = getenv_s(&bufsize,buf,bufsize,"PATH");
if (e) {
std::cerr << "`getenv_s` failed, returned " << e << '\n';
exit(EXIT_FAILURE);
}
std::string env_path = buf;
std::cout << "In main process, `PATH`=" << env_path << std::endl;
env_path += ";C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64";
e = _putenv_s("PATH",env_path.c_str());
if (e) {
std::cerr << "`_putenv_s` failed, returned " << e << std::endl;
exit(EXIT_FAILURE);
}
std::cout << std::endl;
e = std::system("echo \"In child process `PATH`=%PATH%\"");
if (e) {
std::cerr << "`std::system` failed, returned " << e << std::endl;
exit(EXIT_FAILURE);
}
return 0;
}
See it live
I'm using a shared object in my program which is loaded via dlopen().
When I overwrite the library with mv debug/newLibrary.so plugin/usedLibrary.so my program crashes as soon as it tries to interact with the loaded library. I cant even use dlclose(), this gets me a SIGSEV.
What is the best way to handle with this situations?
OS is Linux
Edit: actual code
void DynamicallyLoadedLibrary::loadLibrary() {
// ModificationTime updaten
lastModificationTime = modificationTime();
// Library laden
libraryHandle = dlopen(path.c_str(), RTLD_NOW);
if (!libraryHandle) { // Library gefunden?
throw DynamicLibraryException("Dynamic Library not found: " + path + "\n" + dlerror());
}
// Funktion laden
externalFunction = (dll_function) dlsym(libraryHandle, "run");
char *error;
if ((error = dlerror()) != NULL) { // Funktion gefunden?
throw DynamicLibraryException("Dynamic Library not found: run()\n" + string(error));
}
}
void DynamicallyLoadedLibrary::close() {
if (libraryHandle != nullptr) {
cout << "DLL/close(): " << dlclose(libraryHandle) << endl; // DEBUG
libraryHandle = nullptr;
externalFunction = nullptr;
}
}
void DynamicallyLoadedLibrary::operator()(vector<shared_ptr<ServerData>> &data) {
// Wenn Datei sich geaendert hat, neu laden
if (fileChanged()) {
close();
loadLibrary();
}
externalFunction(data);
}
Edit 2: The Library (UA_String is from open62541)
Its simply build with eclipse and copied in [...]/plugins. Execution works fine until I overwrite it
extern "C" void run(vector<shared_ptr<ServerData>> &data) {
cout << "++++ OPC_WORKING_PACKAGE EXTERN ++++" << endl; // XXX
for (unsigned int i = 0; i < data.size(); i++){
UA_String *uaString = (UA_String*) data[i]->dataReference();
cout << string((char*) uaString->data, uaString->length) << endl;
}
cout << "---- OPC_WORKING_PACKAGE EXTERN ----" << endl; // XXX
}
Your question is unclear.
If you have some /tmp/plugin.so and you do
void* dl = dlopen("/tmp/plugin.so", TRL_NOW);
and later (in the same process) some
rename("/tmp/plugin.so", "/tmp/oldplugin.so")
(or even unlink("/tmp/plugin.so"); ...) you should be able to dlclose(dl);
However, if your build process is making a new one, e.g. you have some make /tmp/plugin.so target, then you really should do a
mv /tmp/plugin.so /tmp/plugin.so~
or even
rm /tmp/plugin.so
before linking the shared library, e.g. before
gcc -shared -Wall -O /tmp/plugin*.pic.o -o /tmp/plugin.so
In other words, be sure that your build procedure is not overwriting bytes in the same inode (of the original /tmp/plugin.so)
So if you overwrite your old /tmp/plugin.so with some mv /tmp/newplugin.so /tmp/plugin.so command in your build process you'll better do a mv /tmp/plugin.so /tmp/plugin.so~ or a rm /tmp/plugin.so just before.
Notice that mmap(2) (internally invoked by dlopen(3)) is actually working on opened inodes. See path_resolution(7). So you could unlink(2) your shared library while still having it dlopen-ed.
So never overwrite bytes in an existing shared library inode; do whatever is necessary to be sure to create a fresh shared library inode in your plugin build procedure.
Read Advanced Linux Programming & Drepper's How to Write a Shared Library
BTW, the real issue is not related to dlopen but to the nature of file descriptors (that is, of opened inodes) on POSIX systems (on which several processes can read and write the same file; the user or sysadmin -or tool developer- is supposed to avoid breaking havoc.).
Use also pmap(1) (as pmap 1234) and/or cat /proc/1234/maps to understand the memory mapping of process of pid 1234 (i.e. its virtual address space).
In practice, the user or sysadmin installing a plugin should ensure that a pristine inode is created for it, or that no process is using that plugin (before installation). It is his responsibility (and is a whole system issue). So you really need to educate your user or sysadmin, and document the issue, e.g. by suggesting the use of install(1) and/or locking utilities like package managers when installing plugins.
PS. Copying in a private copy the shared object before dlopen might improve the situation, but does not solve the issue (what if the shared object source gets updated during the copy?). The real bug is in the build process which overwrites a shared object instead of writing & creating a pristine new inode.
I want to have my DLL's in a subdirectory of the directory where my executable is. My current directory looks like:
Main Folder: [Folder]
Program.exe
sfml.dll
Assets [Folder]
Picture.png
Music.wav
When I really want it to look like:
Main Folder: [Folder]
Program.exe
Assets [Folder]
Picture.png
Music.wav
MyDlls[Folder]
sfml.dll
When I try to put them (DLL's) in a folder I get the error message:
The program can't start because sfml-system-d-2.dll is missing from your computer. Try reinstalling the program to fix this problem.
So, then I looked into explicit linking, and followed the tutorial here:
http://www.dreamincode.net/forums/topic/118076-dlls-explicit-linking/
If explicit linking is not what I need to use, then please tell me what I need to do. Else, please tell me what is wrong with my code below: (Also, I do not know if this is static or dynamic linking..??)
// Startup.h
#ifndef STARTUP_H
#define STARTUP_H
#include <iostream>
#include <windows.h>
class Startup
{
private:
HINSTANCE hDLL;
public:
// Explicitly link SFML DLL's
typedef int(*funcAdd) (int, int);
typedef int(*funcSubtract) (int, int);
void LoadDLLs()
{
// Retrieve DLL handle.
vector<LPCSTR> libraries = {"openal32.dll",
"sfml-audio-2.dll",
"sfml-audio-d-2.dll",
"sfml-graphics-2.dll",
"sfml-graphics-d-2.dll",
"sfml-system-2.dll",
"sfml-system-d-2.dll",
"sfml-window-2.dll",
"sfml-window-d-2.dll"};
for (int i = 0; i < libraries.size(); i++)
{
hDLL = LoadLibrary(libraries[i]);
if (hDLL == NULL)
{
std::cout << "Failed to load library.\n";
}
else
{
funcAdd Add = (funcAdd)GetProcAddress(hDLL, "Add");
funcSubtract Subtract = (funcSubtract)GetProcAddress(hDLL, "Subtract");
if (Add)
std::cout << "10+10=" << Add(10, 10) << std::endl;
if (Subtract)
std::cout << "50-10=" << Subtract(50, 10) << std::endl;
FreeLibrary(hDLL);
}
std::cin.get();
}
};
#endif
You could register an App Path (see link), making sure you add your Applications alternate DLL folder location to the App Path PATH value.
You cannot do what you want directly. The code you attached will work only for dynamic loading dlls, but it is not the case.
What you want to do will be platform specific and you need to set the path for the library before executing the program.
I am writing a game in allegro and would like to load some image files. However, whenever I call al_load_bitmap, I am getting a null pointer. I am using XCode 4.1 as my IDE. I would try compiling using g++ (in case it is a path issue) however I don't know what I need to do in order to compile it in the command line with g++ (simply g++ main.cpp does not work). Anyways, here is my code:
ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
for (int i = 0; i < NUM_TILES; i++)
{
switch (static_cast<Tile>(i)) {
case GRASS:
al_set_path_filename(path, "grass.png");
tileFiles[i] = al_load_bitmap(al_path_cstr(path, '/'));
if (!tileFiles[i])
{
std::cerr<<"grass.png not initialized"<<std::endl;
}
break;
case DIRT:
al_set_path_filename(path, "dirt.png");
tileFiles[i] = al_load_bitmap(al_path_cstr(path, '/'));
if (!tileFiles[i])
{
std::cerr<<"dirt.png not initialized"<<std::endl;
}
break;
default:
std::cerr
<< "Missing case statement for datatype Tile numbered at "
<< i
<< " in Board::Board (float mw, float mh, int tst)"
<< " declared in Board.cpp."
<< std::endl;
break;
}
}
I have already run:
if(!al_init_image_addon()) {
al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
NULL, ALLEGRO_MESSAGEBOX_ERROR);
return -1;
}
and I have also put:
#include "allegro5/allegro_image.h"
#include "allegro5/allegro_native_dialog.h"
at the top of my file. Neither grass.png, nor dirt.png load and they are in the exact same directory as my main.cpp file. I get no compilation errors, but I consistently get the null pointer when I try to load my images, so when it comes time to draw them to the display, they do not show. Please help!
Neither grass.png, nor dirt.png load and they are in the exact same directory as my main.cpp file
Just a debugging tip... If you were to output the result of al_path_cstr(path, '/') to the console, it should be extremely obvious why the call is failing.
ALLEGRO_RESOURCES_PATH is the location of "bundled resources," which on OS X means the directory of the executable file. (If you were to use an app bundle, then it would be the resource folder of the bundle.) As a quick check, just copy the images into the same directory that your executable file is being built.
Most IDEs have very odd directory structures, IMO. I would ultimately set it up so that you are building into something like:
/src/main.c
/include/main.h
/obj/release
/obj/debug
/bin/game.exe
/bin/game-debug.exe
/bin/image.png
But that's just my preference. Use whatever you like, but you should read the docs again to get a clear picture of the different locations that al_get_standard_path() reveals.
Okay, I had been having the same problem, and I was absolutely positive that I was looking in the correct directory and that the resources for the program were there. I used al_path_cstr(path, '/') and allegro's working directory was as expected. Then I looked at the resource file sizes....
All my resources in my build directory were zero bytes. Copied them over myself and it solved the issue. I hope this helps some one out!