我已经通过使用 ptrace()
跟踪它停止了一个进程系统调用。这实际上发送了一个 kill -sigstop <pid>
到流程。
现在我检查 [heap] 区域,这是我从 /proc/<pid>/maps
获得的
但是读取堆内存范围内的某些地址返回不同的值!
ptrace(PEEKDATA*, <pid>, <addr>, null) => 33
ptrace(PEEKDATA*, <pid>, <addr>, null) => 34
ptrace(PEEKDATA*, <pid>, <addr>, null) => 34
随着时间的推移(不重复调用)值增加 1,直到字节在 63 处溢出并再次从 0 开始!
我做了完整性测试并直接从 /proc/<pid>/mem
中读出值
返回相同的值。它也随着时间的推移而增加。
更多背景:
我是 ptrace()
正在玩一款名为 Rogue Legacy 的游戏,其堆大小约为 2 亿个地址。游戏的进程层次结构如下所示:
- SteamChildMonit
- 流氓遗产
- RogueLegacy.bin//<- 我跟踪这个过程,它停止了窗口动画和音乐
- 流氓遗产
更新:ptrace 附加到各个线程。它以 pid 作为参数,但 pid 既可以是进程也可以是线程。我假设它始终是一个过程,只是现在这个不准确的模型对我来说是错误的。那么,在我的示例中,“RogueLegacy.bin”只是一个跟踪线程,还有另一个未停止的线程正在导致堆更改。
多个线程共享堆作为公共(public)资源。这也意味着 我们必须小心处理多线程应用程序中的 peekdata,因为受到审查的数据可能会因其他正在运行的线程的主权而发生变化。
最佳答案
我想我将其缩小为一个解决方案:
给定一个多线程应用程序,所有线程都共享相同的堆地址空间
- foo线程
- 条形线
qux线程
以及运行我们的 ptrace 调用的进程(在本例中为单线程进程):
跟踪线程
如果我们 ptrace(PTRACE_ATTACH ..) 到 foo-thread,我们使 tracer-thread 成为另一个父线程 foo 线程。根据 ptrace 的文档,发送一个 SIGSTOP,停止 线程。但是这个由 tracer-thread 发送的 SIGSTOP 只停止 foo-thread 而不是任何 其他线程!
但是如果我们直接向 foo-thread 发送一个SIGSTOP,即不是通过 attach ptrace call,那么整个进程,以及它的线程 foo- 和 bar-thread 都是 停止了。
这是 ptrace 成为临时寄养家庭的特殊性的一个例子 必须考虑线程。
关于linux - 停止进程但堆仍在变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42426046/