Skip to content

Commit

Permalink
sysrq: don't depend on weak undefined arrays to have an address that …
Browse files Browse the repository at this point in the history
…compares as NULL

When taking an address of an extern array, gcc quite naturally should be
able to say "an address of an object can never be NULL" and just
optimize away the test entirely.

However, the new alternate sysrq reset code (commit 154b7a4:
"Input: sysrq - allow specifying alternate reset sequence") did exactly
that, and declared platform_sysrq_reset_seq[] as a weak array, and
expecting that testing the address of the array would show whether it
actually got linked against something or not.

And that doesn't work with all gcc versions.  Clearly it works with
*some* versions of gcc, and maybe it's even supposed to work, but it
really is a very fragile concept.

So instead of testing the address of the weak variable, just create a
weak instance of that array that is empty.  If some platform then has a
real platform_sysrq_reset_seq[] that overrides our weak one, the linker
will switch to that one, and it all works without any run-time
conditionals at all.

Reported-by: Dave Airlie <[email protected]>
Cc: David Howells <[email protected]>
Cc: Russell King <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
Acked-by: Mathieu Poirier <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
torvalds committed Feb 27, 2013
1 parent 0988496 commit adf96e6
Showing 1 changed file with 7 additions and 8 deletions.
15 changes: 7 additions & 8 deletions drivers/tty/sysrq.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,21 +870,20 @@ static struct input_handler sysrq_handler = {

static bool sysrq_handler_registered;

unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };

static inline void sysrq_register_handler(void)
{
extern unsigned short platform_sysrq_reset_seq[] __weak;
unsigned short key;
int error;
int i;

if (platform_sysrq_reset_seq) {
for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
key = platform_sysrq_reset_seq[i];
if (key == KEY_RESERVED || key > KEY_MAX)
break;
for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
key = platform_sysrq_reset_seq[i];
if (key == KEY_RESERVED || key > KEY_MAX)
break;

sysrq_reset_seq[sysrq_reset_seq_len++] = key;
}
sysrq_reset_seq[sysrq_reset_seq_len++] = key;
}

error = input_register_handler(&sysrq_handler);
Expand Down

0 comments on commit adf96e6

Please sign in to comment.