What's the consequence of a sequence-point "immediately before a library function returns"?
Asked Answered
B

2

10

In this recent question, some code was shown to have undefined behavior:

a[++i] = foo(a[i-1], a[i]);

because even though the actual call of foo() is a sequence point, the assignment is unsequenced, so you don't know whether the function is called after the side-effect of ++i took place or before that.

Thinking further about this, the sequence point at a function call only guarantees that side effects from evaluating the function arguments are carried out once the function is entered, e.g.

int y = 1;
int func1(int x) { return x + y; }
int main(void)
{
    int result = func1( y++ ); // guaranteed to be 3
}

But looking at the standard, there's also §7.1.4 p3 (in the chapter about the standard library):

There is a sequence point immediately before a library function returns.

My question here is: What's the consequence of this paragraph? Why does it only concern library functions and what kind of code would actually rely on that?

Simple ideas like (nonsensical code to follow)

errno = 0;
long result = ftell(file) * errno;

would still be undefined as this time, the multiplication is unsequenced. I'm looking for an example that makes use of this special guarantee §7.1.4 p3 makes for library functions.


Regarding the suggested duplicate, Sequence point after a return statement?, this is indeed closely related and I found it before asking this question. It's not a duplicate, because

  • it asks about normative text stating there is a sequence point immediately after a return, without asking about the consequences when there is one.
  • it only mentions the special rule for library functions this question is about, without further elaborating on it.

Consequently, my questions here are not answered over there. The accepted answer uses a return value in an unsequenced expression (in this case an addition) and explains how the result depends on the sequencing of this addition, only finding that if you knew the sequencing of the addition, the whole result would be defined with a sequence point immediately after return. It doesn't show an example of code that is actually defined because of this rule, and it doesn't say anything about how/why library functions are special.

Brainwashing answered 22/8, 2017 at 10:0 Comment(5)
"standard disclaimer": If you downvote because I miss something "obvious", please leave a comment to point it out, thanks.Brainwashing
Possible duplicate of Sequence point after a return statement?Quietly
@MichaelFoukarakis I checked that one, it's closely related but doesn't answer this question. Although the special library function rule is mentioned there, there's no example for code where this rule actually has any effect.Brainwashing
Practical use of this statement is when multithreading is used in a program.Butterbur
@Butterbur I guess there must be something else, as the same paragraph is already found in C99.Brainwashing
S
9

Library functions don't have the code that implements them covered by the standard (they might not even be implemented in C). The standard only specifies their behaviour. So the provision about return statements does not apply to implementation of library functions.

The purpose of this clause (in combination with there being a sequence point on entry of a library function) is to say that any side-effects of the library functions are sequenced either before or after any other evaluations that might be in the code which calls the library function.

So the example in your question is not undefined behaviour (unless the multiplication overflows!): the read of errno is either sequenced before or after the modification by ftell, it's unspecified which.

Shemeka answered 22/8, 2017 at 11:40 Comment(3)
Ahh, the subtle difference between "undefined" and "unspecified" ... I tend to use them too sloppily I guess. Thanks so far! (isn't your example undefined for something completely different: signed overflow?)Brainwashing
@FelixPalmen I changed my answer to use your example, in my original example I don't think there was signed overflow but if there was then it would detract from my point so your example is better anywayShemeka
Well, there was, strtol would have returned LONG_MAX and ERANGE is positive :) At least, your first paragraph explains very logically why library functions are "special" here, thanks and uv'd :)Brainwashing
P
2

The requirement for a sequence point before a library function returns was formalized in C99 due to a Defect Report by Clive D.W. Feather, filed by the C standard working group (ISO/IEC JTC1/SC22/WG14) as Defect Report #147.

Clive considers the following code:

#include <string.h>
char s[10];
/* ... */
(strcpy)(s, "Testing") [0] = 'X';

If strcpy was a normal function written in C, there would be a sequence point after the last full expression evaluated by the function (which would be the evaluation of the expression in the return statement), so s[0] would be guaranteed to be set to 'T' before that sequence point, and would be guaranteed to be set to 'X' after the sequence point. However, because the normal rules of C do not apply to library functions (that might not be written in C), then there was no requirement specified for that sequence point to be there, so s[0] could have been modified more than once between sequence points. The resolution of the Defect Report fixes that by requiring the sequence point before the library function returns.

Pile answered 12/7, 2024 at 11:23 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.