A C++ book I have been reading states that when a pointer is deleted using the delete
operator the memory at the location it is pointing to is "freed" and it can be overwritten. It also states that the pointer will continue to point to the same location until it is reassigned or set to NULL
.
我一直在读的一个c++的书中说,当一个指针被删除操作符删除时,在它指向的位置的内存被“释放”,它可以被覆盖。它还声明指针将继续指向相同的位置,直到重新分配或设置为NULL。
In Visual Studio 2012 however; this doesn't seem to be the case!
然而在Visual Studio 2012中;这似乎不是事实!
Example:
例子:
#include <iostream>
using namespace std;
int main()
{
int* ptr = new int;
cout << "ptr = " << ptr << endl;
delete ptr;
cout << "ptr = " << ptr << endl;
system("pause");
return 0;
}
When I compile and run this program I get the following output:
当我编译并运行这个程序时,我得到以下输出:
ptr = 0050BC10
ptr = 00008123
Press any key to continue....
Clearly the address that the pointer is pointing to changes when delete is called!
显然,当调用delete时,指针指向的地址发生了变化!
Why is this happening? Does this have something to do with Visual Studio specifically?
为什么会这样?这和Visual Studio有什么关系吗?
And if delete can change the address it is pointing to anyways, why wouldn't delete automatically set the pointer to NULL
instead of some random address?
如果delete可以改变它指向的地址,为什么delete不能自动将指针设置为NULL而不是随机地址呢?
6 个解决方案
#1
171
I noticed that the address stored in ptr
was always being overwritten with 00008123
...
我注意到存储在ptr中的地址总是被00008123覆盖……
This seemed odd, so I did a little digging and found this Microsoft blog post containing a section discussing "Automated pointer sanitization when deleting C++ objects".
这看起来很奇怪,所以我做了一点挖掘,发现了这个Microsoft博客文章,里面有一节讨论“删除c++对象时自动指针消毒”。
...checks for NULL are a common code construct meaning that an existing check for NULL combined with using NULL as a sanitization value could fortuitously hide a genuine memory safety issue whose root cause really does needs addressing.
…检查NULL是一种常见的代码构造,这意味着对NULL的现有检查结合使用NULL作为清理值可能会偶然地隐藏一个真正的内存安全问题,其根源确实需要处理。
For this reason we have chosen 0x8123 as a sanitization value – from an operating system perspective this is in the same memory page as the zero address (NULL), but an access violation at 0x8123 will better stand out to the developer as needing more detailed attention.
出于这个原因,我们选择0x8123作为清理值——从操作系统的角度来看,它与0地址(NULL)位于同一个内存页中,但是在0x8123上的访问违例将更好地引起开发人员的注意,因为需要更详细的关注。
Not only does it explain what Visual Studio does with the pointer after it is deleted, it also answers why they chose NOT to set it to NULL
automatically!
它不仅解释了Visual Studio在删除指针后对指针做什么,还回答了为什么他们选择不自动将其设置为NULL !
This "feature" is enabled as part of the "SDL checks" setting. To enable/disable it go to: PROJECT -> Properties -> Configuration Properties -> C/C++ -> General -> SDL checks
此“特性”作为“SDL检查”设置的一部分启用。要启用/禁用它,请转到:PROJECT -> Properties -> Configuration Properties -> C/ c++ -> General -> SDL check
To confirm this:
证实了这一点:
Changing this setting and rerunning the same code produces the following output:
更改此设置并重新运行相同的代码将产生以下输出:
ptr = 007CBC10
ptr = 007CBC10
"feature" is in quotes because in a case where you have two pointers to the same location, calling delete will only sanitize ONE of them. The other one will be left pointing to the invalid location.
“feature”在引号中,因为当你有两个指向同一个位置的指针时,调用delete只会清除其中的一个。另一个则指向无效的位置。
Visual Studio could set you up for a sticky situation by failing to document this flaw in its design.
Visual Studio如果没有在设计中记录这个缺陷,可能会让您陷入困境。
#2
30
You see the side-effects of the /sdl
compile option. Turned on by default for VS2015 projects, it enables additional security checks beyond those provided by /gs. Use Project > Properties > C/C++ > General > SDL checks setting to alter it.
您可以看到/sdl编译选项的副作用。VS2015项目在默认情况下是打开的,除了/gs提供的安全检查之外,它还支持其他的安全检查。使用项目>属性> C/C+ >常规> SDL检查设置修改。
Quoting from the MSDN article:
引用MSDN文章:
- Performs limited pointer sanitization. In expressions that do not involve dereferences and in types that have no user-defined destructor, pointer references are set to a non-valid address after a call to delete. This helps to prevent the reuse of stale pointer references.
- 执行卫生处理有限的指针。在不涉及去引用的表达式和没有用户定义的析构函数的类型中,指针引用在一次要删除的调用之后被设置为一个无效地址。这有助于防止重用过时的指针引用。
Do keep in mind that setting deleted pointers to NULL is a bad practice when you use MSVC. It defeats the help you get from both the Debug Heap and this /sdl option, you can no longer detect invalid free/delete calls in your program.
请记住,在使用MSVC时,将删除的指针设置为NULL是一种不好的做法。它破坏了从调试堆和这个/sdl选项获得的帮助,您不能再检测程序中无效的free/delete调用。
#3
19
It also states that the pointer will continue to point to the same location until it is reassigned or set to NULL.
它还声明指针将继续指向相同的位置,直到重新分配或设置为NULL。
That is definitely misleading information.
这绝对是误导性的信息。
Clearly the address that the pointer is pointing to changes when delete is called!
显然,当调用delete时,指针指向的地址发生了变化!
Why is this happening? Does this have something to do with Visual Studio specifically?
为什么会这样?这和Visual Studio有什么关系吗?
This is clearly within the language specifications. ptr
is not valid after the call to delete
. Using ptr
after it has been delete
d is cause for undefined behavior. Don't do it. The run time environment is free to do whatever it wants to with ptr
after the call to delete
.
这显然在语言规范中。ptr在调用删除后无效。删除ptr后使用ptr会导致未定义的行为。不要这样做。运行时环境可以在调用ptr删除之后*地使用ptr执行它想做的任何事情。
And if delete can change the address it is pointing to anyways, why wouldn't delete automatically set the pointer to NULL instead of some random address???
如果delete可以改变它指向的地址,为什么delete不能自动将指针设置为NULL而不是随机地址呢?
Changing the value of the pointer to any old value is within the language specification. As far as changing it to NULL, I would say, that would be bad. The program would behave in a more sane manner if the value of the pointer were set to NULL. However, that will hide the problem. When the program is compiled with different optimization settings or ported to a different environment, the problem will likely show up in the most inopportune moment.
将指针的值更改为任何旧值是在语言规范中。至于把它变为零,我认为,这很糟糕。如果将指针的值设置为NULL,程序的行为将更加理智。然而,这将掩盖问题。当程序使用不同的优化设置或移植到不同的环境时,问题很可能在最不合适的时候出现。
#4
10
delete ptr;
cout << "ptr = " << ptr << endl;
In general even reading (like you do above, note: this is different from dereferencing) values of invalid pointers (pointer becomes invalid for example when you delete
it) is implementation defined behaviour. This was introduced in CWG #1438. See also here.
一般来说,即使读取无效指针(如您上面所做的那样,注意:这与取消引用不同)的值(指针在删除时变得无效)也是实现定义的行为。这是在CWG #1438中介绍的。参见这里。
Please note that before that reading values of invalid pointers was undefined behaviour, so what you have above would be undefined behaviour, which means anything could happen.
请注意,在读取无效指针的值之前是未定义的行为,因此上面的操作将是未定义的行为,这意味着任何事情都可能发生。
#5
1
I believe, you are running some sort of debug mode and VS is attempting to repoint your pointer to some known location, so that further attempt to dereference it could be traced and reported. Try compiling/running the same program in release mode.
我相信,您正在运行某种调试模式,VS正在尝试将指针重新指向某个已知位置,以便进一步尝试取消引用,以便跟踪和报告它。尝试在发布模式中编译/运行相同的程序。
Pointers are usually not changed inside delete
for the sake of efficiency and to avoid giving a false idea of safety. Setting delete pointer to pre-defined value will do no good in most of complex scenarios, since the pointer being deleted is likely to be only one of several pointing to this location.
为了提高效率和避免给出安全的错误想法,指针通常不会在删除中被更改。在大多数复杂的场景中,将delete指针设置为预定义值不会有什么好处,因为被删除的指针很可能只是指向这个位置的几个指针中的一个。
As a matter of fact, the more I think about it, the more I find that VS is at fault when doing so, as usual. What if the pointer is const? Is it still gonna change it?
事实上,我想得越多,就越会发现v和往常一样有问题。如果指针是const呢?它还会改变吗?
#6
0
After deleting the pointer the memory to which it points may still be valid. To manifest this error, the pointer value is set to an obvious value. This really helps the debugging process. If the value were set to NULL
, it may never show up as potential bug in the program flow. So it may hide a bug when you test later against NULL
.
删除指针后,指针指向的内存可能仍然有效。为了显示这个错误,指针值被设置为一个明显的值。这确实有助于调试过程。如果该值被设置为NULL,它可能永远不会在程序流中显示为潜在的bug。因此,当您稍后对NULL进行测试时,它可能会隐藏一个错误。
Another point is, that some run time optimizer may check that value and change its results.
另一点是,某些运行时优化器可能会检查该值并更改其结果。
In earlier times MS set the value to 0xcfffffff
.
在早些时候,MS将值设置为0xcfffffff。
#1
171
I noticed that the address stored in ptr
was always being overwritten with 00008123
...
我注意到存储在ptr中的地址总是被00008123覆盖……
This seemed odd, so I did a little digging and found this Microsoft blog post containing a section discussing "Automated pointer sanitization when deleting C++ objects".
这看起来很奇怪,所以我做了一点挖掘,发现了这个Microsoft博客文章,里面有一节讨论“删除c++对象时自动指针消毒”。
...checks for NULL are a common code construct meaning that an existing check for NULL combined with using NULL as a sanitization value could fortuitously hide a genuine memory safety issue whose root cause really does needs addressing.
…检查NULL是一种常见的代码构造,这意味着对NULL的现有检查结合使用NULL作为清理值可能会偶然地隐藏一个真正的内存安全问题,其根源确实需要处理。
For this reason we have chosen 0x8123 as a sanitization value – from an operating system perspective this is in the same memory page as the zero address (NULL), but an access violation at 0x8123 will better stand out to the developer as needing more detailed attention.
出于这个原因,我们选择0x8123作为清理值——从操作系统的角度来看,它与0地址(NULL)位于同一个内存页中,但是在0x8123上的访问违例将更好地引起开发人员的注意,因为需要更详细的关注。
Not only does it explain what Visual Studio does with the pointer after it is deleted, it also answers why they chose NOT to set it to NULL
automatically!
它不仅解释了Visual Studio在删除指针后对指针做什么,还回答了为什么他们选择不自动将其设置为NULL !
This "feature" is enabled as part of the "SDL checks" setting. To enable/disable it go to: PROJECT -> Properties -> Configuration Properties -> C/C++ -> General -> SDL checks
此“特性”作为“SDL检查”设置的一部分启用。要启用/禁用它,请转到:PROJECT -> Properties -> Configuration Properties -> C/ c++ -> General -> SDL check
To confirm this:
证实了这一点:
Changing this setting and rerunning the same code produces the following output:
更改此设置并重新运行相同的代码将产生以下输出:
ptr = 007CBC10
ptr = 007CBC10
"feature" is in quotes because in a case where you have two pointers to the same location, calling delete will only sanitize ONE of them. The other one will be left pointing to the invalid location.
“feature”在引号中,因为当你有两个指向同一个位置的指针时,调用delete只会清除其中的一个。另一个则指向无效的位置。
Visual Studio could set you up for a sticky situation by failing to document this flaw in its design.
Visual Studio如果没有在设计中记录这个缺陷,可能会让您陷入困境。
#2
30
You see the side-effects of the /sdl
compile option. Turned on by default for VS2015 projects, it enables additional security checks beyond those provided by /gs. Use Project > Properties > C/C++ > General > SDL checks setting to alter it.
您可以看到/sdl编译选项的副作用。VS2015项目在默认情况下是打开的,除了/gs提供的安全检查之外,它还支持其他的安全检查。使用项目>属性> C/C+ >常规> SDL检查设置修改。
Quoting from the MSDN article:
引用MSDN文章:
- Performs limited pointer sanitization. In expressions that do not involve dereferences and in types that have no user-defined destructor, pointer references are set to a non-valid address after a call to delete. This helps to prevent the reuse of stale pointer references.
- 执行卫生处理有限的指针。在不涉及去引用的表达式和没有用户定义的析构函数的类型中,指针引用在一次要删除的调用之后被设置为一个无效地址。这有助于防止重用过时的指针引用。
Do keep in mind that setting deleted pointers to NULL is a bad practice when you use MSVC. It defeats the help you get from both the Debug Heap and this /sdl option, you can no longer detect invalid free/delete calls in your program.
请记住,在使用MSVC时,将删除的指针设置为NULL是一种不好的做法。它破坏了从调试堆和这个/sdl选项获得的帮助,您不能再检测程序中无效的free/delete调用。
#3
19
It also states that the pointer will continue to point to the same location until it is reassigned or set to NULL.
它还声明指针将继续指向相同的位置,直到重新分配或设置为NULL。
That is definitely misleading information.
这绝对是误导性的信息。
Clearly the address that the pointer is pointing to changes when delete is called!
显然,当调用delete时,指针指向的地址发生了变化!
Why is this happening? Does this have something to do with Visual Studio specifically?
为什么会这样?这和Visual Studio有什么关系吗?
This is clearly within the language specifications. ptr
is not valid after the call to delete
. Using ptr
after it has been delete
d is cause for undefined behavior. Don't do it. The run time environment is free to do whatever it wants to with ptr
after the call to delete
.
这显然在语言规范中。ptr在调用删除后无效。删除ptr后使用ptr会导致未定义的行为。不要这样做。运行时环境可以在调用ptr删除之后*地使用ptr执行它想做的任何事情。
And if delete can change the address it is pointing to anyways, why wouldn't delete automatically set the pointer to NULL instead of some random address???
如果delete可以改变它指向的地址,为什么delete不能自动将指针设置为NULL而不是随机地址呢?
Changing the value of the pointer to any old value is within the language specification. As far as changing it to NULL, I would say, that would be bad. The program would behave in a more sane manner if the value of the pointer were set to NULL. However, that will hide the problem. When the program is compiled with different optimization settings or ported to a different environment, the problem will likely show up in the most inopportune moment.
将指针的值更改为任何旧值是在语言规范中。至于把它变为零,我认为,这很糟糕。如果将指针的值设置为NULL,程序的行为将更加理智。然而,这将掩盖问题。当程序使用不同的优化设置或移植到不同的环境时,问题很可能在最不合适的时候出现。
#4
10
delete ptr;
cout << "ptr = " << ptr << endl;
In general even reading (like you do above, note: this is different from dereferencing) values of invalid pointers (pointer becomes invalid for example when you delete
it) is implementation defined behaviour. This was introduced in CWG #1438. See also here.
一般来说,即使读取无效指针(如您上面所做的那样,注意:这与取消引用不同)的值(指针在删除时变得无效)也是实现定义的行为。这是在CWG #1438中介绍的。参见这里。
Please note that before that reading values of invalid pointers was undefined behaviour, so what you have above would be undefined behaviour, which means anything could happen.
请注意,在读取无效指针的值之前是未定义的行为,因此上面的操作将是未定义的行为,这意味着任何事情都可能发生。
#5
1
I believe, you are running some sort of debug mode and VS is attempting to repoint your pointer to some known location, so that further attempt to dereference it could be traced and reported. Try compiling/running the same program in release mode.
我相信,您正在运行某种调试模式,VS正在尝试将指针重新指向某个已知位置,以便进一步尝试取消引用,以便跟踪和报告它。尝试在发布模式中编译/运行相同的程序。
Pointers are usually not changed inside delete
for the sake of efficiency and to avoid giving a false idea of safety. Setting delete pointer to pre-defined value will do no good in most of complex scenarios, since the pointer being deleted is likely to be only one of several pointing to this location.
为了提高效率和避免给出安全的错误想法,指针通常不会在删除中被更改。在大多数复杂的场景中,将delete指针设置为预定义值不会有什么好处,因为被删除的指针很可能只是指向这个位置的几个指针中的一个。
As a matter of fact, the more I think about it, the more I find that VS is at fault when doing so, as usual. What if the pointer is const? Is it still gonna change it?
事实上,我想得越多,就越会发现v和往常一样有问题。如果指针是const呢?它还会改变吗?
#6
0
After deleting the pointer the memory to which it points may still be valid. To manifest this error, the pointer value is set to an obvious value. This really helps the debugging process. If the value were set to NULL
, it may never show up as potential bug in the program flow. So it may hide a bug when you test later against NULL
.
删除指针后,指针指向的内存可能仍然有效。为了显示这个错误,指针值被设置为一个明显的值。这确实有助于调试过程。如果该值被设置为NULL,它可能永远不会在程序流中显示为潜在的bug。因此,当您稍后对NULL进行测试时,它可能会隐藏一个错误。
Another point is, that some run time optimizer may check that value and change its results.
另一点是,某些运行时优化器可能会检查该值并更改其结果。
In earlier times MS set the value to 0xcfffffff
.
在早些时候,MS将值设置为0xcfffffff。