如何从漏洞本身返回的函数中修复内存泄漏?
例如,我创建一个char* returnMe = new char[24324];
returnMe,最终从函数返回。你如何解释这个内存泄漏?一旦它被退回,你怎么摧毁它?我有一些内存管理规则会在内存泄漏上抛出运行时错误来阻止它,所以我不能忽略它。
Orrr我是个傻瓜,这不是泄密,暗示泄漏在其他地方?
答案 0 :(得分:13)
如果你退回它并不是一个泄漏(好吧,它不是你的泄漏)。
您需要考虑资源所有权。如果从函数返回已分配的缓冲区,函数的调用者现在负责它。 API应该明确表示它们在完成后需要被释放。
无论是自己释放它还是将它传递给你的另一个函数来释放它(封装以防止需要完成而不仅仅是释放内存)是API的另一个问题。
答案 1 :(得分:3)
即使返回指针,您仍然可以delete[]
指针returnMe
。除非您忘记删除returnMe
,否则不会造成内存泄漏。
答案 2 :(得分:2)
如果你的函数返回一个已分配的缓冲区,那么就没有泄漏。更好的是,如果客户端代码故意调用您的例程并且不对它返回的内容做任何事情,则会发生泄漏,但在这种情况下,客户端代码违反了您的合同。
当缓冲区返回时,它由客户端代码控制。通常,对于可靠的编程来说,让分配/释放发生在同一层是一个好主意。这意味着如果你有一个返回缓冲区的例程,你应该有一个相应的例程来解除它,即使客户端代码可以调用delete []。
例如:假设您有此代码
char *mylib_gimmeh_buffer() {
char* returnMe = new char[24324];
return returnMe;
}
对于对称性,你也应该
char *mylib_free_buffer(buffer) {
delete[] buffer;
}
现在,您的客户端代码应该像这样
buf = mylib_gimmeh_buffer();
/* do something with buf */
mylib_free_buffer(buf);
如果您的客户做了类似的事情
mylib_gimmeh_buffer(); // just for fun
或者像这样
buf = mylib_gimmeh_buffer();
/* do something with buf */
/* never call mylib_free_buffer() */
然后是内存泄漏
答案 3 :(得分:1)
char* function()
{
char* returnMe = new char[24324];
return returnMe;
}
int main()
{
char* pGetReturnME = function();
delete [] pGetReturnME;
}
只有在指向已分配内存的指针时,仍然可以释放函数中分配的内存。如果函数返回指向已分配内存的指针,则可以使用delete
或delete[]
释放。
你必须小心拥有明确的内存分配和释放协议,以避免多次删除或内存泄漏。
答案 4 :(得分:1)
调用函数负责释放返回的内存。
void function() {
char *to_free = NULL;
//to_free does not need to be freed yet
to_free = function_that_uses_new_to_set_return();
//to_free now must be freed if that function worked
if (to_free != NULL) delete[] to_free;
}
答案 5 :(得分:1)
虽然有可能有一个分配内存并返回指针的函数,但它确实容易出错......每当有人调用该函数时,他们需要知道该函数将代表他们分配内存,并且他们需要知道他们负责释放内存,并且他们需要知道在完成内存时释放内存的适当方法(删除?delete []?free()?还有什么?),然后他们在所有情况下,需要确保自由发生一次,并且他们需要确保在自由发生后再也不要再取消引用指针。
不可避免地,在一个非平凡的计划中,有人(可能是你!)会让其中一个错误。然后有人(可能是你)将花费几个小时的时间与调试器(或者如果你很幸运,valgrind)追踪为什么你的程序有时会崩溃或泄漏内存。这真的不是很有趣。
幸运的是,在C ++中,有更好的方法可以让调用者更加困难。例如,您可以返回一个shared_array,而不是返回原始指针,当它的最后一个指针消失时,它会自动删除已分配的内存。这样,没有人必须考虑内存管理,它“只是有效”。
一旦你习惯了这样做,你永远不会想回去!
答案 6 :(得分:0)
一种解决方案是以难以泄漏的方式返回内存。例如。将其作为带有自定义删除器的boost::shared_ptr
返回(因为您需要删除[])。现在它实际上需要呼叫者努力泄漏。