2

I'm asking this question from the perspective of a compiler developer – I want to know whether a particular potential optimisation is valid (because all programs that the optimisation would break have undefined behavior) or invalid (i.e. it would break some programs whose behavior is defined).

The question is about static restrict array function parameters. I know that restrict means that memory accessed through the restrict pointer isn't accessed any other way during the function body, and static means that the pointer does in fact point to an array of the correct size, but am unsure on the exact details of how these work.

Suppose someone writes the following code, which takes a static restrict array as a function parameter, passes it to an extern function, then conditionally reads through the array afterwards:

extern int bar(int x[static restrict 1]);
int foo(int x[static restrict 1])
{
    *x = 1;
    int y = bar(x);
    int z = 0;
    while (y--) z += *x;
    return z;
}

My question is: does this code have undefined behaviour if x is a pointer to malloc-ed memory, and bar frees its argument and returns 0? (In other words, this is a question about whether the int x[static restrict 1] argument has to point to an array of 1 int throughout the entire body of the function foo, or whether the requirement applies only at the point of the calls to foo and bar.)

If the requirement applies over the whole function, thus meaning that it would be undefined behavior for bar to free its argument, it would be legal for a compiler to optimise the last three lines into return y * *x;, which has the same result in all situations where x is known to still point to an allocated integer. However, if the requirement applies just on entry, it isn't (with the best available optimisation being someting like return y ? y * *x : 0 instead). So whether the behavior is defined or undefined affects what a compiler is allowed to do with the code.

6
  • I think it is UB to assign a restrict pointer to another restrict pointer in the same scope - passing arguments to a function is done as per assignment. This is about a muddy fiasco chapter of ISO C called "formal definition of restrict" (C23 6.7.4.2). Commented Nov 25 at 13:57
  • @Lundin: 6.7.4.2p4 is ambiguous, and I agree that on its own, its second half could be interpreted to ban any assignment of one restrict pointer to another (not just assignments after initialization). However, 6.7.4.2p11 seems to clariify that the rule only applies to assignments that occur after the pointer initially gains its value (and specifically states that the case of passing a restrict pointer to a function that takes a restrict pointer as argument is legal). Commented Nov 25 at 14:09
  • 1
    @ais523: Your references to paragraph numbers suggest you are using an unofficial draft of the C standard. The official 2024 C standard does not contain paragraph numbers. You should be aware that, unlike prior versions of the standard, there are considerable differences between the committee’s last draft and the official C standard. (It changed in some post-committee balloting process I have little information about.) So it is preferable to use the official standard and not drafts and, when using a draft, to explicitly state that and cite the draft version. Commented Nov 25 at 14:25
  • @EricPostpischil: you're right, I'm using a draft (specifically N3299) because I don't have access to the official version. I didn't realise that it had diverged so much (previous drafts were pretty close to the standard). Commented Nov 25 at 14:30
  • Re “restrict means that memory accessed through the restrict pointer isn't accessed any other way during the function body”: Not quite. That only applies if the memory is modified in any way. If all accesses are reads, restrict does not impose any requirements. Commented Nov 25 at 14:46

1 Answer 1

4

In other words, this is a question about whether the int x[static restrict 1] argument has to point to an array of 1 int throughout the entire body of the function foo, or whether the requirement applies only at the point of the calls to foo and bar.

static says nothing about the parameter. It says something about value of the argument passed to the function, not about the parameter. C 2024 6.7.7.4 says:

… If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

This imposes a constraint on the caller. It does not impose any constraint on the parameter x. In regard to static, the function is free to change the value of x and to change or deallocate the memory it points to.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.