C++ Logo

sg12

Advanced search

Re: [isocpp-sg12] Pull requests for UB/IFNDR Annexes

From: Herb Sutter <herb.sutter_at_[hidden]>
Date: Thu, 24 Apr 2025 12:01:18 -1000
I wrote:

> > Using the example \ubxref{expr.delete.dynamic.type.differ} as a test for

> > what we want to do:

> >

> >

> >

> > Current PR says:

> > If the static type of the object to be deleted is different from its dynamic

> > type and the selected deallocation function (see below) is not a destroying

> > operator delete, the static type shall be a base class of the dynamic type of

> > the object to be deleted and the static type shall have a virtual destructor or

> > the behavior is undefined.

> >

> > Possible rewrite 1 – just avoid normative words:

> > Issue: Deleting an object whose static type is different from its dynamic type

> > and the selected deallocation function is not a destroying operator delete,

> > and:

> > * the static type is not a base class of the dynamic type of the

> > > object to be deleted; or

> > * the static type does not have a virtual destructor.

> >

> > Possible rewrite 2 – condensed paraphrase:

> > Issue: Deleting an object of type T, where the operand of the delete-

> > expressions is of type "pointer to U", for certain combinations of T and U.

> >

> > Jens suggested that style 2 may be better: It’s less likely to become

> inconsistent if we ever change the normative rule in the future. It avoids

> trying to exactly reproduce the rule (we have cross-references for that).

 

Ville wrote:

> I concur with Jens's suggestion, use Rewrite 2 with cross-references.

> The rationale is 2+-fold:

>

> 1) This is an index-annex.

> 1.1) It should attempt to be explanatory beyond what a mere specification is.

> 2) It's not productive to rephrase existing wording in it with only "let's not use

> 'shall'" modifications.

> That loses the opportunity to be more explanatory, and gets out of sync when

> the spec-wording changes and the annex-wording doesn't, so don't aim for

> Specification Wording in the annex, make it an index with an explanatory

> summary of what's what, and link to the actual spec-standardese with a

> cross-reference.

 

Thanks! I got this other feedback privately from Richard, pasting here at his suggestion:

 

Richard wrote:

 

---
 
I would look to C's Annex J subclause 2 for guidance. Here's a snippet:
 
"""
J.2 Undefined behavior
 
1 The behavior is undefined in the following circumstances:
— A "shall" or "shall not" requirement that appears outside of a constraint is violated (Clause 4).
— A nonempty source file does not end in a new-line character which is not immediately preceded by a backslash character or ends in a partial preprocessing token or comment (5.1.1.2).
[...]
— The pointer argument to the free or realloc function does not match a pointer earlier returned by a memory management function, or the space has been deallocated by a call to free or realloc (7.22.3.3, 7.22.3.5).
[...]
"""
 
In general these are terse but explicit and precise. I think that's the right balance -- I don't think we should be handwaving about our UB rules in this annex or asking people to go do some research to figure out what our rules are. (Which combinations are "certain combinations", and how can you be sure you've found all the combinations of types that lead to undefined behavior while reading the normative wording? Maybe there's a second or third rule you missed.) Where precision and terseness conflict, I would consider defining additional terms in the main text in order to keep the annex terse. For example, in this case I might consider:
 
Change in [expr.delete]/3:
 
"<ins>An object of static type T is dynamically deletable if either the dynamic type U of the object is similar to T, or if</ins> <del>In</del> a single-object delete expression <ins>is used, and either</ins> <del>, if the static type of the object to be deleted is not similar ([conv.qual]) to its dynamic type and</del> the selected deallocation function (see below) is <del>not</del> a destroying operator delete<del>, the static type shall be</del> <ins>or T is</ins> a base class of <del>the dynamic type of the object to be deleted and the static type shall have</del> <ins>U and has</ins> a virtual destructor<ins>. If the object to be deleted is not dynamically deletable,</ins> <del>or</del> the behavior is undefined. <del>In an array delete expression, if the dynamic type of the object to be deleted is not similar to its static type, the behavior is undefined.</del>"
 
[Herb: it's easier for me to read a "before/after" so here's that, I think... From:
 
"In a single-object delete expression, if the static type of the object to be deleted is not similar ([conv.qual]) to its dynamic type and the selected deallocation function (see below) is not a destroying operator delete, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined."
 
To:
 
"An object of static type T is dynamically deletable if either the dynamic type U of the object is similar to T, or if a single-object delete expression is used, and either the selected deallocation function (see below) is a destroying operator delete or T is a base class of U and has a virtual destructor. If the object to be deleted is not dynamically deletable, the behavior is undefined."
 
/Herb]
 
 
And then in the UB annex:
 
"Issue: Deleting an object that is not dynamically deletable ([expr.delete])."
 
---
 
What do you think?
 
Herb
 

Received on 2025-04-24 22:01:22