Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is delete allowed to modify its parameter?

In an answer, https://stackoverflow.com/a/704568/8157187, there is a quote from Stroustrup:

C++ explicitly allows an implementation of delete to zero out an lvalue operand, and I had hoped that implementations would do that, but that idea doesn't seem to have become popular with implementers.

However, I failed to find this explicit statement in the standard. There is a part of the current draft standard (N4659), that one may interpret this way:

6.7:

When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values (6.9.2). Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.

Footnote: Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault

So, after a delete ptr;, ptr's value becomes a invalid pointer value, and using this value has implementation-defined behavior. However, it doesn't say that ptr's value is allowed to change.

It might be a philosophical question, how can one decide that a value has changed, if one cannot use its value?

6.9:

For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (4.4) making up the object can be copied into an array of char, unsigned char, or std::byte (21.2.1).43 If the content of that array is copied back into the object, the object shall subsequently hold its original value.

So, it seems, that it is valid to memcpy an invalid pointer value into a char array (depending on which statement is "stronger", 6.7 or 6.9. To me, 6.9 seems stronger).

This way, I can detect, that the pointer value has been changed by delete: memcpy the pointer's value before and after the delete to char array, then compare them.

So, as I understand, 6.7 doesn't grant that delete is allowed to modify its parameter.

Is delete allowed to modify its parameter?

Check out the comments here: https://stackoverflow.com/a/45142972/8157187


Here's an unlikely, but still possible real-world code, where this matters:

SomeObject *o = ...; // We have a SomeObject // This SomeObject is registered into someHashtable, with its memory address // The hashtable interface is C-like, it handles opaque keys (variable length unsigned char arrays)  delete o;  unsigned char key[sizeof(o)]; memcpy(key, &o, sizeof(o)); // Is this line OK? Is its behavior implementation defined? someHashtable.remove(key, sizeof(key)); // Remove o from the hashtable 

Of course, this snippet can be reordered, so it becomes a surely valid code. But the question is: is this a valid code?


Here's a related train of thought: suppose, that an implementation does define what footnote describes:

copying an invalid pointer value causes a system-generated runtime fault

6.9 guarantees that I can memcpy() any value. Even an invalid one. So in this theoretical implementation, when I memcpy() the invalid pointer value (which should succeed, 6.9 guarantees that), in a sense, I don't use the invalid pointer value, but only its underlying bytes (because it would generate a runtime fault, and 6.9 doesn't allow it), so 6.7 doesn't apply.

like image 317
geza Avatar asked Jul 17 '17 16:07

geza


People also ask

Can Delete have query parameters?

There's nothing wrong with using DELETE on a collection and filtering by query parameters. Neither the REST dissertation nor the HTTP spec say anything about not doing this.

Can we use request body with delete?

This is an know scenario and Integration Server doesn't accept request body for HTTP DELETE Method. The only means to accept the content for DELETE method in IS is by passing the Query parameter.

What is the API method for delete?

In RESTful APIs resources are typically deleted using the HTTP DELETE method. The resource that should be deleted is identified by the request URI. DELETE is an idempotent HTTP operation. Sending the same DELETE request multiple times should only alter the server state once.


2 Answers

Before the deletion, ptr's value was valid. After the deletion, the value was invalid. Therefore the value changed. Valid values and invalid values are mutually exclusive -- a value cannot be simultaneously valid and invalid.

Your question has a basic misconception; you're conflating these two different concepts:

  • The value of a variable
  • The representation of a variable in memory.

There isn't a one-to-one correspondence between these two things. The same value may have multiple representations, and the same representation may correspond to different values.


I think the gist of your question is: can delete ptr; change the representation of ptr?. To which the answer is "Yes". You could memcpy the deleted pointer into a char array, inspect the bytes, and find them all to be zero-valued bytes (or anything else). This is covered in the standard by C++14 [basic.stc.dynamic.deallocation]/4 (or C++17 [basic.stc]/4):

Any other use of an invalid pointer value has implementation-defined behavior.

It's implementation-defined and the implementation could define that inspecting the bytes gives bytes with value zero.


Your code snippet relies on implementation-defined behaviour. "Valid code" isn't terminology used by the Standard, but the code might not remove the intended item from the hash table.

As alluded to by Stroustrup, this is an intentional design decision. An example usage would be a compiler in debug mode setting deleted pointers to a particular representation, so that it can raise a runtime error if a deleted pointer is subsequently used. Here's an example of that principle in action for uninitialized pointers.

Historical note: In C++11 this case was undefined, rather than implementation-defined. So the behaviour of using a deleted pointer was identical to the behaviour of using an uninitialized pointer. In the C language, freeing memory is defined as putting all pointers to that memory into the same state as an uninitialized pointer has.

like image 109
M.M Avatar answered Oct 04 '22 07:10

M.M


The context in which you found the statement from Stroustrup, is available under Stroustrup, delete zero

Stroustrup let you consider

delete p; // ... delete p; 

After the first delete, pointer p was invalid. The second delete is wrong, but it would have no effect if p was set to 0 after the first delete.

Stroustrups idea was to compile it as something like

delete p; p = 0; // ... delete p; 

delete itself is not able to zero out the pointer since it passed void * but not void *&

However, I find zero out p doesn't help very much as they may exist other copies of that pointer which may accidently deleted, too. A better way is to use the different type of smartpointers.

Spec 6.7

Says that any pointer with the address of pointer p will be invalid (in an implementation defined way) after a delete p. It says nothing about changing the pointer address, neither it is allowed nor it is forbidden.

Spec 6.9

The prerequisit of 6.9 is a object (valid or not). This spec does not apply here since p (the address) is no more valid after delete and thatfore does NOT point to an object. So there is no contradiction, and any discussion whether 6.7 or 6.9 is stronger is invalid.

The spec requires also to copy the bytes back to the original object location, which your code does not, and would not be able too, because the original object has been deleted.


However, I see no reason to pack a pointer address into a char array and pass it. And pointers have always the same size in an certain implementation. Your code is just a cumbersome version of:

SomeObject *o = ...;  void *orgO = o; delete o;  someHashtable.remove(orgO); // someHashtable.remove(o); o might be set to 0 

However, this code still looks strange. To get an object from the hash table you need the pointer to that object. Why not directly use the pointer directly??

A hash table should help to find objects by some invariant values of the objects. That is not your application of hash table

Did you intented to have a list of all valid instances of SomeObject?

Your code is invalid cause, according to Stroustrup, the compiler is allowed to set p to zero. If this happened your code will crash

like image 20
stefan bachert Avatar answered Oct 04 '22 07:10

stefan bachert