Date: Fri, 12 May 1995 17:59:24 +0300 From: Tatu Ylonen <ylo@cs.hut.fi> To: bde@zeta.org.au Cc: maddox@CS.Berkeley.EDU, freebsd-bugs@freefall.cdrom.com, maddox@redwood.CS.Berkeley.EDU, shadows-tech@cs.hut.fi Subject: Re: i386/395: CRITICAL PROBLEM: spl functions implemented incorrectly Message-ID: <199505121459.RAA03674@shadows.cs.hut.fi> In-Reply-To: <199505120932.TAA20816@godzilla.zeta.org.au> (bde@zeta.org.au)
index | next in thread | previous in thread | raw e-mail
> No it can't. `static inline' functions have the same semantics as
> ordinary static functions. They aren't equivalent to macros. Reordering
> is severely limited by the C Standard. The ISO version section 5.1.2.3
> says:
>
> "Accessing a volatile object, modifying an object, modifying a file, or
> calling a function that does any of these operations are all _side effects_.
> At ... _sequence points_, all side effects of previous evaluations shall
> be complete and no side effects of subsequent evaluations shall have
> taken place".
>
> Note that static [inline] functions are not special. spl*() all modify
> the (non-volatile) object `cpl', so the above applies to them. Making
> `cpl' volatile wouldn't affect this and would be wrong (it isn't volatile
> as far as C routines can tell since interrupt handlers preserve it).
You don't say anything about what can be assumed about values of non-volatile
expressions.
I checked with gcc-2.6.3 (with patches for i386 bugs - I get same
results with plain 2.6.3). The following code:
extern int cpl;
extern int value;
static __inline int spl1()
{
int old = cpl;
cpl |= 1;
return old;
}
static __inline void splx(int x)
{
cpl = x;
}
void foo()
{
int x, y;
value *= 2;
x = spl1();
value *= 3;
splx(x);
}
When compiled with "gcc -O -S koe.c" this gives:
.file "koe.c"
gcc2_compiled.:
___gnu_compiled_c:
.text
.align 2
.globl _foo
.type _foo,@function
_foo:
pushl %ebp
movl %esp,%ebp
movl _value,%eax
leal 0(,%eax,2),%edx
movl %edx,_value
movl _cpl,%ecx
orb $1,_cpl
leal (%edx,%eax,4),%eax <-- note: "value" kept in register across
movl %eax,_value call to spl1.
movl %ecx,_cpl
leave
ret
Lfe1:
.size _foo,Lfe1-_foo
Thus, the spl code did not do what it was supposed to do: we cannot
make assumptions about values computed before entering the critical
section being still valid in the critical section.
There definitely is a serious problem here. I cannot be absolutely
sure whether it is in the compiler or in the kernel as I do not have
the standard. In my opinion the compiler is doing only reasonable and
expectable things here. It is keeping the non-volatile value "value"
in a register across a call it knows will not modify "value". This
sounds very reasonable.
Tatu Ylonen <ylo@cs.hut.fi>
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199505121459.RAA03674>
