Jim*_*ell 12 c++ memory free pointers
我的观察是,如果free( ptr )调用if ptr不是指向系统分配的内存的有效指针,则会发生访问冲突.让我们说我这样称呼free:
LPVOID ptr = (LPVOID)0x12345678;
free( ptr );
这肯定会导致访问冲突.有没有办法测试指向的内存位置ptr是否是有效的系统分配内存?
在我看来,Windows操作系统内核的内存管理部分必须知道已分配了哪些内存以及剩余的内存用于分配.否则,它怎么知道是否有足够的内存来满足给定的请求?(修辞) 也就是说,似乎有理由断定必须有一个函数(或一组函数)允许用户确定指针是否是有效的系统分配内存.也许微软没有公开这些功能.如果微软没有提供这样的API,我只能假定它是出于故意和特定的原因.提供这样一个钩子进入系统是否会对系统安全造成重大威胁?
情况报告
虽然知道内存指针是否有效在许多情况下都很有用,但这是我的特殊情况:
我正在为新的硬件编写驱动程序,以替换通过USB连接到PC的现有硬件.我的任务是编写新的驱动程序,以便对当前驱动程序的现有API的调用将继续在使用它的PC应用程序中工作.因此,对现有应用程序唯一需要的更改是在启动时加载适当的驱动程序DLL.这里的问题是现有的驱动程序使用回调将接收到的串行消息发送给应用程序; 指向包含消息的已分配内存的指针通过回调从驱动程序传递到应用程序.然后,应用程序负责调用另一个驱动程序API,通过将相同的指针从应用程序传递给驱动程序来释放内存.在这种情况下,第二个API无法确定应用程序是否实际传回了指向有效内存的指针.
In *_*ico 19
实际上,有一些函数调用IsBadReadPtr(),IsBadWritePtr(),IsBadStringPtr(),和IsBadCodePtr()那可能做的工作,但永远不要使用它.我之所以提到这一点,是因为你意识到这些选择是不可追求的.
你最好确保你设置所有指针NULL或0什么时候指向什么,并检查它.
例如:
// Set ptr to zero right after deleting the pointee.
delete ptr; // It's okay to call delete on zero pointers, but it
            // certainly doesn't hurt to check.
注意:这可能是某些编译器的性能问题(请参阅本页的"代码大小"部分),因此首先对零进行自检可能是值得的.
ptr = 0;
// Set ptr to zero right after freeing the pointee.
if(ptr != 0)
{
    free(ptr); // According to Matteo Italia (see comments)
               // it's also okay to pass a zero pointer, but
               // again it doesn't hurt.
    ptr = 0;
}
// Initialize to zero right away if this won't take on a value for now.
void* ptr = 0;
更好的是使用RAII的某些变体,而不必直接处理指针:
class Resource
{
public:
    // You can also use a factory pattern and make this constructor
    // private.
    Resource() : ptr(0)
    {
        ptr = malloc(42); // Or new[] or AcquiteArray() or something
        // Fill ptr buffer with some valid values
    }
    // Allow users to work directly with the resource, if applicable
    void* GetPtr() const { return ptr; }
    ~Resource()
    {
        if(ptr != 0)
        {
            free(ptr); // Or delete[] or ReleaseArray() or something
            // Assignment not actually necessary in this case since
            // the destructor is always the last thing that is called
            // on an object before it dies.
            ptr = 0;            
        }
    }
private:
    void* ptr;
};
或者如果适用,使用标准容器(这实际上是RAII的应用):
std::vector<char> arrayOfChars;
Joh*_*ing 16
简答:不.
在Windows中有一个函数可以告诉你指针是否指向真实内存(IsBadreadPtr()和它的同类),但它不起作用,你永远不应该使用它!
问题的真正解决方案是始终将指针初始化为NULL,并在将它们重置为NULL后重置为NULL delete.
你真的暗示了一个更大的问题:你如何确保你的代码在客户端代码面前继续正常运行?
这真的应该是一个问题.没有简单的答案.但这取决于你的意思是"继续正常运作".
有两种理论.有人说,即使客户端代码向您发送完整的废话,您也应该能够跋涉,丢弃垃圾并处理好的数据.实现这一目标的关键是异常处理.如果在处理客户端数据时遇到异常,请回滚状态并尝试返回,就好像他们根本没有打过你一样.
另一种理论是甚至不试图继续,而只是失败.失败可以是优雅的,并且应该包括一些全面的日志记录,以便可以识别问题并希望在实验室中修复.启动错误消息.告诉用户下次要尝试的一些事情.生成小型转储,并自动将它们发送回商店.但随后,关闭.
我倾向于赞同第二种理论.当客户端代码开始发送垃圾时,系统的稳定性通常处于危险之中.他们可能已经破坏了堆.可能无法获得所需的资源.谁知道问题可能是什么.你可能会得到一些好的数据,但你甚至不知道好的数据是否真的好.因此,尽快关闭,以降低风险.
为了解决您的具体问题,我认为您不必担心检查指针.如果应用程序将DLL传递给无效地址,则表示应用程序中存在内存管理问题.无论您如何编写驱动程序代码,都无法修复真正的错误.
为了帮助应用程序开发人员调试他们的问题,您可以向返回应用程序的对象添加幻数.调用库时释放对象,检查编号,如果不存在,则打印调试警告,不要释放它!即:
#define DATA_MAGIC 0x12345678
struct data {
    int foo;    /* The actual object data. */
    int magic;  /* Magic number for memory debugging. */
};
struct data *api_recv_data() {
    struct data *d = malloc(sizeof(*d));
    d->foo = whatever;
    d->magic = DATA_MAGIC;
    return d;
}
void api_free_data(struct data *d) {
    if (d->magic == DATA_MAGIC) {
        d->magic = 0;
        free(d);
    } else {
        fprintf(stderr, "api_free_data() asked to free invalid data %p\n", d);
    }
}
这只是一种调试技术. 如果应用程序没有内存错误,这将正常工作.如果应用程序确实存在问题,这可能会提醒开发人员注意错误.它只能起作用,因为你的实际问题比初始问题所表明的要严格得多.
不可以.你应该只有一个指向你知道有效的内存的指针,通常是因为你在同一个程序中分配了它.正确跟踪你的内存分配,然后你甚至不需要这个!
此外,您通过尝试free无效指针来调用未定义的行为,因此它可能会崩溃或执行任何操作.
此外,free是从C继承的C++标准库的函数,而不是WinAPI函数.
首先,在标准中没有什么可以保证这样的事情(free非malloced指针是未定义的行为).
无论如何,路过free只是试图访问该内存的扭曲路线; 如果你想检查一个指针指向的内存是否在Windows上是可读/可写的,你真的应该尝试并准备好处理SEH异常; 这实际上是IsBadxxxPtr函数的功能,通过在返回代码中转换这种异常.
然而,这是一种隐藏微妙错误的方法,正如Raymond Chen的帖子中所解释的那样; 所以,长话短说,没有没有安全的方法来确定指针是否指向有效的东西,我认为,如果你需要在某个地方进行这样的测试,那么代码中就存在一些设计缺陷.
| 归档时间: | 
 | 
| 查看次数: | 8054 次 | 
| 最近记录: |