Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
318 views
in Technique[技术] by (71.8m points)

c - Requirements for behavior of pointer-to-volatile pointing to non-volatile object

C11 6.7.3 Type qualifiers, paragraph 7, reads:

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3.

In the following example, is the object accessed in the third line subject to the above rule?

int x;
volatile int *p = &x;
*p = 42;

In other words, does the fact that the lvalue *p has type volatile int mean that a volatile object is being accessed, or does the fact that p points to a non-volatile object x mean that the compiler can optimize with this knowledge and omit the volatile access?

Since it may be of interest, the particular usage case I'm interested in is outside the scope of plain C; it involves atomics for thread synchronization using pre-C11 constructs (which could be inline asm or simply thought of as a black box) for atomic compare-and-swap, with the following idiom:

do {
    tmp = *p;
    new = f(tmp);
} while (atomic_cas(p, tmp, new) != success);

Here the pointer p would have type volatile int *, but I'm concerned about what happens when the actually pointed-to object is non-volatile, particularly whether the compiler could transform the single access to *p from tmp = *p into two accesses of the following form:

do {
    new = f(*p);
} while (atomic_cas(p, *p, new) != success);

which would obviously render the code incorrect. Thus the goal is to determine whether all such pointed-to objects actually need to be volatile int.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Update 18 February 2017

The answer below quotes & discusses the language in the Standard, some contradictory language in the Rationale and some comments from gnu.cc re the contradiction. There is a defect report which essentially has committee agreement (although still open) that the Standard should say, and that the intent has always been, and that implementations have always reflected, that it is not the volatility of an object that matters (per the Standard) but of the volatility of (the lvalue of) an access (per the Rationale). (Credit to Olaf for mentioning this DR.)

Defect Report Summary for C11 Version 1.10 Date: April 2016 DR 476 volatile semantics for lvalues 04/2016 Open


No. Because the object accessed is not volatile.

Object p is of type pointer to volatile int. But x is not an object of a volatile-qualified type. The qualifications on p affect what accesses can be made through it, but do not affect the type of the object that it points to. There is no restriction on accessing a non-qualified-type object via a volatile lvalue. So accessing x through p is not an access of a object of a volatile-qualified type.

(See 6.7.3 Type qualifiers for the restrictions on accessing objects of qualified types. It just says you can't access a volatile qualified object via an unqualified lvalue.)

On the other hand, this post quotes from the 6.7.3 of the Rationale for International Standard--Programming Languages--C:

A cast of a value to a qualified type has no effect; the qualification (volatile, say) can have no effect on the access since it has occurred prior to the case. If it is necessary to access a non-volatile object using volatile semantics, the technique is to cast the address of the object to the appropriate pointer-to-qualified type, then dereference that pointer.

However, I can't find language in the standard that says that the semantics is based on the lvalue type. From gnu.org:

One area of confusion is the distinction between objects defined with volatile types, and volatile lvalues. From the C standard's point of view, an object defined with a volatile type has externally visible behavior. You can think of such objects as having little oscilloscope probes attached to them, so that the user can observe some properties of accesses to them, just as the user can observe data written to output files. However, the standard does not make it clear whether users can observe accesses by volatile lvalues to ordinary objects.

[..] it is not clear from the standard whether volatile lvalues provide more guarantees in general than nonvolatile lvalues, if the underlying objects are ordinary.

No, because there are no side effects:

Even if the semantics of *p must be that of a volatile, the standard nevertheless says:

5.1.2.3 Program execution 4 In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

Again, there is no volatile object in your code. Although a compilation unit that only sees p couldn't make that optimization.

Also keep in mind

6.7.3 Type qualifiers 7 [...] What constitutes an access to an object that has volatile-qualified type is implementation-defined.

5.1.2.3 Program execution 8 More stringent correspondences between abstract and actual semantics may be defined by each implementation.

So mere appearances of volatile lvalues does not tell you what "accesses" there are. You have no right to talk about "the single access to *p from tmp = *p" except per documented implementation behaviour.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...