众所周知,在运行时修改多线程应用程序中的进程环境是自找麻烦。然而,我们并不总是可以控制谁访问它。
在这种情况下,我们依赖于一些第三方库,我们只有二进制分发版(.so 文件)。不幸的是,他们倾向于滥用
setenv()
函数,这偶尔会导致我们的记录器在 strftime()
调用期间崩溃。有时它可能几天内崩溃一次,有时每天可能崩溃几次,但堆栈跟踪总是以getenv()
结束,正如你可以想象的那样,这对用户来说并不是很愉快。
我想到的一个潜在的修复方法是挂钩
setenv()
和 getenv()
函数并在调用原始实现之前使用全局互斥体,我正在寻找更多不包含汇编的面向未来的方法。
在 Windows 上,我可以使用 Microsoft Detours 轻松做到这一点,但我不知道关于 *nix 世界有任何简单的方法。
总的来说,我希望有一个适用于 Android C 库(Bionic)、Apple Clang 及其 C 库和 Linux 的 glibc 的工作解决方案。 Android 是我最优先考虑的,因为与任何其他平台相比,Android 的崩溃频率要高出许多倍。还要提一下 LD_PRELOAD 不是一个选项,它应该是来自主可执行文件的完全 C 代码解决方案,我可以在开始任何复杂例程之前执行它。
附注我知道使用这种钩子我无法防止直接使用全局
environ
变量,但我相信它不会被第 3 方直接使用。
正确修复您的代码。
你的代码显然是这样的:
setenv
设置 TZ。strftime
或
getenv
备份 TZ。setenv
设置 TZ。strftime
setenv
恢复TZ。这些需要更改为
setenv
设置 TZ。strftime
或
getenv
备份 TZ。setenv
设置 TZ。strftime
setenv
恢复TZ。这些模式都不能通过替换
getenv
和 setenv
来修复。
在第一种模式中,您需要替换
setenv
来获取锁定,并且需要替换 strftime
来释放锁定。
在第二种模式中,您需要替换
getenv
来获取锁,并且需要替换 setenv
来释放锁,但仅当要求将环境设置回最新调用的 时getenv
回来了。
这是极其脆弱的。
如果您的代码不遵循这些模式之一,它可能会严重失败,例如陷入死锁。