Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > [Q] UB query

Reply
Thread Tools

[Q] UB query

 
 
Ben Bacarisse
Guest
Posts: n/a
 
      12-30-2009
Simon P Simonson <(E-Mail Removed)> writes:

> Simon P Simonson wrote:
>
>> Barry Schwarz wrote:
>>
>>> On Sat, 26 Dec 2009 16:26:43 +0000 (UTC), Simon P Simonson
>>> <(E-Mail Removed)> wrote:
>>>
>>>>In the following code,
>>>>
>>>> 1 main()
>>>> 2 {
>>>> 3 auto a;
>>>> 4 volatile b;
>>>> 5 (void) a;
>>>> 6 (void) b;
>>>> 7 }
>>>>
>>>>is line 5 an undefined behavior? (I would say NO)
>>>>
>>>>is line 6 an undefined behavior? (I would say YES)
>>>
>>> An uninitialized variable without static duration has an indeterminate
>>> value. Any attempt to evaluate such a value leads to undefined
>>> behavior. The fact that you discard the result of the evaluation is
>>> irrelevant. Both statements invoke undefined behavior.

>>
>> Are you sure about this analysis?


Barry is correct from the point of view of portable code, but an
indeterminate value is always either a valid (but unknown) value of
the type in question or it is a trap representation. On a system
whose int type has no trap representations, the effect of evaluating
an indeterminate value is not undefined (in the C sense of the word).
Of course, what value you get is not specified so the effect is
"undefined" in the ordinary sense of the word.

>> Code 1 <<EOF
>> auto a;
>> (void) a;
>> EOF
>>
>> Code 2 <<EOF
>> auto a;
>> EOF
>>
>> By the "as if" rule, these two code extracts are equivalent, and most
>> (all?) compilers will not generate any code for Code 1 following the "as
>> if" rule.


The "as if" rule can't be used to make undefined code defined. On a
system with an int type that has trap reps., a compiler can replace
Code 1 with anything it likes. If int has no trap reps., then Code 1
is defined, and the compiler can replace it with Code 2 because it is
equivalent.

> Actually this raises the interesting question: What code should a
> compiler generated for Code 3?
>
> Code 3 <<EOF
> volatile a;
> (void) a;
> EOF


Pass. On the face of it, it must generate code to access a, but there
may be ways in which it can prove that this is not required.

--
Ben.
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      12-30-2009
Simon P Simonson <(E-Mail Removed)> writes:
> Barry Schwarz wrote:
>
>> On Sat, 26 Dec 2009 16:26:43 +0000 (UTC), Simon P Simonson
>> <(E-Mail Removed)> wrote:
>>
>>>In the following code,
>>>
>>> 1 main()
>>> 2 {
>>> 3 auto a;
>>> 4 volatile b;
>>> 5 (void) a;
>>> 6 (void) b;
>>> 7 }
>>>
>>>is line 5 an undefined behavior? (I would say NO)
>>>
>>>is line 6 an undefined behavior? (I would say YES)

>>
>> An uninitialized variable without static duration has an indeterminate
>> value. Any attempt to evaluate such a value leads to undefined
>> behavior. The fact that you discard the result of the evaluation is
>> irrelevant. Both statements invoke undefined behavior.

>
> Are you sure about this analysis?
>
> Code 1 <<EOF
> auto a;
> (void) a;
> EOF
>
> Code 2 <<EOF
> auto a;
> EOF
>
> By the "as if" rule, these two code extracts are equivalent, and most
> (all?) compilers will not generate any code for Code 1 following the "as
> if" rule.


The "as if" rule doesn't say they're equivalent. It says that
an implementation is allowed to eliminate the evaluation of "a",
transforming Code 1 to the equivalent of Code 2. It's not *required*
to eliminate it.

If "a" happens to contain a trap representation, and the compiler
doesn't optimize away the evaluation, then the program could crash.
(Accessing a trap representation doesn't necessarily cause a crash,
but that's one of the infinitely many possible consequences of
undefined behavior.)

