gpt4 book ai didi

c++ - 初始化文件范围变量时出现段错误

转载 作者:行者123 更新时间:2023-11-30 04:17:46 29 4
gpt4 key购买 nike

我遇到的情况是,我试图在共享对象构造函数中初始化一个文件作用域变量 std::string。在代码中可能会更清楚:

#include <string>
#include <dlfcn.h>
#include <cstring>
static std::string pathToDaemon; // daemon should always be in the same dir as my *.so
__attribute__((constructor))
static void SetPath()
{
int lastSlash(0):
Dl_info dl_info;
memset(&dl_info, 0, sizeof(dl_info));

if((dladdr((void*)SetPath, &dl_info)) == 0)
throw up;

pathToDaemon = dl_info.dli_fname; // **whoops, segfault here**
lastSlash = pathToDaemon.find_last_of('/');
if(std::string::npos == lastSlash)
{
// no slash, but in this dir
pathToDaemon = "progd";
}
else
{
pathToDaemon.erase(pathToDaemon.begin() + (lastSlash+1), pathToDaemon.end());
pathToDaemon.append("progd");
}

std::cout << "DEBUG: path to daemon is: " << pathToDaemon << std::endl;
}

我有一个非常简单的程序可以做同样的事情:一个概念测试驱动程序,如果你愿意的话。其中的代码看起来就像这样:一个“共享对象 ctor”,它在加载文件时使用 dladdr() 来存储 *.so 文件的路径。

我尝试过的修改:

namespace {
std::string pathToDaemon;
__attribute__((constructor))
void SetPath() {
// function def
}
}

static std::string pathToDaemon;
__attribute__((constructor))
void SetPath() { // this function not static
// function def
}

std::string pathToDaemon; // variable not static
__attribute__((constructor))
void SetPath() { // this function not static
// function def
}

您在上面看到的示例位于一个编译成静态对象库和 DLL 的文件中。编译过程:

  • static.a 的选项:--std=C++0x -c -Os。
  • shared.so 的选项:-Wl,--whole-archive/path/to/static.a -Wl,--no-whole-archive -lz -lrt -ldl -Wl,-Bstatic -lboost_python -lboost_thread -lboost_regex -lboost_system -Wl,-Bdynamic -fPIC -shared -o mymodule.so [大量更多对象将静态内容包装到 python 中]

在更大的项目中,我必须克服的困难使构建过程比我的小测试驱动程序所需的复杂得多。这让我认为问题出在那里。任何人都可以阐明我所缺少的东西吗?

谢谢,安迪

最佳答案

我认为给出我找到的答案是值得的。问题是由于共享库加载的复杂性。经过一番挖掘后,我发现在启用优化的情况下编译代码时,我可以在我的测试台程序中重现该问题。这证实了变量在被构造函数访问时确实不存在的假设。

GCC 包括一些用于 C++ 的额外工具,允许开发人员在代码初始化期间强制某些事情在特定时间发生。更准确地说,它允许某些事情按特定顺序而不是特定时间发生。

例如:

int someVar(55) __attribute__((init_priority(101)));

// This function is a lower priority than the initialization above
// so, this will happen *after*
__attribute__((constructor(102)))
void SomeFunc() {
// do important stuff
if(someVar == 55) {
// do something here that important too
someVar = 44;
}
}

即使启用了优化,我也能够使用这些工具在试验台计划中取得成功。当应用于我更大的图书馆时,随之而来的幸福是短暂的。最终,问题是由于如此大量代码的性质以及变量存在的方式有问题。使用这些机制并不可靠。

因为我想避免重复调用评估路径,即

std::string GetPath() {
Dl_info dl_info;
dladdr((void*)GetPath, &dl_info);
// do wonderful stuff to find the path
return dl_info.dli_fname;
}

事实证明,解决方案比我尝试的要简单得多:

namespace {
std::string PathToProgram() {
Dl_info dl_info;
dladdr((void*)PathToProgram, &dl_info);
std::string pathVar(dl_info.dli_fname);

// do amazing things to find the last slash and remove the shared object
// from that path and append the name of the external daemon
return pathVar;
}

std::string DaemonPath() {
// I'd forgotten that static variables, like this, are initialized
// only once due to compiler magic.
static const std::string pathToDaemon(PathToProgram());
return pathToDaemon;
}
}

如您所见,这正是我想要的,而且不那么困惑。一切只发生一次,除了调用 DaemonPath(),一切都保留在翻译单元内。

我希望这对将来遇到此问题的人有所帮助。

安迪

关于c++ - 初始化文件范围变量时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16847146/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com