【问题标题】:Can we access dangling pointer /access other process memory similar to anti-virus? Would memory leak be possible for such inter-process access?我们可以访问悬空指针/访问类似于防病毒的其他进程内存吗?这种进程间访问是否​​可能发生内存泄漏?
【发布时间】:2014-03-19 18:09:45
【问题描述】:

我一直认为,尝试访问动态释放(首先分配,然后删除/释放)的内存最终会导致核心转储。 但是,当我执行下面的代码时,它成功了。

 int* ptr = new int(3);
delete ptr;

cout << "value : " << *ptr << "  " << ptr;

所以我继续创建了一个悬空指针并明确尝试访问内存,但现在它被转储了。

int* aptr;
aptr = (int*)0x561778;
cout << "value : " << *aptr << "  " << aptr;

1) 如果我们无法访问超出给定进程空间的内存,那么在释放/释放内存后我如何能够访问内存? (第一个例子)

另外,如果是这种情况,那么防病毒软件如何扫描其他进程分配的内存?

2) 如果我动态分配但不释放内存,则会导致内存泄漏。 但是如果我的整个过程都被杀死了怎么办?或完成执行,所以被关闭。 那么操作系统不会确保清理分配给该进程的所有资源吗?那么内存泄漏只会发生在长期运行的进程中吗?

如果这是真的,那么当我明确尝试访问另一个进程的内容时,操作系统将如何确保它不会释放此内存?

【问题讨论】:

  • 你需要查找分页和虚拟内存。您还需要意识到newdelete 至少是从上述事物中删除的三个抽象级别,特别是delete 不会使内存无法访问。
  • E#1。是未定义的行为。如果它确实崩溃了,你会很幸运。尚未在该内存位置重写数据,这就是仍然打印数据的原因。 E#2。也是未定义的,因为aptr 指向内存中的随机位置或已删除的内存块。我认为 Q#2 是一个相当合理的问题。
  • 它在这两种情况下的未定义行为和未定义包括显然按(不)预期工作。至于杀毒软件,他们可能使用this之类的东西。

标签: c++ pointers operating-system coredump antivirus


【解决方案1】:

1) 如果我们不能访问超出给定进程空间的内存,那么如何 是我释放/释放内存后能够访问内存吗? (第一个例子)

因为 C 或 C++ 运行时会保留一个“堆”内存,并且当您调用 free 或 delete 时,内存实际上并没有呈现为对进程不可用,它只是简单地放回了进程的“空闲内存”区域堆,所以它会被重用。这样做是因为进程分配一些内存、释放它、再次分配一些、释放它等是很常见的。例如

void readfile(const std::string& fname)
{
    std::ifstream f(fname.c_str());
    std::string* content = new std::string;
    while(cin.getline(content))
    {
       ...
    }
    delete content;
}

这个函数(愚蠢的是,因为我们不应该分配std::string)将首先为std::string分配空间,然后在getline调用被调用时为std:string内的内容[可能分几个部分]分配空间读取文件。例如`std::ifstream 中可能还有其他内存分配。

堆旨在最大限度地减少它要求操作系统将内存从全局物理内存映射/取消映射到特定进程的次数,因为它在性能方面非常“昂贵”,几乎可以映射和取消映射虚拟内存所有处理器(特别是,从其他内核卸载现已失效的内存页面将涉及向另一个处理器发送消息,另一个处理器停止它当前正在执行的操作,更新它的虚拟映射,然后回复“我已经完成了” ,然后继续原处)。当然,如果操作系统在进程停止使用它时没有取消映射进程的内存,那么同一个进程确实可以“使用”该内存地址来查找其他进程的内容——这将是一件坏事,所以操作系统将强制所有处理器内核放弃它的内存映射,然后该位内存可以再次用于另一个进程[至少]。

编辑:澄清一下,堆有时会将内存释放回操作系统。例如,如果您进行 LARGE 分配,然后释放相同的分配,它可能会立即取消映射,因此您将无法在释放后访问内存。在内存被释放后对内存的任何访问都是未定义的行为,运行时可以(并且经常会)在那时对内存做任何它喜欢的事情。最常见的情况是:

  1. 保持原样,但将其放入“释放”堆中。
  2. 保留它作为释放的内存,但用一些“神奇”模式填充它以检测它何时被写入,因此可以检测到“释放后使用”(检测非常好!)
  3. 内存未映射,不再可供当前进程使用。
  4. 几乎立即将内存分配给其他用途,并再次使用。

同一个操作系统可以在不同时间以几乎任何顺序使用这些场景中的任何一个。

另外,如果是这种情况,那么防病毒软件如何扫描内存 由其他进程分配?

完全不同的问题。他们要么使用调试接口来读取另一个进程的内存,要么使用他们自己的内核驱动程序功能,该功能使用允许任何进程读取任何其他进程的内存的内核函数——毕竟,内核可以做任何事情。 [实际上,反病毒软件通常对从文件加载到内存中的内容更感兴趣,因此应用文件访问过滤器来检查对文件的读取/写入数据,而不是扫描内存中的内容]

2) 如果我动态分配但不释放内存,那么它会 导致内存泄漏。但是如果我的整个过程都被杀死了怎么办?或者 完成执行,所以关闭。那么操作系统不会确保清理 分配给这个进程的所有资源?内存泄漏也是如此 只发生在长期运行的进程中?

当进程死亡时,进程的内存被释放。总是,每次。或者,您可以通过启动分配大量内存的进程、故意杀死它、再次运行它、杀死它、运行、杀死等来导致系统失败。那将是一件坏事,对吧?

你当然可以有一个非常快的内存泄漏。试试:

 std:string str;

 str.append(100000, 'x');
 std::vector<std::string> v;

 int i = 0;
 while(1)
 {
     std::cout << "i=" << i << std::endl;
     v.push_back(str);

在系统启动 swappng 之前不会花费那么多秒,稍后它会被杀死(如果你不觉得无聊,先杀死它)。如果你这样做,预计 linux 系统会变得相当迟钝......

如果这是真的,那么当我明确地尝试访问 另一个过程操作系统如何确保它不会释放这个 内存?

一个正常的进程将无法访问属于另一个进程的内存——只有通过调试接口或专门编写的内核驱动程序等有限的接口才能做到这一点。或者通过使用操作系统支持的共享内存,当然,在操作系统允许的情况下,相同的内存被映射到两个不同的进程中。

这些访问另一个进程内存的方法将涉及某种形式的“引用计数”[事实上,同样适用于例如,如果进程当前正在尝试保存一个 1000MB 文件的系统调用,并且该进程是为一个原因或另一个被杀死 - 说另一个线程导致不可恢复的故障] - 操作系统跟踪给定内存有多少“用户”,这样它就不会从某个进程的脚下拉扯地毯[或本身]。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-24
    • 2021-04-27
    • 2010-12-31
    • 2017-11-18
    • 2011-12-14
    • 2019-10-05
    • 2011-10-07
    • 1970-01-01
    相关资源
    最近更新 更多