A compiler is allowed to *assume* that no undefined behavior occurs,
and generate code based on that assumption. This is most commonly
shows up in optimization, but a compiler could emit extra checks.
For example, it might generate code that checks whether any variables
are used without being initialized, and that terminates the program
with an error message if the check fails. (Create a flag for
each declared variable. Set it to 1 when the variable has a value
assigned to it. Check the flag whenever the variable is accessed.
Or there might be hardware support.)

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      12-30-2009
Simon P Simonson <(E-Mail Removed)> writes:
[...]
> Obviously I used auto to emphasize and draw attention to the contrast
> between volatile and non-volatile variables that was at the heart of my
> question. Normally I don't use the auto qualifier in my code.


Here's the code again:

1 main()
2 {
3 auto a;
4 volatile b;
5 (void) a;
6 (void) b;
7 }

(Incidentally, posting code with line numbers makes it more difficult
for the rest of us to copy-and-paste it and try it ourselves. If you
want to refer to a line by number, add a "/* line 5 */ comment.)

"auto" is a storage-class specifier; "volatile" is a type qualifier.
Both "a" and "b" have the same storage class. If you wanted to be
painfully explicit, you could have written:

auto int a;
volatile auto int b;

This:

int a;
volatile int b;

would have been clearer and would have made your point better.
Omitting the type, and letting it default to int, is considered
poor style in C90, and isn't even allowed in C99.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Simon P Simonson
Guest
Posts: n/a
 
      12-30-2009
Ben Bacarisse wrote:

> Simon P Simonson <(E-Mail Removed)> writes:


>>> Code 1 <<EOF
>>> auto a;
>>> (void) a;
>>> EOF
>>>
>>> Code 2 <<EOF
>>> auto a;
>>> EOF
>>>
>>> By the "as if" rule, these two code extracts are equivalent, and most
>>> (all?) compilers will not generate any code for Code 1 following the
>>> "as if" rule.

>
> The "as if" rule can't be used to make undefined code defined. On a
> system with an int type that has trap reps., a compiler can replace Code
> 1 with anything it likes. If int has no trap reps., then Code 1 is
> defined, and the compiler can replace it with Code 2 because it is
> equivalent.
>
>> Actually this raises the interesting question: What code should a
>> compiler generated for Code 3?
>>
>> Code 3 <<EOF
>> volatile a;
>> (void) a;
>> EOF

>
> Pass. On the face of it, it must generate code to access a, but there
> may be ways in which it can prove that this is not required.


OK, but what does it mean to access a? If a is stored in a memory
location (possibly memory mapped hardware) is it enough to load a into a
register? What if a is already in cache?
 
Reply With Quote
 
Barry Schwarz
Guest
Posts: n/a
 
      12-30-2009
On Wed, 30 Dec 2009 13:26:30 +0000 (UTC), Simon P Simonson
<(E-Mail Removed)> wrote:

>Barry Schwarz wrote:
>
>> On Sat, 26 Dec 2009 16:26:43 +0000 (UTC), Simon P Simonson
>> <(E-Mail Removed)> wrote:
>>
>>>In the following code,
>>>
>>> 1 main()
>>> 2 {
>>> 3 auto a;
>>> 4 volatile b;
>>> 5 (void) a;
>>> 6 (void) b;
>>> 7 }
>>>
>>>is line 5 an undefined behavior? (I would say NO)
>>>
>>>is line 6 an undefined behavior? (I would say YES)

>>
>> An uninitialized variable without static duration has an indeterminate
>> value. Any attempt to evaluate such a value leads to undefined
>> behavior. The fact that you discard the result of the evaluation is
>> irrelevant. Both statements invoke undefined behavior.

>
>Are you sure about this analysis?
>
>Code 1 <<EOF
>auto a;
>(void) a;
>EOF
>
>Code 2 <<EOF
>auto a;
>EOF
>
>By the "as if" rule, these two code extracts are equivalent, and most
>(all?) compilers will not generate any code for Code 1 following the "as
>if" rule.


You didn't ask if the generated code would be well behaved on most
systems. What about turning ALL optimization off.

You used the standard specific term "undefined behavior" so I assumed
you wanted to know what the standard specified.

I guess I could have been a bit more precise and said the behavior is
undefined at the point the value is evaluated.

--
Remove del for email
 
Reply With Quote
 
Flash Gordon
Guest
Posts: n/a
 
      12-30-2009
Simon P Simonson wrote:
> Ben Bacarisse wrote:
>
>> Simon P Simonson <(E-Mail Removed)> writes:


<snip>

>>> Actually this raises the interesting question: What code should a
>>> compiler generated for Code 3?
>>>
>>> Code 3 <<EOF
>>> volatile a;
>>> (void) a;
>>> EOF

>> Pass. On the face of it, it must generate code to access a, but there
>> may be ways in which it can prove that this is not required.

>
> OK, but what does it mean to access a?


That is implementation defined...

> If a is stored in a memory
> location (possibly memory mapped hardware) is it enough to load a into a
> register? What if a is already in cache?


The documentation for the implementation should tell you what it does,
since implementation defined means it has to be documented. In most
implementations it will do something sensible, and if you need to do
more than just use volatile it will tell you what, but that is a matter
of quality rather than requirement.
--
Flash Gordon
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      12-30-2009
Simon P Simonson <(E-Mail Removed)> writes:
> Ben Bacarisse wrote:
>> Simon P Simonson <(E-Mail Removed)> writes:

[...]
>>> Actually this raises the interesting question: What code should a
>>> compiler generated for Code 3?
>>>
>>> Code 3 <<EOF
>>> volatile a;
>>> (void) a;
>>> EOF

>>
>> Pass. On the face of it, it must generate code to access a, but there
>> may be ways in which it can prove that this is not required.

>
> OK, but what does it mean to access a? If a is stored in a memory
> location (possibly memory mapped hardware) is it enough to load a into a
> register? What if a is already in cache?


Here's what the standard says (C99 6.7.3p6):

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. Furthermore,
at every sequence point the value last stored in the object
shall agree with that prescribed by the abstract machine, except
as modified by the unknown factors mentioned previously. What
constitutes an access to an object that has volatile-qualified
type is implementation-defined.

with a footnote:

A volatile declaration may be used to describe an object
corresponding to a memory-mapped input/output port or an object
accessed by an asynchronously interrupting function. Actions
on objects so declared shall not be ‘‘optimized out’’
by an implementation or reordered except as permitted by the
rules for evaluating expressions.

On the other hand, if you just apply "volatile" to a local variable,
the compiler can reasonably know that there's no magic going on behind
the scenes. It's not clear whether the compiler is permitted to take
advantage of this knowledge; I'd say it probably isn't.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      01-13-2010
Ben Bacarisse <(E-Mail Removed)> writes:

> Simon P Simonson <(E-Mail Removed)> writes:
>
>> Simon P Simonson wrote:
>>
>>> Barry Schwarz wrote:
>>>
>>>> On Sat, 26 Dec 2009 16:26:43 +0000 (UTC), Simon P Simonson
>>>> <(E-Mail Removed)> wrote:
>>>>
>>>>>In the following code,
>>>>>
>>>>> 1 main()
>>>>> 2 {
>>>>> 3 auto a;
>>>>> 4 volatile b;
>>>>> 5 (void) a;
>>>>> 6 (void) b;
>>>>> 7 }
>>>>>
>>>>>is line 5 an undefined behavior? (I would say NO)
>>>>>
>>>>>is line 6 an undefined behavior? (I would say YES)
>>>>
>>>> An uninitialized variable without static duration has an indeterminate
>>>> value. Any attempt to evaluate such a value leads to undefined
>>>> behavior. The fact that you discard the result of the evaluation is
>>>> irrelevant. Both statements invoke undefined behavior.
>>>
>>> Are you sure about this analysis?

>
> Barry is correct from the point of view of portable code, but an
> indeterminate value is always either a valid (but unknown) value of
> the type in question or it is a trap representation. On a system
> whose int type has no trap representations, the effect of evaluating
> an indeterminate value is not undefined (in the C sense of the word).
> Of course, what value you get is not specified so the effect is
> "undefined" in the ordinary sense of the word.


This was covered (IIRC) in one of the DR's. I believe the
behavior is undefined even if the type in question has no
trap representations, eg, even (unsigned char) can be
undefined behavior. That doesn't hold (again IIRC) for
variables whose address has been taken with &, and I'm
not sure if a variable declared 'volatile' is different.
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      01-13-2010
Keith Thompson <(E-Mail Removed)> writes:

> Simon P Simonson <(E-Mail Removed)> writes:
>> Ben Bacarisse wrote:
>>> Simon P Simonson <(E-Mail Removed)> writes:

> [...]
>>>> Actually this raises the interesting question: What code should a
>>>> compiler generated for Code 3?
>>>>
>>>> Code 3 <<EOF
>>>> volatile a;
>>>> (void) a;
>>>> EOF
>>>
>>> Pass. On the face of it, it must generate code to access a, but there
>>> may be ways in which it can prove that this is not required.

>>
>> OK, but what does it mean to access a? If a is stored in a memory
>> location (possibly memory mapped hardware) is it enough to load a into a
>> register? What if a is already in cache?

>
> Here's what the standard says (C99 6.7.3p6):
>
> 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. Furthermore,
> at every sequence point the value last stored in the object
> shall agree with that prescribed by the abstract machine, except
> as modified by the unknown factors mentioned previously. What
> constitutes an access to an object that has volatile-qualified
> type is implementation-defined.
>
> with a footnote:
>
> A volatile declaration may be used to describe an object
> corresponding to a memory-mapped input/output port or an object
> accessed by an asynchronously interrupting function. Actions
> on objects so declared shall not be ''optimized out''
> by an implementation or reordered except as permitted by the
> rules for evaluating expressions.
>
> On the other hand, if you just apply "volatile" to a local variable,
> the compiler can reasonably know that there's no magic going on behind
> the scenes. It's not clear whether the compiler is permitted to take
> advantage of this knowledge; I'd say it probably isn't.


The whole point of volatile is that the compiler does NOT know
and must not assume that it does, even for local variables.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-13-2010
Tim Rentsch <(E-Mail Removed)> writes:

> Ben Bacarisse <(E-Mail Removed)> writes:

<snip?
>> Barry is correct from the point of view of portable code, but an
>> indeterminate value is always either a valid (but unknown) value of
>> the type in question or it is a trap representation. On a system
>> whose int type has no trap representations, the effect of evaluating
>> an indeterminate value is not undefined (in the C sense of the word).
>> Of course, what value you get is not specified so the effect is
>> "undefined" in the ordinary sense of the word.

>
> This was covered (IIRC) in one of the DR's. I believe the
> behavior is undefined even if the type in question has no
> trap representations, eg, even (unsigned char) can be
> undefined behavior.


Do you have a reference? A DR that modifies what seems to be the
clear wording of standard, it usually ends with an edit to the wording
which should be reflected in the drafts. I don't understand the
process that well, so I may have got this wrong. The text of the DR
would help.

<snip>
--
Ben.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
ASP.NET won't retrieve query results that depend on union query Eric Nelson ASP .Net 5 02-04-2009 10:51 PM
Trying to query the Address table data of AdventureWorks database from Query Analyzer - need help! Learner ASP .Net 1 01-30-2006 08:58 PM
Build dynamic sql query for JSTL <sql:query> Anonymous Java 0 10-13-2005 10:01 PM
xpath query query David Gordon XML 2 05-18-2005 03:33 PM
CAML Query: Multiple Query Fields Issue Jon F. ASP .Net Web Services 0 05-12-2004 08:19 PM



Advertisments