[comp.lang.c] Volatile is stupid

firth@sei.cmu.edu (Robert Firth) (06/09/88)

I'm on Chris' side in this debate.  The cue word "volatile" is
unnecessary, stupid, and anyway insufficient for the job.

The only way a programmer can know that an address is volatile is
if he has read some document that says so:

"the time-of-day register is 16#fffffeeb#, and when read will return
 the current time-of-day in millicatnaps since last Tuesday"

Or, alternatively, he has built the hardware himself, stuffed it into
the chassis, and scribbled a few notes in magic marker on the side.

Either way, the programmer now has to do something special to all
the programs (or all their header files) that reference that new
hardware.

Would it not be far simpler, and far safer, for the compiler to read
a single "target memory definition file", or similar, that says

	00000000..0003ffff is ROM
	00040000..00ffffff is RAM
	fffffeeb	   is volatile

and so on, and so on?  If anyone changes the physical target, they edit
the target memory definition file.  The complier simply reads this file
whenever it compiles a program, and does the right thing.  If you are
writing code for such a target, you have an environment variable or
whatever that points to "/usr/targets/mc68000/TESTBENCH5.mdf", or some
such.

Not only does this work, it is amenable to decent verification, management,
configuration control, and maintenance.  "Volatile" is a hacker's answer.

guy@gorodish.Sun.COM (Guy Harris) (06/10/88)

As I understand it, not all "volatile" locations are that way only because some
piece of external hardware is going to change them; even if they were, there's
no guarantee that you can specify that a fixed range of addresses (other than,
say, 0x00000000 - 0xffffffff on a machine with 32-bit addresses) are
potentially volatile and that no others are.

pja@ralph.UUCP (Pete Alleman) (06/19/88)

In article <5800@aw.sei.cmu.edu> firth@bd.sei.cmu.edu.UUCP (Robert Firth) writes:
>Would it not be far simpler, and far safer, for the compiler to read
>a single "target memory definition file", or similar, that says
>
>	00000000..0003ffff is ROM
>	00040000..00ffffff is RAM
>	fffffeeb	   is volatile
>
>and so on, and so on?  If anyone changes the physical target, they edit
>the target memory definition file.  The complier simply reads this file
>whenever it compiles a program, and does the right thing.  If you are
>
>Not only does this work, it is amenable to decent verification, management,
>configuration control, and maintenance.  "Volatile" is a hacker's answer.

The compiler generally DOES NOT KNOW the address being accessed.  The only
time the compiler can know an absolute address is when that address is
an int being typecast to a pointer and then dereferenced.

As an example suppose I were to write this routine:
dev_wait (csr)
volatile int *csr;
{
	/* wait for the device to complete some operation */
	while (*csr & DEVBUSY)
		/* So this is in the kernel, reasonable example */
		sleep (csr, PRI);
}

How could the compiler possibly know that the pointer passed
at runtime might point to a volatile location (without the keyword)??

The compiler generally works with symbolic addresses.  The LINKER assigns
values to those symbols and puts the actual numbers in the proper locations
in the code.  
-- 
Pete Alleman
	ralph!pja or
	digitran!pja

chris@mimsy.UUCP (Chris Torek) (06/21/88)

>In article <5800@aw.sei.cmu.edu> firth@bd.sei.cmu.edu.UUCP (Robert Firth)
>writes:
>>... the compiler [could] read a single "target memory definition file",
>>or similar, that says
>>	00000000..0003ffff is ROM
>>	00040000..00ffffff is RAM
>>	fffffeeb	   is volatile
>>... Not only does this work, it is amenable to decent verification,
>>management, configuration control, and maintenance.  "Volatile" is
>>a hacker's answer.

