I am trying to figure out to load the function shm_open dynamically at runtime and have hit a wall.
My current code is as such:
CMakeLists.txt
project(dlsysm_stack_overflow_example)
cmake_minimum_required(VERSION 3.16)
add_executable(${PROJECT_NAME}
main.cpp
custom_mman.cpp
)
target_link_libraries(${PROJECT_NAME}
dl
)
custom_mman.cpp
#include <iostream>
#define _GNU_SOURCE
#include <dlfcn.h>
extern "C"
{
int shm_open(const char* name, int oflag, mode_t mode)
{
using ShmOpenFuncPtr_t = int (*)(const char*, int, mode_t);
static ShmOpenFuncPtr_t real_shm_open = nullptr;
std::cout << "custom shm_open\n";
if (nullptr == real_shm_open)
{
real_shm_open = reinterpret_cast<ShmOpenFuncPtr_t>(dlsym(RTLD_NEXT, "shm_open"));
char* error = dlerror();
if (error != nullptr)
{
std::cout << "could not load shm_open at runtime! error: " << error << "\n";
return -1;
}
}
return real_shm_open(name, oflag, mode);
}
}
main.cpp
#include <sys/mman.h>
#include <fcntl.h>
#include <iostream>
int main(int argc, char** argv)
{
int return_value = shm_open("/shm_name", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
std::cout << "return_value: " << return_value << "\n";
return 0;
}
At the moment, because I give the executable the custom_mann.cpp source file, the linker finds my definition of shm_open before the standard library definition and calls that instead. My intention is then to do some logic before calling the real shm_open function.
However, the call to dlsym is returning a null pointer so when real_shm_open is called, a segfault occurs. Strangely, dlerror does not set the error code so the function doesn't return early as I would expect if dlsym is not returning the proper pointer.
Any ideas why this could be happening is much appreciated?
shm_open is supplied by librt.so. Per the Linux shm_open() man page (bolding mine):
NAME
shm_open, shm_unlink - create/open or unlink POSIX shared memory
objects
SYNOPSIS
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
int shm_open(const char *name, int oflag, mode_t mode);
int shm_unlink(const char *name);
Link with -lrt.
You need to add rt to your target_link_libraries.
You should be checking the value returned from dlsym() directly for errors. Per the dlsym man page:
RETURN VALUE
On success, these functions return the address associated with
symbol. On failure, they return NULL; the cause of the error can
be diagnosed using dlerror(3).
Additionally, your code is not thread-safe:
static ShmOpenFuncPtr_t real_shm_open = nullptr;
std::cout << "custom shm_open\n";
if (nullptr == real_shm_open)
{
real_shm_open = reinterpret_cast<ShmOpenFuncPtr_t>(dlsym(RTLD_NEXT, "shm_open"));
char* error = dlerror();
if (error != nullptr)
{
std::cout << "could not load shm_open at runtime! error: " << error << "\n";
return -1;
}
}
Two or more threads can be executing the code in parallel, resulting in a corrupted real_shm_open that is neither NULL nor correct.
Related
I would like to control various ov5640 camera parameters by using ioctl and VIDIOC_S_CTRL from V4L2 in the following manner:
#include <string>
#include <iostream>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <cstring>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#define IOCTL_TRIES 3
#define CLEAR(x) memset (&(x), 0, sizeof (x))
static int xioctl(int fd, int request, void *arg)
{
int r;
int tries = IOCTL_TRIES;
do {
r = ioctl(fd, request, arg);
} while (--tries > 0 && r == -1 && EINTR == errno);
return r;
}
bool v4l2_ctrl_set(int fd, uint32_t id, int val)
{
struct v4l2_control ctrl;
CLEAR(ctrl);
ctrl.id = id;
ctrl.value = val;
if (xioctl(fd, VIDIOC_S_CTRL, &ctrl) == -1) {
std::cout << "Failed to set ctrl with id "
<< id << " to value " << val
<< "\nerror (" << errno << "): " << strerror(errno) << std::endl;
return false;
}
return true;
}
int main()
{
int fd = open("/dev/video0", O_RDWR | O_NONBLOCK);
if (fd == -1) {
std::cout << "Failed to open the camera" << std::endl;
return -1;
}
v4l2_ctrl_set(fd, V4L2_CID_SATURATION, 100);
return 0;
}
Unfortunately ioctl fails and I get error (25): Inappropriate ioctl for device. I'm using Intrinsyc Open-Q 820 µSOM with linaro 4.14. I've managed to add some debugs prints to ov5640 driver file in ov5640_s_ctrl function before if (sensor->power_count == 0) { (in case there were problems with power save mode) and recompile the kernel. I ran the code, but looking through dmesg my printk message doesn't get printed, so that means that ov5640_s_ctrl doesn't get called even though the callback is set:
static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
.g_volatile_ctrl = ov5640_g_volatile_ctrl,
.s_ctrl = ov5640_s_ctrl,
};
Am I using V4L2 wrong? Should I enable something before setting the controls? It's even more confusing since I manage to get an image from the camera with v4l2, but I can't set/get any controls.
In the the kernel source code of ov5640.c that you supplied, the driver is assigned the flag V4L2_SUBDEV_FL_HAS_DEVNODE which means it might supply a subdev node /dev/v4l-subdevX. According to the kernel docs:
Device nodes named v4l-subdevX can be created in /dev to access sub-devices directly. If a sub-device supports direct userspace configuration it must set the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered.`
So you can try to set the control directly from the v4l-subdevX node if it exists.
So I'm trying to load a .dylib file at runtime in c++ and calling a function within it. It does not seem to be any problem loading the file but when i try to create a function-pointer to the "print" function it's result is NULL.
Here is my code:
/* main.cpp */
#include <iostream>
#include <string>
#include <dlfcn.h>
#include "test.hpp"
int main(int argc, const char * argv[]) {
std::string path = argv[0];
std::size_t last = path.find_last_of("/");
// get path to execution folder
path = path.substr(0, last)+"/";
const char * filename = (path+"dylibs/libtest.dylib").c_str();
// open libtest.dylib
void* dylib = dlopen(filename, RTLD_LAZY);
if (dylib == NULL) {
std::cout << "unable to load " << filename << " Library!" << std::endl;
return 1;
}
// get print function from libtest.dylib
void (*print)(const char * str)= (void(*)(const char*))dlsym(dylib, "print");
if (print == NULL) {
std::cout << "unable to load " << filename << " print function!" << std::endl;
dlclose(dylib);
return 2;
}
// test the print function
print("Herro Word!");
dlclose(dylib);
return 0;
}
test dylib headerfile
/* test.hpp */
#ifndef test_hpp
#define test_hpp
void print(const char * str);
#endif
the dylib c++ file
#include <iostream>
#include "test.hpp"
void print(const char * str) {
std::cout << str << std::endl;
}
the output when running is:
unable to load /Users/usr/Library/Developer/Xcode/DerivedData/project/Build/Products/Debug/dylibs/libtest.dylib print function!
Program ended with exit code: 2
I am quite new to c++ and have never loaded dylibs before. Any help would be much appreciated!
Try qualifying the print function declaration with extern "C" to get around the name mangling that is likely going on.
Here's a nice article on the topic: http://www.tldp.org/HOWTO/C++-dlopen/theproblem.html (solution discussion on page following)
I am trying to use clang+llvm 3.6 to JIT compile several C functions (each can eventually be very large).
Unfortunately I the function pointer that LLVM provides makes the program SEGFAULT.
So far I have following code:
#include <iostream>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/FrontendDiagnostic.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Frontend/Utils.h>
#include <clang/Parse/ParseAST.h>
#include <clang/Lex/Preprocessor.h>
#include <llvm/Analysis/Passes.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/Verifier.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/Linker/Linker.h>
int main(int argc, char *argv[]) {
using namespace llvm;
using namespace clang;
static const char* clangArgv [] = {"program", "-x", "c", "string-input"};
static const int clangArgc = sizeof (clangArgv) / sizeof (clangArgv[0]);
// C functions to be compiled (they could eventually be extremely large)
std::map<std::string, std::string> func2Source;
func2Source["getOne"] = "int getOne() {return 1;}";
func2Source["getTwo"] = "int getTwo() {return 2;}";
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
std::unique_ptr<llvm::Linker> linker;
std::unique_ptr<llvm::LLVMContext> context(new llvm::LLVMContext());
std::unique_ptr<llvm::Module> module;
/**
* add each C function to the same module
*/
for (const auto& p : func2Source) {
const std::string& source = p.second;
IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *diagClient = new TextDiagnosticPrinter(llvm::errs(), &*diagOpts); // will be owned by diags
IntrusiveRefCntPtr<DiagnosticIDs> diagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> diags(new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
ArrayRef<const char *> args(clangArgv + 1, // skip program name
clangArgc - 1);
std::unique_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
if (invocation.get() == nullptr) {
std::cerr << "Failed to create compiler invocation" << std::endl;
exit(1);
}
CompilerInvocation::setLangDefaults(*invocation->getLangOpts(), IK_C,
LangStandard::lang_unspecified);
invocation->getFrontendOpts().DisableFree = false; // make sure we free memory (by default it does not)
// Create a compiler instance to handle the actual work.
CompilerInstance compiler;
compiler.setInvocation(invocation.release());
// Create the compilers actual diagnostics engine.
compiler.createDiagnostics(); //compiler.createDiagnostics(argc, const_cast<char**> (argv));
if (!compiler.hasDiagnostics()) {
std::cerr << "No diagnostics" << std::endl;
exit(1);
}
// Create memory buffer with source text
std::unique_ptr<llvm::MemoryBuffer> buffer = llvm::MemoryBuffer::getMemBufferCopy(source, "SIMPLE_BUFFER");
if (buffer.get() == nullptr) {
std::cerr << "Failed to create memory buffer" << std::endl;
exit(1);
}
// Remap auxiliary name "string-input" to memory buffer
PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
po.addRemappedFile("string-input", buffer.release());
// Create and execute the frontend to generate an LLVM bitcode module.
clang::EmitLLVMOnlyAction action(context.get());
if (!compiler.ExecuteAction(action)) {
std::cerr << "Failed to emit LLVM bitcode" << std::endl;
exit(1);
}
std::unique_ptr<llvm::Module> module1 = action.takeModule();
if (module1.get() == nullptr) {
std::cerr << "No module" << std::endl;
exit(1);
}
if (linker.get() == nullptr) {
module.reset(module1.release());
linker.reset(new llvm::Linker(module.get()));
} else {
if (linker->linkInModule(module1.release())) {
std::cerr << "LLVM failed to link module" << std::endl;
exit(1);
}
}
}
llvm::InitializeNativeTarget();
llvm::Module* m = module.get();
std::string errStr;
std::unique_ptr<llvm::ExecutionEngine> executionEngine(EngineBuilder(std::move(module))
.setErrorStr(&errStr)
.setEngineKind(EngineKind::JIT)
.setMCJITMemoryManager(std::unique_ptr<SectionMemoryManager>(new SectionMemoryManager()))
.setVerifyModules(true)
.create());
if (!executionEngine.get()) {
std::cerr << "Could not create ExecutionEngine: " + errStr << std::endl;
exit(1);
}
executionEngine->finalizeObject();
/**
* Lets try to use each function
*/
for (const auto& p : func2Source) {
const std::string& funcName = p.first;
llvm::Function* func = m->getFunction(funcName);
if (func == nullptr) {
std::cerr << "Unable to find function '" << funcName << "' in LLVM module" << std::endl;
exit(1);
}
// Validate the generated code, checking for consistency.
llvm::raw_os_ostream os(std::cerr);
bool failed = llvm::verifyFunction(*func, &os);
if (failed) {
std::cerr << "Failed to verify function '" << funcName << "' in LLVM module" << std::endl;
exit(1);
}
#if 1
func->dump(); // Dump the function for exposition purposes.
// JIT the function, returning a function pointer.
void *fPtr = executionEngine->getPointerToFunction(func); ///// BAD function pointer!!!!
// Cast it to the right type (takes no arguments, returns a double) so we
// can call it as a native function.
int (*funcPtr)();
*(int **) (&funcPtr) = *(int **) fPtr;
int v = (*funcPtr)();
std::cout << "return: " << v << std::endl;
#else // THIS DOES NOT WORK EITHER:
// JIT the function, returning a function pointer.
uint64_t fPtr = executionEngine->getFunctionAddress(funcName); ///// BAD function pointer!!!!
if (fPtr == 0) {
std::cerr << "Unable to find function '" << funcName << "' in LLVM module" << std::endl;
exit(1);
}
int (*funcPtr)();
*(int **) (&funcPtr) = *(int **) fPtr;
int v = (*funcPtr)();
std::cout << "return: " << v << std::endl;
#endif
}
}
Can anyone help me pin-point the problem?
(I'm running this in linux-ubuntu 15.04)
This assignment is incredibly messed up:
*(int **) (&funcPtr) = *(int **) fPtr;
Not only does it violate strict-aliasing to write an int* and then use it as a function pointer on the next line, but a data pointer is often not large enough to hold an entire code pointer.
The safe approach is either
memcpy(funcPtr, fPtr, sizeof funcPtr);
or
funcPtr = reinterpret_cast<decltype(funcPtr)>(fPtr);
I am trying to learn how to embed lua in a C program, but I am not great at reading technical documents, and I haven't found any current tutorials. This is my program:
#include <iostream>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
void report_errors(lua_State*, int);
int main(int argc, char** argv) {
for (int n = 1; n < argc; ++n) {
const char* file = argv[n];
lua_State *L = luaL_newstate();
luaL_openlibs(L);
std::cerr << "-- Loading File: " << file << std::endl;
int s = luaL_loadfile(L, file);
if (s == 0) {
s = lua_pcall(L, 0, LUA_MULTRET, 0);
}
report_errors(L, s);
lua_close(L);
std::cerr << std::endl;
}
return 0;
}
void report_errors(lua_State *L, int status) {
if (status) {
std::cerr << "-- " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
}
The compiler gives undefined reference errors for luaL_newstate, luaL_openlibs, luaL_loadfilex, lua_pcallk, and lua_close. I am using Code::Blocks one a Windows computer and I have added the lua include directory to all of the search paths and liblua53.a to the link libraries. The IDE autocompleted the header names and the parser displays most of the lua functions, but with a brief search I found that the parser could not find either lua_newstate or luaL_newstate. Why does it find some of the functions and not others?
In c++ you should include lua.hpp not lua.h. lua.h does not define the extern "C" block to stop the name mangling of the c++ compiler.
The arguments for g++ had -llua before the input file. I put -llua at the end, and everything works fine now.
undefined reference to `luaL_newstate'
Need extern "C" wrapping and also as recommended above put "-llua" at the end.
extern "C" {
#include <lua5.3/lualib.h>
#include <lua5.3/lauxlib.h>
#include <lua5.3/lua.h>
}
gcc -o l -ldl l.cpp -llua5.3
I am trying to access all files in a directory and do some thing on the files under this and the subsequent directories. For this operation I used dirent.h with windows and it manages to get all the files and open and close these files. My problem is, when i try to read some something from them and write to another, as shown below, i get the error shown at the end.
Here is the code:
#include <iostream>
#include <cstring>
#include <sys/stat.h>
#include <dirent.h>
FILE *test_file;
char buffer[51];
void listdir(const char *path)
{
struct dirent *entry;
DIR *dp;
//std::cout << "Dir: " << path << "\n";
if(dp = opendir(path))
{
struct stat buf ;
FILE *input_file;
while((entry = readdir(dp)))
{
std::string p(path);
p += "\\";
p += entry->d_name;
char fpath[250];
//strcpy(fpath,path);
if(!stat(p.c_str(), &buf))
{
if(S_ISREG(buf.st_mode))
{
std::cout << " File: " << entry->d_name << "\n";
sprintf(fpath,"%s\\%s",path,entry->d_name);
input_file=fopen(fpath,"r+b");
test_file=fopen("test_test.txt","a+b");
if(input_file==NULL)
{
std::cout<<"\n Could not open\n"<<entry->d_name<<std::endl;
continue;
}
if(test_file==NULL)
goto z;
else
{
std::cout<<"\n Successfully Opened\n"<<fpath;
fread(buffer,50,1,input_file);
fprintf(test_file,"\n\n%s\n\n",fpath);
fwrite(buffer,50,1,test_file);
fclose(input_file);
fclose(test_file);
// free(buffer);
}
z:
if(test_file=NULL)
fclose(test_file);
}
if(S_ISDIR(buf.st_mode) &&
// the following is to ensure we do not dive into directories "." and ".."
strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..") )
{
listdir(p.c_str());
}
}
else
std::cout << "ERROR in stat\n";
}
// delete buf;
closedir(dp);
}
else
std::cout << "ERROR in opendir\n";
fclose(test_file);
}
int main(int argc, char **argv)
{
listdir(argv[1]);
return 0;
}
It manages to open and read the first file but after the first file it will show the following error and open dbgheap.c
HEAP[direntdir.exe]: Invalid address specified to RtlValidateHeap(
002C0000, 002C5718 ) Windows has triggered a breakpoint in
direntdir.exe.
This may be due to a corruption of the heap, which indicates a bug in
direntdir.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while direntdir.exe has
focus.
The output window may have more diagnostic information.
EDIT:
corrected the errors with the buf variables.
Now i get
Debug Assertion Failed!
... Expression:(buffer!=NULL) ...
You have two variables named buf:
char* buf;
...
struct stat *buf = new struct stat;
The latter hides the first and latter is free()d, even though it was created using new, and then reused without being reallocated.
The latter is also used as an argument to fread(). Rename char* buf and possibly make it local to the function and just use a stack allocated buffer:
char fread_buffer[51];
EDIT:
char* buffer never has memory allocated for it before it used in fread() so the call to fread() could be writing anywhere in memory. Change to:
char buffer[50]; /* as only 50 bytes are read from the file */
and don't call free() on buffer if it is declared this way.
Also, to simplify things just declare buf as:
struct stat buf;
and call stat():
if(!stat(p.c_str(), &buf))
Making these two changes will remove all dynamic memory management from the code.
EDIT 2:
This if is an assignment, not an inequality check:
if(test_file=NULL)
fclose(test_file);
should be:
if(NULL != test_file)
fclose(test_file);