-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[intro.object] Converting a pointer value that is returned from a malloc operation that creates an array object to the element type results in UB? #378
Comments
This is a known issue, although CWG issue is missing. See cplusplus/draft#3203 (and perhaps cplusplus/draft#4808).
Approaches IMO:
|
If the first element is not of an implicit-lifetime type, it cannot because these operations select one of the implicitly-created objects.
This means, for the second example, we can only get the pointer value pointing to the array object and use array-to-pointer conversion, which is the only way to be right. |
If T is of implicit-lifetime type, so is "array of T". What we need for the T example to be valid: Implicitly create an object of type "array of 10 T" in the storage and return a pointer to the first element. It seems the only thing we need to say to make the quoted wording do the right thing is to say that a subobject (that is of implicit-lifetime type) of an implicitly created object is also an implicitly created object. Then, the quoted wording can return a pointer to the first element (instead of a pointer to the entire array). |
Unless we already have wording that says that a pointer to the array also points to the first element (but not vice versa). |
The S example can't be made to work without placement-new or |
The example in cplusplus/draft#5782 (comment) seems to be related. |
However, we didn't say the array object and its first element have the same address, which means, if we consider the first element located at the start of the region, the array object may located at the outside of the region because no rule guarantee they are the same address. |
I don't think anything can permit an object to be located outside of an allocated storage. Is the currently wording happening not to forbid this? |
Where does that wording in the current draft forbid the case? |
[intro.object] p1
It might be not. But... [intro.object] p10 says:
which should cover the cases in this issue. |
It does not necessary to create complete objects, subobjects are also objects anyway. Moreover, it says
No rule says the program will be undefined if the operation only creates the subobject in its region, it even didn't say the complete object of the subobject that occupies the region should also be within the region. |
@xmh0511 , as I said elsewhere, if it's sufficient for a subobject to be implicitly created in the region of storage, then there is no point in attempting to somehow create a (larger) complete object that starts before the storage. (You can just create the subobject as a complete object.) I'd also like to point out that a subobject doesn't (conceptually) exist without its complete object, so the creation of a subobject implies that a complete object must have been created. I find the text "in its region of storage" sufficiently clear (together with "An object occupies a region of storage") to imply that a complete object can't be partially outside the given region of storage. [dcl.array] p6 seems sufficiently clear ("consists of") that there is no padding in an array object outside of the elements, which implies that the address of the first element is the same as the address of the entire array. |
As I said above(or in another issue), the interpretation may feel absurd, however, we do lack the (sufficient)formal wording to make the interpretation irrefutable.
It just means what it could literally mean. As per [basic.compound] p5, the storage occupied by a complete object is not necessarily reachable by its subobject, in other words, when we only have a pointer value points to a certain subobject, we may not reach the storage occupied its complete object, so, from the perspective of subobjects, it doesn't matter where their complete objects locates. |
Back to the original example. "malloc" implicitly creates objects, in particular the "array of 10 T" and the T subobjects of that array. It then returns a pointer to the first element of the array (not to the entire array), which is one of the implicitly-created objects, which makes the rest of the program have defined behavior (in particular, pointer arithmetic is valid). I'm not seeing a defect in the handling of your example. |
I think it may exist two cases here:
For the second case, we may consider it in an extreme way, assuming the third element subobject locates at the start of the region created by |
So, what's the actual problem with such thinking that would need fixing? Obviously, the enclosing "array of 10 T" object hasn't started its lifetime in such a case, thus you can't do pointer arithmetic on the elements. If that's what you want, fine with me. |
So, are we allowed to do the pointer arithmetic to make the pointer points to the storage outside of the storage allocated by |
I continue to fail to see a problem, because my (alternative) interpretation is that an array of N-1 is implicitly created entirely within that storage, and pointer arithmetic is certainly valid there. |
Whether an interpretation can be true is based on whether the program can result in well-defined behavior. In my interpretation, together with the clarification that pointer arithmetic can be done on a non-living array object, the program seems to be valid when
As discussed above, no rule says that |
It may be better to say "a subobject is implicitly created only if its complete object is implicitly created". But I do think that this can be done without a CWG issue. |
@frederick-vs-ja plz see e.g.
Do you see «the»? There is only one object «created» by a new-expression, even if it has subobjects. Subobjects are not considered «created» (except when https://timsong-cpp.github.io/cppwp/n4868/intro.object#2.sentence-4 applies). If you think new-expression first creates the containing objects and then creates subobjects, or that it first creates subobjects and then glues them together into containing object, you have a very wrong mental model. I think the same applies to other cases when objects are created, otherwise it would be a mess. Subobjects are not «created»! |
Oh, subobjects are considered implicitly created in the comments in this example. Moreover, in [class.union.general] p6, some subobjects of the activated union member may also be considered created. If we clarify that subobjects are not created, we'll need some different wording to specify implicitly starting the lifetime of a subobject. The current wording seemingly implies that explicit operations only create the outermost object, while implicit creation may create the outermost object and its subobjects, which is inconsistent. |
Full name of submitter (unless configured in github; will be published with the issue): Jim X
The original question is on SO
[intro.object] p11 says:
Consider this example:
Since T is an implicit-lifetime class, the operation malloc can implicitly create an object of class type T. In this example, we intend to make
ptr
point to the initial element of the array object with 10 elements of typeT
, based on this assumption,ptr++
would have a valid behavior. This case assumes the first element has its address at the start of the region.Since an array of any type is an implicit-lifetime type,
malloc(sizeof(T)*10)
can implicitly create an array object with 10 elements and start the lifetime of that array object. Since the initial element and the containing array are not pointer-interconvertible.That means,
ptr
either point to the first element of that array or that complete array. However, if we consider the first element locates at the start of the region, how do we prove whether this assumption is true or not? After all, there is no rule to say that array and its first element must have the same address.Furthermore, consider this example:
Now,
S
is not an implicit-lifetime class, must#1
and#2
be replaces toto make
ptr
well-defined to point to the first element?The text was updated successfully, but these errors were encountered: