在运行时使用 C 代码挂钩 setenv()、getenv(),使它们线程安全

问题描述 投票:0回答:1

众所周知,在运行时修改多线程应用程序中的进程环境是自找麻烦。然而,我们并不总是可以控制谁访问它。

在这种情况下,我们依赖于一些第三方库,我们只有二进制分发版(.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 方直接使用。

c hook glibc libc bionic
1个回答
0
投票

正确修复您的代码。


你的代码显然是这样的:

  1. setenv
    设置 TZ。
  2. strftime

  1. getenv
    备份 TZ。
  2. setenv
    设置 TZ。
  3. strftime
  4. setenv
    恢复TZ。

这些需要更改为

  1. setenv
    设置 TZ。
  2. strftime
  3. 解锁

  1. getenv
    备份 TZ。
  2. setenv
    设置 TZ。
  3. strftime
  4. setenv
    恢复TZ。
  5. 解锁

这些模式都不能通过替换

getenv
setenv
来修复。

在第一种模式中,您需要替换

setenv
来获取锁定,并且需要替换
strftime
来释放锁定。

在第二种模式中,您需要替换

getenv
来获取锁,并且需要替换
setenv
来释放锁,但仅当要求将环境设置回最新调用的
getenv
回来了。

这是极其脆弱的。

如果您的代码不遵循这些模式之一,它可能会严重失败,例如陷入死锁。

© www.soinside.com 2019 - 2024. All rights reserved.