lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 2 Dec 2006 05:39:03 -0500
From:	Kyle Moffett <mrmacman_g4@....com>
To:	davids@...master.com
Cc:	"Linux-Kernel@...r. Kernel. Org" <linux-kernel@...r.kernel.org>,
	schwab@...e.de
Subject: Re: [patch 2.6.19-rc6] Stop gcc 4.1.0 optimizing wait_hpet_tick away

On Dec 01, 2006, at 09:03:26, David Schwartz wrote:
>> "David Schwartz" <davids@...master.com> writes:
>>> The problem is that '*(volatile unsigned int *)' results in a  
>>> 'volatile unsigned int'.
>>
>> No, it doesn't.  Values don't have qualifiers, only objects have.   
>> Qualifiers on rvalues are meaningless.
>
> Yeah. That's the problem here. The 'volatile' has no object to  
> qualify. You are essentially lying to the compiler (telling it the  
> pointer points to a volatile object when it doesn't) and hoping it  
> does the right thing.

No, the volatile has a perfectly valid object to qualify; the object  
pointed to by the provided pointer.  Casting in C is explicitly  
defined so that you can change the properties of something.  When I  
cast a "char *" pointer to "int *", I'm not telling the compiler to  
go through and magically convert a bunch of data, I'm telling it to  
treat the preexisting memory addresses, whatever they happened to be,  
as integer data.  The _only_ place where that is not true is casting  
an "int" to a "float" or vice versa, and even then it doesn't apply  
to any levels of indirection (casting "int *" to "float *" is  
virtually guaranteed to cause headaches for first-year CS students).

Likewise when I cast a pointer to "(volatile int *)", I am telling it  
that whatever happened before I want it to treat accesses through  
that new pointer as accesses to a volatile object, with all the  
implied confusion.  Now if my code isn't careful about aliasing and I  
modified the data through a different pointer a few moments before  
(and I have strict-aliasing turned on) then I may get inconsistent  
results because the value has not been written to memory yet just  
stored in a register.

> Nothing in the standard requires any special behavior for accesses  
> through volatile-qualified pointers. It only requires special  
> behavior for access to objects that are in fact volatile.

This is completely and utterly wrong.  See this quote from the C99  
standard pulled from the bugzilla page:
>> 6.7.3:  any expression referring to an object of volatile- 
>> qualified type must be evaluated strictly by the rules of the  
>> abstract machine, although precisely what constitutes an "access"  
>> to the object is implementation-defined.  (Note, implementation- 
>> defined" behavior is required to be well-defined and  
>> documented*.)  So if the reference in question is an "access", it  
>> must occur where the abstract machine says it should.

Now GCC's documentation in multiple places refer to an empty  
statement containing an lvalue or rvalue as being "read" access.   
Example: The statement "int i = 0; i;" would cause "i" to be "read"  
in the second statement.  Since "i" is not volatile then it may be  
optimized out, however if I stated "volatile int i = 0; i;", then the  
compiler would allocate "i" on the stack, assign 0 to it, then read  
it into a register.  GCC could not optimize any part of that out  
without breaking the rules of the abstract machine.

> I think the technically right solution is some mechanism to define  
> an object (which can be volatile-qualified) that exists at a  
> particular address.  Accessing this object would be accessing a  
> volatile object and you'd get all the things the standard promises.

Umm, that's exactly what "volatile" on a pointer means; treat this  
memory address as containing a volatile-qualified object.

> An adequate solution would probably be to make 'readl' return a  
> volatile-qualified unsigned integer.

No, you cannot return a volatile-qualified value because you a return  
value is an "rvalue" and rvalues cannot be "volatile".  They can't be  
"const" or "restrict" either, it just doesn't make any sense.

What would these mean?

const int foo(float x);
restrict int foo(float x);

How can a return-value be const or restrict?  It doesn't have an  
address I can take so I can't modify it where it is.  If you have an  
expression for which you cannot get the address of with the "&"  
operator (in other words, an rvalue) then "volatile", "const", or  
"restrict" make no sense on the type of your expression.

> It comes down to just what those guarantees GCC provides actually are.

This is the first correct statement in your email.  In any case the  
documented GCC guarantees have always been much stronger than you  
have been trying to persuade us they should be.  I would argue that  
the C standard somewhat indirectly specifies those guarantees but I  
really don't have the heart for any more language-lawyering so I'm  
going to leave it at that.

Cheers,
Kyle Moffett

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists