c++ - 破坏全局和静态对象的最佳方法?
问题描述
结束具有静态存储持续时间的对象生命周期的最佳方法是什么?
当前实现找到调用者__run_exit_handlers
,然后将用于确定__exit_funcs
.
但是,这很容易失败,因为__run_exit_handlers
即使在具有相同版本的 glibc 中,偏移量也可以轻松更改。可以做的另一件事是先解析地址,__run_exit_handlers
然后使用它来查找调用者,而不是使用硬编码的调用偏移量。
#include <iostream>
#include <fstream>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cstdio>
#include <execinfo.h>
struct A
{
A(std::string pName)
: mName(pName)
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
~A()
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
volatile int i = 0;
std::string mName;
};
A a{"a"};
A b{"b"};
A c{"c"};
class StaticDestroyer
{
public:
StaticDestroyer()
{
std::ifstream maps("/proc/self/maps", std::ios::in);
char line[1024];
uint8_t* magic = nullptr;
while (maps.getline(line, sizeof(line)))
{
char perms[4];
uint8_t *magicbegin, *magicend;
std::string lsv(line);
if (std::string::npos == lsv.find("/libc-",0,6)) continue;
std::sscanf(line, "%lx-%lx %4s", &magicbegin, &magicend, perms);
if (perms[0]==114 && perms[2]==120)
{
magic = findMagic(magicbegin, magicend);
break;
}
}
if (magic==nullptr)
throw std::runtime_error("magic not found!");
mHead = *(HakaishinNode**)magic;
}
bool destroy(void* pTarget)
{
HakaishinNode *current = mHead;
while (nullptr != current)
{
for (size_t i = current->idx-1 ; i>0; i--)
{
const Hakaishin *const f = ¤t->fns[i];
if (4 == f->type && pTarget == f->arg)
{
void (*destruct) (void *arg, int status) = f->fn;
asm ("ror $2*8+1, %0\nxor %%fs:%c2, %0" : "=r" (destruct) : "0" (destruct), "i" (48));
destruct (f->arg, 1);
if (current->idx-1 != i) for (size_t j = i; j < current->idx ; j++) current->fns[j] = current->fns[j+1];
current->idx--;
return true;
}
}
current = current->next;
}
return false;
}
private:
struct Hakaishin
{
long int type;
void (*fn) (void *arg, int status);
void *arg;
void *dso_handle;
};
struct HakaishinNode
{
struct HakaishinNode *next;
size_t idx;
Hakaishin fns[32];
};
uint8_t* findMagic(uint8_t* magicbegin, uint8_t* magicend)
{
const void* const begin = magicbegin;
int32_t ptr;
while ((magicbegin+7) <= magicend)
{
if (magicbegin[0]==0x48 && (magicbegin[1]==0x8b || magicbegin[1]==0x8d))
{
std::memcpy(&ptr, magicbegin+3, sizeof(ptr));
uint8_t* magicp = magicbegin+ptr+7;
if (ptr==0x38a5c1) return magicp;
}
magicbegin++;
}
return nullptr;
}
HakaishinNode* mHead = nullptr;
};
A& getA()
{
static A a{"getA"};
return a;
}
A& getA2()
{
static A a{"getA2"};
return a;
}
int main()
{
std::printf("entering...\n");
StaticDestroyer d;
d.destroy(&a);
d.destroy(&b);
auto& ga = getA();
d.destroy(&ga);
getA2();
std::printf("returning...\n");
}
输出:
A::A(std::string) a
A::A(std::string) b
A::A(std::string) c
entering...
A::~A() a
A::~A() b
A::A(std::string) getA
A::~A() getA
A::A(std::string) getA2
returning...
A::~A() getA2
A::~A() c
解决方案
需要以这种方式处理生命周期的默认行为表明您的应用程序存在设计缺陷。
因此,您应该考虑重组程序以不使用全局变量。或者至少改变你处理全局变量的方式。所以如果你真的需要全局变量并提前释放它们,那么切换到unique_ptr
:
#include <iostream>
#include <functional>
#include <memory>
struct A
{
A(std::string pName)
: mName(pName)
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
~A()
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
volatile int i = 0;
std::string mName;
};
auto a = std::make_unique<A>("a");
auto b = std::make_unique<A>("b");
auto c = std::make_unique<A>("c");
auto& getA()
{
static auto a = std::make_unique<A>("getA");
return a;
}
auto& getA2()
{
static auto a = std::make_unique<A>("getA2");
return a;
}
int main() {
std::printf("entering...\n");
a = nullptr;
b = nullptr;
c = nullptr;
getA();
getA2();
getA() = nullptr;
std::printf("returning...\n");
}
这样你可以释放unique_ptr
之前管理的对象,但如果你不nullptr
手动设置它们,它们将在退出时自动释放。
推荐阅读
- python - 如何对某个目录中的多个图像进行K-means聚类并将其保存到另一个目录?(在本地)
- amazon-web-services - 如何使用 cloudformation 更新到 t3?
- lucene - 支持 Lucene 的 RDF4J 中的空间 SPARQL 查询
- android - Firebase电话号码认证,每次验证码都过期
- python - 谷歌 aiy 视觉套件编译器:从 tensorboard 获取输出节点
- reactjs - Azure 应用服务上的符号链接上的 yarn EPERM(不允许操作)
- java - 为什么客户端在使用 Netty 不断地从服务器获取图像时会阻塞?
- php - 如何使用codeigniter中的不同提交按钮从同一表单调用不同的函数?
- mongodb - MongoDb:如何从 .gz 文件导入转储数据?
- html - 在行下方添加元素