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)
next in thread | previous in thread | raw e-mail | index | archive | help
> 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>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199505121459.RAA03674>