Projections and Undefined Behavior #1868
Replies: 7 comments 9 replies
|
Very nice laws! I understand the general meaning of the definitions but I think they require some tweaks. Some comments:
A projection can have any access effect, including In my working lexicon, I use projection to mean an access on (parts of) one or several values. For example, Here I would call It may also be interesting to note that
A
A "use" is an IR term and thus I think we can't limit ourselves to occurrences visible in sources only. Also I think this definition contradicts the one before it (which incidentally describes more accurately what a use is in the IR). The name to which a temporary projection is bound does not show up in sources. The issue is that an expression like I understand it is inconvenient to bring up the IR but in any case, we'll at least have to consider evaluation order in your laws. For example, this program is legal in safe Hylo: There are two temporary projections of
If possible I would like to avoid giving any special status to In my personal mental model I stopped seeing methods as a concept separate from free functions (and subscripts).
I don't understand the distinction you draw between deinitialized and incomplete. |
OK.
I think it's fine for “use” to have a contextual meaning. Isn't every use in IR derived from some use-as-I-have-defined-it? Regardless, the wording doesn't depend on having a definition of “use” so I just removed it.
I don't think the fact that evaluation order is sometimes not lexically left-to-right demands any changes to what I wrote. The point is to lay out what causes UB given the evaluation order rules, whatever they may be. I also don't see where I touch on your point.
IMO the logical conclusion of that is that every piece of memory is always accessible as any type without UB. Think about when we can access a tuple of two I draw no distinction between deinitialized and incomplete. I say they are the same: an object stops being complete precisely when it becomes deinitialized. |
Shouldn't the definition of
I think compiler disallows the "other than" part. For example:
Also this rule is from where, I got the idea of pointer provenance. Consider following program: On line But from our last discussion, I think you meant to say, we should not treat pointer as something more than a memory address. And any binding created from pointer dereference, should be logically assumed to be created from latest active binding? |
How? The definition of “complete” is precisely that all the parts are initialized, so it does not require returning from an initializer (or any other
👍 applied |
You are right, sorry! Also I confirm that we should not allow the first example from Rishab, but not because of any problem related to the "completeness" of the object. Unless I missed something Dave's laws do not describe what uniqueness (or exclusivity) means. An attempt from my part is:
Note that I didn't use contiguous storage because it occurred to me that the term might be slightly incorrect since it is possible to store properties indirectly, in both enums and structs. Isn't enough to say "parts of an object"? Even if we're talking about an array, it should not be possible to access the same part (i.e., position in the out-of-line buffer) from two different bindings. And I would claim that CoW representations involve a peer relationship between the container and its storage, meaning that the latter would not be considered "part of" the former. |
|
My text doesn't include the terms “uniqueness” or “exclusivity” because it doesn't need to. It's all there in the 2nd bullet. And the text you propose doesn't prevent active immutable bindings from overlapping active mutable ones. I will remove the “contiguous storage” part. It was intended as a clarification for the casual reader who wonders about “logical parts.” In the domain of objects those don't exist so it's strictly unneeded but then you have to be aware of the technical meaning of object. I can add a footnote.
If you mean a dynamic array, parts are irrelevant to the rules that prevent that access. It's already covered. Parts are only used to define completeness and to talk about allowed narrowing (in a note, which should be considered non-normative—it exists to help the reader understand how upholding those properties leads to safety). I don't know what you mean about CoW, but I claim all that is above the level of these rules and these rules are sufficient to ensure that it works and is safe. |
Does this OK mean, the above definition should be changed accordingly? Asking as this would impact the shape of my data structure. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Definitions
sink,set,inoutorletaccess. 1 2Tis an access to an object of typeT.x: inout T = &y,ybecomes inactive, and if still alive, becomes active again when the lifetime ofxends.setaccess on it (aninitfunction is asetaccess onself).sinkparameter, and returns to its prior state whenever all of its parts have returned to an initialized state.Laws
In entirely safe code, the compiler upholds these properties:
setprojection of typeTalways refers to a complete object of typeT.sink,set, orinoutprojection of an object y, no other projection that includes y is active.Note: the compiler also ensures that only active projections of complete objects are used in expressions other than those that narrow active projections of incomplete objects to their stored parts, e.g. in
x.y,xmay project an incomplete object.The behavior of a program that violates either property (e.g., using pointers) is undefined. For example:
Note: this post reflects revisions based on the discussion below.
Footnotes
Projections can be bound to names but may also be the temporary unnamed results of expressions. ↩
A
vardeclaration creates a boundsinkprojection. ↩An object's parts all follow from its type declaration and do not depend on the user-defined semantics of operations. For example, they do not include “logical parts” that can only be reached via declared pointers, such as the elements of a dynamic array, even though its
==operation implies that they are parts. ↩Every initialized object is complete, so every incomplete object is uninitialized. ↩
All reactions