Re: linux-next: build failure

Previous thread: Improving the existing /proc/loadavg metrics by auntvini on Tuesday, July 29, 2008 - 6:53 am. (1 message)

Next thread: sparc64: build failure at sys_sparc32.c by Alexander Beregalov on Monday, July 28, 2008 - 11:59 pm. (6 messages)
From: Stephen Rothwell
Date: Monday, July 28, 2008 - 11:23 pm

Hi Dave,

Today's linux-next build (sparc64 defconfig) failed like this:

kernel/time/tick-common.c: In function `tick_check_new_device':
kernel/time/tick-common.c:210: error: invalid lvalue in unary `&'
kernel/time/tick-common.c:223: error: invalid lvalue in unary `&'
kernel/time/tick-common.c:255: error: invalid lvalue in unary `&'

gcc is version 3.4.5 sparc64 cross compiler (powercp64 host).

The below patch fixes it.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 29 Jul 2008 16:07:37 +1000
Subject: [PATCH] cpumask: statement expressions confuse some versions of gcc

when you take the address of the result.  Noticed on a sparc64 compile
using a version 3.4.5 cross compiler.

kernel/time/tick-common.c: In function `tick_check_new_device':
kernel/time/tick-common.c:210: error: invalid lvalue in unary `&'
kernel/time/tick-common.c:223: error: invalid lvalue in unary `&'
kernel/time/tick-common.c:255: error: invalid lvalue in unary `&'

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 include/linux/cpumask.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 96d0509..d3219d7 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -287,7 +287,7 @@ static inline const cpumask_t *get_cpu_mask(unsigned int cpu)
  * gcc optimizes it out (it's a constant) and there's no huge stack
  * variable created:
  */
-#define cpumask_of_cpu(cpu) ({ *get_cpu_mask(cpu); })
+#define cpumask_of_cpu(cpu) (*get_cpu_mask(cpu))
 
 
 #define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS)
-- 
1.5.6.3

--

From: Ingo Molnar
Date: Tuesday, July 29, 2008 - 1:00 am

hm, i'm wondering - is this a compiler bug?

	Ingo
--

From: Stephen Rothwell
Date: Tuesday, July 29, 2008 - 1:03 am

Hi Ingo,


Or maybe a deficiency in such an old compiler (v3.4.5) but the fix makes
sense anyway, right?

--=20
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
From: Ingo Molnar
Date: Tuesday, July 29, 2008 - 1:58 am

yeah, i was just wondering.

	Ingo
--

From: KOSAKI Motohiro
Date: Tuesday, July 29, 2008 - 4:28 am

in linux/README

COMPILING the kernel:

 - Make sure you have at least gcc 3.2 available.
   For more information, refer to Documentation/Changes.



So, if 3.4.5 is old, Should we change readme?



--

From: Ingo Molnar
Date: Tuesday, July 29, 2008 - 4:40 am

the fix is simple enough.

but the question is, wont it generate huge artificial stackframes with 
CONFIG_MAXSMP and NR_CPUS=4096? Maybe it is unable to figure out and 
simplify the arithmetics there - or something like that.

	Ingo
--

From: Mike Travis
Date: Tuesday, July 29, 2008 - 7:31 am

I've looked at stack frames quite extensively and usually they are
not generated unless you explicitly use a named cpumask variable,
pass a cpumask by value, expect a cpumask function return, create
an initializer that contains a cpumask field, and (probably a couple
more I missed).

Almost all others are done efficiently via pointers or simple
struct copies:

	cpus_xxx(*cpumask_of_cpu(), ...
	struct->cpumask_var = *cpumask_of_cpu()
	global_cpumask_var = *cpumask_of_cpu()
	etc.

Thanks,
Mike
--

From: Mike Travis
Date: Tuesday, July 29, 2008 - 7:33 am

Geez, I edited the above after I first used *cpumask_var and didn't
get the semantics right!

 	cpus_xxx(cpumask_of_cpu(), ...
 	struct->cpumask_var = cpumask_of_cpu()
 	global_cpumask_var = cpumask_of_cpu()

--

From: Linus Torvalds
Date: Tuesday, July 29, 2008 - 9:33 am

Quite the reverse.

The "address-of statement expression" is the one that is more likely to 
generate artificial stack-frames because of a temporary variable (of 
course, I wouldn't count on it, since statement expressions are gcc 
extensions, and as such the gcc people could make up any semantics they 
want to them, including just defining that a statement expression with 
an lvalue value is the same lvalue rather than any temporary). 

In contrast, "address-of lvalue" is _guaranteed_ to not do anything stupid 
like that, and gives just the address-of.

Oh, and I was wrong about the &*x losing the 'const'. It doesn't. So I 
think Stephen's patch is fine after all - if somebody tries to modify the 
end result through the pointer, it will give a big compiler warning.

			Linus
--

From: Ingo Molnar
Date: Tuesday, July 29, 2008 - 9:42 am

yeah, both variants do that, i've checked it earlier today - i tried to 
find a way to get something more drastic than a compiler warning. (but 
failed)

	Ingo
--

From: Linus Torvalds
Date: Tuesday, July 29, 2008 - 9:44 am

In fact, that does seem what gcc-4.x does. The way to tell is to do

	const int *x;

	({ *x }) = 1;

and it's (a) legal (assignments to non-lvalues wouldn't work) and (b) 
gives a nice warning about assignment to read-only location, which in turn 
implies that the compiler properly just peeled off the de-reference even 
though it was inside the statement expression.

IOW, at least in gcc-4.3 (and apparently in earlier gcc-4 versions, but 
not in gcc-3.4.5), a statement expression with an lvalue return value _is_ 
actually an lvalue.

But that also means that there is no difference what-so-ever between (x) 
and ({ x; }) in gcc-4. And in gcc-3 there is, because apparently in gcc-3 
a statement expression is never an lvalue (which is actually the sane 
thing, imho).

			Linus
--

From: Wenji Huang
Date: Tuesday, July 29, 2008 - 1:14 am

Same problem on x86/gcc 3.4.6, but will pass on gcc 4.x

Regards,
Wenji
--

From: Linus Torvalds
Date: Tuesday, July 29, 2008 - 9:26 am

Not necessarily. The code is fragile.

Doing a statement expression basically creates a new temporary variable 
with pretty much undefined scope. Taking the address of it *may* be 
optimized away to the original cpu_mask pointer, but it's not really a 
well-defined operation: there really _is_ a local temporary variable, and 
if you were to change things through the address-of thing, gcc would be 
buggy if it had done the optimization.

So the "address-of statement expression" really is a dubious construct.

That said, the change that Stephen introduces is _not_ a no-op. It very 
fundamentally changes the code - exactly because now there is no temporary 
value created any more: it's a real lvalue, and now anybody who does 
&cpumask_of_cpu(cpu) will fundamentally get the original pointer back, 
except it has lost the "const".

And that's actually dangerous - exactly because it now loses the "const" 
thing, there may be people who end up modifying the result without 
getting any compile-time warnings.

I would _seriously_ suggest that both the original code and Stephen's 
modified version is really bad. And you should have taken my interface 
as-is - one that returns a "const cpumask_t *", and nothing else. 

Anything else is simply fundamentally broken.

			Linus
--

Previous thread: Improving the existing /proc/loadavg metrics by auntvini on Tuesday, July 29, 2008 - 6:53 am. (1 message)

Next thread: sparc64: build failure at sys_sparc32.c by Alexander Beregalov on Monday, July 28, 2008 - 11:59 pm. (6 messages)