cplusplus / CWG

Core Working Group
24 stars 7 forks source link

[expr] evaluations vs. executed expressions for defining undefined behavior #282

Open xmh0511 opened 1 year ago

xmh0511 commented 1 year ago

Full name of submitter (unless configured in github; will be published with the issue): Jim X

We have specified UB for certain evaluations of expressions, such as:

[expr.pre] p4

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.

[basic.indet] p2

If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:

Consider this example

void show(){
    int cc = 0;
   std::cout<< cc; 
    if /*constexpr*/(false){
       int a;
       int r = a;  // this evaluation reads indeterminate value
       int c = 100000;
       short d = *(short*)&c; // violate [basic.lval] p11 and [expr.pre] p4
   }
}

Since the condition is false, the statement won't be executed, is this program undefined behavior? [intro.abstract] p5 says

However, if any such execution contains an undefined operation, this document places no requirement on the implementation executing that program with that input (not even with regard to operations preceding the first undefined operation).

So, in this example, Is cc printing 0 guaranteed?

Suggested resolution

Is undefined behavior defined for just evaluations or for these executed evaluations? This issue is similar to https://github.com/cplusplus/CWG/issues/268 but this is a more general issue.

jensmaurer commented 1 year ago

"evaluation" is following the execution flow, not the lexical appearance.

For example, a loop has fresh evaluations for each execution of the loop body.

[intro.abstract] p5 pretty clearly says that it's the actual execution in the abstract machine that can produce undefined behavior.

If you feel "preceding" in [intro.abstract] p5 can be misread as lexical, maybe "preceding ... in that execution" would be clearer?

xmh0511 commented 1 year ago

Because [intro.execution] p7 says:

Evaluation of an expression (or a subexpression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects.

The evaluation of an expression is statically analyzed and determined. what kind of evaluation the expression is isn't changed with each execution of the evaluation. For example, +a in this expression, the evaluation is statically determined as value computation, the kind of evaluation is just that and every execution of the expression just reads the object's value. Not strictly speaking, evaluation just describes what the expression will do/perform, or say it is more like a scheme, the execution of the evaluation will actually do what it should act.

Saying that the execution of such evaluation results in UB, which is clearer, I think.

jensmaurer commented 1 year ago

I don't agree with your interpretation of the words; I think that's not what the existing English phrasing says. The fact that we are fetching a value (as opposed to, say, modifying a value) might be a compile-time determination, but that doesn't contradict the idea that the value is actually fetched every time we execute the surrounding statement.

For example,

void f(bool b, int x, int y)
{
  (b ? x : y) = 5;
}

will arguably "determine the identity of an object" (whether you want x or y) at runtime.

If anything needs to be done at all in this area, we might want to clarify that any "evaluation" is a runtime (execution) property, not a compile-time one. I'm opposed to adding "executed evaluation" or so everywhere; that's clutter.

Specific suggestions for [intro.abstract] or [expr] welcome.

xmh0511 commented 1 year ago

we might want to clarify that any "evaluation" is a runtime (execution) property, not a compile-time one.

Evaluations might be executed at compile-time. For example:

constexpr int fun(bool b){
    if(b){
        return 0;
    }else{
        int i = 0;
        i++ + i;  // note the evaluation, which would cause UB
        return 1;
    }
}
int main(){
   constexpr int v = fun(true);  // this is ok because the evaluation containing unwell-defined behavior won't be executed
}

All implementations compile this example, however, it is a bit unclear in [expr.const] p5

An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

  • [...]
  • an operation that would have undefined behavior as specified in [intro] through [cpp], excluding [dcl.attr.assume];

It is unspecified whether E is a core constant expression if E satisfies the constraints of a core constant expression, but evaluation of E would evaluate

  • an operation that has undefined behavior as specified in [library] through [thread],

In this context, we should view "evaluation" as "the execution of the evaluation". It is even that changing the verb "evaluate" to "execute" is closer to the intent.

I think we should emphasize that the executed evaluation will make the program undefined behavior if the evaluation contains any unwell-defined operations, regardless the execution is at compile or run time. This may be as a common rule specify in [intro.abstract] or [expr]. The key point is the evaluation itself that has undefined behavior may not impact the program or suppress an expression from being a core constant expression but the execution of the evaluation is poison.

jensmaurer commented 1 year ago

I want the word "evaluation" in the standard to mean (what you describe as) "execution of an evaluation", thus actually saying "execution of an evaluation" in the words everywhere is (or will be) redundant. I believe we're quite close to that, but maybe there's some incremental improvement we could apply in some areas. Again, specific wording improvement suggestions that go in this direction are welcome.

You suggestion above goes in the opposite direction.

(You were apparently somehow misled to take a different turn when reading the words, so if we can identity where that happened, we can fix that place.)