(with which I mostly agree, although I think `hacker's answers' are not
inherently wrong.)

In article <278@ralph.UUCP> pja@ralph.UUCP (Pete Alleman) writes:
>The compiler generally DOES NOT KNOW the address being accessed.

And why not?  The answer is only that `the compiler' is too limited:

>As an example suppose I were to write this routine:
>dev_wait (csr)
>volatile int *csr;
>{
>	/* wait for the device to complete some operation */
>	while (*csr & DEVBUSY)
>		/* So this is in the kernel, reasonable example */
>		sleep (csr, PRI);
>}
>
>How could the compiler possibly know that the pointer passed
>at runtime might point to a volatile location (without the keyword)??

Ask the question this way:  Who calls dev_wait?  If you look at a
PDP-11 kernel, it may look like this:

	dev_open(dev)
		dev_t dev;
	{
		register struct devdevice *devaddr = DEVADDR;
		...
		dev_wait(&devaddr->dev_csr);
		...
	}

So the caller (here dev_open()) *does* know the address being accessed
(after a bit of flow analysis).  All the compiler need do (`all' he
says :-) ) is pass that information on down into the generation of
dev_wait().

`But wait!' you object.  `What if dev_open is in a separate file?'

Compilation (including alias and volatility analysis) need not occur
until `link' time.

`But wait!' you object.  `What if I read the address in at run-time?'

	main()
	{
		int *ip;
		...
		... read(fd, (char *)&ip, sizeof(ip));
		...
		while (*ip & BUSY)
			/* void */;
		...
	}

Is *ip volatile?  I cannot say---but neither can you.  The compiler
(which may be disguised as a linker) does not know either.  It must
therefore assume that it is volatile.

The key point here is that there is no algorithmic way to determine
volatility in this worst case---so any competent programmer must
assume that, if there are any volatile addresses, this code may refer
to one.  The programmer's only other option is to decree that the
program must never read an address that *is* volatile.  A programmer
who makes such a decree is certain to be surprised by a user.  If
you meant that *ip had better not be volatile, you should check ip:

	if (is_volatile(ip)) {
		fprintf(stderr, "%s: bad input data in %s\n",
			progname, infile);
		exit(EX_DATAERR);
	}
	while (*ip & BUSY)
		/* void */;

How will you write is_volatile()?  On an IBM PC you might say

	if ((unsigned long)ip >= 640*1024L) ...

Once you have done that, the compiler can (by a bit of range checking)
also determine that *ip is not volatile.

`But wait!' you say.  `Even a very fancy optimising ``compiler''
(linker) is going to miss *some* things.  Why, we can use some fancy
mathematics to prove that it cannot catch everything.'

That is so.  But how often will this occur in practise?  Today,
probably all the time; but tomorrow?  Five years from now?  Fifty?
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

smryan@garth.UUCP (Steven Ryan) (06/22/88)

>>>... Not only does this work, it is amenable to decent verification,
>>>management, configuration control, and maintenance.  "Volatile" is
>>>a hacker's answer.

What isn't a hack in Unix?

>>The compiler generally DOES NOT KNOW the address being accessed.
>
>And why not?  The answer is only that `the compiler' is too limited:

Inherently too limited.
 
>Ask the question this way:  Who calls dev_wait?  If you look at a
>PDP-11 kernel, it may look.....

Optimisers are essentially big bags of clever tricks. When some construct
sucks up enough runtime, somebody will figure a way to recognise it and
speed it up. Thus optimisers get better and better (and bigger and bigger)
BUT they are inherently limited.
 
>The key point here is that there is no algorithmic way to determine
>volatility in this worst case---so any competent programmer must
>assume that, if there are any volatile addresses, this code may refer
>to one.  The programmer's only other option is to decree that the
>program must never read an address that *is* volatile.  A programmer
>who makes such a decree is certain to be surprised by a user.  If
>you meant that *ip had better not be volatile, you should check ip:

Hear! Hear! Safe programming means verifying each assertion about your input.
 
>`But wait!' you say.  `Even a very fancy optimising ``compiler''
>(linker) is going to miss *some* things.  Why, we can use some fancy
                                                                -----
>mathematics to prove that it cannot catch everything.'

(Was it really that fancy? Godel incompleteness=Turing's halting problem.
Everybody should know the answer to that.)

I disagree that volatile is therefore stupid. That is a value judgement.
Dangerous? Perhaps. Unnecessary in many cases? Perhaps. Up to the user to
decide?

chris@mimsy.UUCP (Chris Torek) (06/26/88)

>In article <12056@mimsy.UUCP> I suggested that a worst case (not
necessarily the only one) is where a pointer is read in at runtime:
>>The key point here is that there is no algorithmic way to determine
>>volatility in this worst case---so any competent programmer must
>>assume that, if there are any volatile addresses, this code may refer
>>to one.  The programmer's only other option is to decree that the
>>program must never read an address that *is* volatile.  A programmer
>>who makes such a decree is certain to be surprised by a user. ...

In article <314@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu
(Rob Carriere) writes:
>What if the pointer ip is the output of another program, known to
>produce only non-volatile pointers?

Then the program will work fine for five years, and someone will install
it in an airplane controller, then someone else will manually `correct'
something, and your program will crash, along with the airplane.  This
is what correctness checking is all about.

>I know, the compiler.... That compiler is going to be rather sizable!

Yes, it will probably be enormous.  I doubt that I would want to use
it until computers are some orders of magnitude faster than they are
today.

>>`But wait!' you say.  `Even a very fancy optimising ``compiler''
>>(linker) is going to miss *some* things.  Why, we can use some fancy
>>mathematics to prove that it cannot catch everything.'
>>
>>That is so.  But how often will this occur in practise?  Today,
>>probably all the time; but tomorrow?  Five years from now?  Fifty?

>1) You started out by saying ``volatile'' is *useful* not *necessary*.
>   You have just admitted the fallacy of your own argument :-) 

Not really: I believe it is not necessary to get perfect optimisation:
enough that the difference is hard to notice is enough.  Any more is
unnecessary.  (In a way, *all* optimisation is unnecessary.  Useful
though. :-) )

>3) All this discussing boils down to: we have to tell the compiler
>   about the volitile things in life at *some* time, either when it's
>   born (your point of view),
(or at compile time, just before compiling the code)
>				or when it gobbles up my program (us
>   volatile types).  Well, *I* have to know as well (or I can't write the
>   code correctly) => from a readability point of view that means that
>   that information should be IN THE CODE.  Now, that's easy to achieve,
>   just add a keyword, say ``volatile''...

And if you have been reading all of my articles, I happen to agree.
I *like* the volatile keyword!  But I also like automatic volatility
detection.  A compiler that says

	"foo.c", line 1234: warning: *p may be volatile,
		but is not declared so

and then goes on to produce an incorrect program is *much* better than
one that simply produces the incorrect program.

And I think I shall say no more on that, at least for a few months.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

mcdonald@uxe.cso.uiuc.edu (06/27/88)

>Then the program will work fine for five years, and someone will install
>it in an airplane controller, then someone else will manually `correct'
>something, and your program will crash, along with the airplane.  This
>is what correctness checking is all about.

Does anyone know what language was used to write the control program
for the Airbus A320 "crash by wire" plane?

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/29/88)

In article <225800039@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes:
>>Then the program will work fine for five years, and someone will install
>>it in an airplane controller, then someone else will manually `correct'
>>something, and your program will crash, along with the airplane.  This
>>is what correctness checking is all about.
>Does anyone know what language was used to write the control program
>for the Airbus A320 "crash by wire" plane?

Who cares?  Such programs should NOT repeat NOT rely on theoretical
total correctness of the compiler, application code, etc. for their
safety!  It is known how to engineer reliability into systems.

I think someone has been listening too intently to the bogus anti-SDI
argument that "everything has to function perfectly the first time".