public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Extern variables in *.c files
@ 2002-01-02 18:18 vda
  2002-01-02 19:24 ` Oliver Xymoron
  0 siblings, 1 reply; 11+ messages in thread
From: vda @ 2002-01-02 18:18 UTC (permalink / raw)
  To: linux-kernel

I grepped kernel *.c (not *.h!) files for extern variable definitions.
Much to my surprize, I found ~1500 such defs.

Isn't that bad C code style? What will happen if/when type of variable gets 
changed? (int->long).

I thought external definitions ought to be in *.h files.
Maybe I'm missing something here...
--
vda

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-02 18:18 Extern variables in *.c files vda
@ 2002-01-02 19:24 ` Oliver Xymoron
  2002-01-02 21:43   ` Andrew Morton
  0 siblings, 1 reply; 11+ messages in thread
From: Oliver Xymoron @ 2002-01-02 19:24 UTC (permalink / raw)
  To: vda; +Cc: linux-kernel

On Wed, 2 Jan 2002, vda wrote:

> I grepped kernel *.c (not *.h!) files for extern variable definitions.
> Much to my surprize, I found ~1500 such defs.
>
> Isn't that bad C code style? What will happen if/when type of variable gets
> changed? (int->long).

Yes; Int->long won't change anything on 32-bit machines and will break
silently on 64-bit ones. The trick is finding appropriate places to put
such definitions so that all the things that need them can include them
without circular dependencies.

-- 
 "Love the dolphins," she advised him. "Write by W.A.S.T.E.."


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-02 19:24 ` Oliver Xymoron
@ 2002-01-02 21:43   ` Andrew Morton
  2002-01-02 22:07     ` Momchil Velikov
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Morton @ 2002-01-02 21:43 UTC (permalink / raw)
  To: Oliver Xymoron; +Cc: vda, linux-kernel

Oliver Xymoron wrote:
> 
> On Wed, 2 Jan 2002, vda wrote:
> 
> > I grepped kernel *.c (not *.h!) files for extern variable definitions.
> > Much to my surprize, I found ~1500 such defs.
> >
> > Isn't that bad C code style? What will happen if/when type of variable gets
> > changed? (int->long).
> 
> Yes; Int->long won't change anything on 32-bit machines and will break
> silently on 64-bit ones. The trick is finding appropriate places to put
> such definitions so that all the things that need them can include them
> without circular dependencies.
> 

Isn't there some way to get the linker to detect the differing
sizes?

-

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-02 21:43   ` Andrew Morton
@ 2002-01-02 22:07     ` Momchil Velikov
  2002-01-03  7:19       ` Andrew Morton
  0 siblings, 1 reply; 11+ messages in thread
From: Momchil Velikov @ 2002-01-02 22:07 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Oliver Xymoron, vda, linux-kernel

>>>>> "Andrew" == Andrew Morton <akpm@zip.com.au> writes:

Andrew> Oliver Xymoron wrote:
>> 
>> On Wed, 2 Jan 2002, vda wrote:
>> 
>> > I grepped kernel *.c (not *.h!) files for extern variable definitions.
>> > Much to my surprize, I found ~1500 such defs.
>> >
>> > Isn't that bad C code style? What will happen if/when type of variable gets
>> > changed? (int->long).
>> 
>> Yes; Int->long won't change anything on 32-bit machines and will break
>> silently on 64-bit ones. The trick is finding appropriate places to put
>> such definitions so that all the things that need them can include them
>> without circular dependencies.
>> 

Andrew> Isn't there some way to get the linker to detect the differing
Andrew> sizes?
`--warn-common'
     Warn when a common symbol is combined with another common symbol
     or with a symbol definition.  Unix linkers allow this somewhat
     sloppy practice, but linkers on some other operating systems do
     not.  This option allows you to find potential problems from
     combining global symbols.  Unfortunately, some C libraries use
     this practice, so you may get some warnings about symbols in the
     libraries as well as in your programs.

Regards,
-velco


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-02 22:07     ` Momchil Velikov
@ 2002-01-03  7:19       ` Andrew Morton
  2002-01-03  7:42         ` H . J . Lu
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Morton @ 2002-01-03  7:19 UTC (permalink / raw)
  To: Momchil Velikov; +Cc: Oliver Xymoron, vda, linux-kernel, H . J . Lu

Momchil Velikov wrote:
> 
> >>>>> "Andrew" == Andrew Morton <akpm@zip.com.au> writes:
> 
> Andrew> Oliver Xymoron wrote:
> >>
> >> On Wed, 2 Jan 2002, vda wrote:
> >>
> >> > I grepped kernel *.c (not *.h!) files for extern variable definitions.
> >> > Much to my surprize, I found ~1500 such defs.
> >> >
> >> > Isn't that bad C code style? What will happen if/when type of variable gets
> >> > changed? (int->long).
> >>
> >> Yes; Int->long won't change anything on 32-bit machines and will break
> >> silently on 64-bit ones. The trick is finding appropriate places to put
> >> such definitions so that all the things that need them can include them
> >> without circular dependencies.
> >>
> 
> Andrew> Isn't there some way to get the linker to detect the differing
> Andrew> sizes?
> `--warn-common'
>      Warn when a common symbol is combined with another common symbol
>      or with a symbol definition.  Unix linkers allow this somewhat
>      sloppy practice, but linkers on some other operating systems do
>      not.  This option allows you to find potential problems from
>      combining global symbols.  Unfortunately, some C libraries use
>      this practice, so you may get some warnings about symbols in the
>      libraries as well as in your programs.
> 

Alas, it doesn't quite work as we'd like:

akpm-1:/home/akpm> cat a.c
int a;

main()
{}
akpm-1:/home/akpm> cat b.c
extern char a;

int b()
{return a;}
akpm-1:/home/akpm> gcc -fno-common -Wl,--warn-common a.c b.c
akpm-1:/home/akpm> 

No warnings emitted.  If b.c doesn't use `extern' it will fail
to link because of -fno-common.

What we'd *like* to happen is for the linker to determine that
the `extern char' and the `int' declarations are a mismatch.
Maybe the object file doesn't have the size info for `extern'
variables.   The compiler emits it though.

We can actually get what we want by disabling `-fno-common' and enabling
`--warn-common', but that's rather awkward. 

Perhaps HJ can suggest a solution?

-

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-03  7:19       ` Andrew Morton
@ 2002-01-03  7:42         ` H . J . Lu
  2002-01-03  7:56           ` Andrew Morton
  0 siblings, 1 reply; 11+ messages in thread
From: H . J . Lu @ 2002-01-03  7:42 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Momchil Velikov, Oliver Xymoron, vda, linux-kernel

On Wed, Jan 02, 2002 at 11:19:29PM -0800, Andrew Morton wrote:
> 
> Alas, it doesn't quite work as we'd like:
> 
> akpm-1:/home/akpm> cat a.c
> int a;
> 
> main()
> {}
> akpm-1:/home/akpm> cat b.c
> extern char a;
> 
> int b()
> {return a;}
> akpm-1:/home/akpm> gcc -fno-common -Wl,--warn-common a.c b.c
> akpm-1:/home/akpm> 
> 
> No warnings emitted.  If b.c doesn't use `extern' it will fail
> to link because of -fno-common.
> 
> What we'd *like* to happen is for the linker to determine that
> the `extern char' and the `int' declarations are a mismatch.
> Maybe the object file doesn't have the size info for `extern'
> variables.   The compiler emits it though.
> 

Compile doesn't emit the size info for

extern char a;

One way to fix it is to remove

extern char a;

and put

extern int a;

in a header file which is included by everyone.


H.J.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-03  7:42         ` H . J . Lu
@ 2002-01-03  7:56           ` Andrew Morton
  2002-01-03  8:24             ` Keith Owens
  2002-01-03  9:57             ` Russell King
  0 siblings, 2 replies; 11+ messages in thread
From: Andrew Morton @ 2002-01-03  7:56 UTC (permalink / raw)
  To: H . J . Lu; +Cc: Momchil Velikov, Oliver Xymoron, vda, linux-kernel

"H . J . Lu" wrote:
> 
> ...
> Compile doesn't emit the size info for
> 
> extern char a;

You're right.  I goofed.
 
> One way to fix it is to remove
> 
> extern char a;
> 
> and put
> 
> extern int a;
> 
> in a header file which is included by everyone.
> 

Yup.  Problem is, we have about 1500 instances in the kernel :(

(Wouldn't it be nice if `int a;' generated a compiler error
if a declaration `extern int a;' was not in scope?)

Oh well.  Seems that disabling -fno-common and enabling
--warn-common is the only way to autodetect bugs such as this.

-

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-03  7:56           ` Andrew Morton
@ 2002-01-03  8:24             ` Keith Owens
  2002-01-03  9:57             ` Russell King
  1 sibling, 0 replies; 11+ messages in thread
From: Keith Owens @ 2002-01-03  8:24 UTC (permalink / raw)
  To: Andrew Morton; +Cc: H . J . Lu, Momchil Velikov, Oliver Xymoron, linux-kernel

On Wed, 02 Jan 2002 23:56:25 -0800, 
Andrew Morton <akpm@zip.com.au> wrote:
>Yup.  Problem is, we have about 1500 instances in the kernel :(

You can ignore the ~250 entries in *syms.c files.  EXPORT_SYMBOL only
needs to know if a symbol is a function or anything else, it does not
care about types at all.  You can define variables and functions with
invalid types in *syms.c without doing any damage.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files
  2002-01-03  7:56           ` Andrew Morton
  2002-01-03  8:24             ` Keith Owens
@ 2002-01-03  9:57             ` Russell King
  2002-01-04  0:28               ` Extern variables in *.c files (maintainers pls read this) vda
  1 sibling, 1 reply; 11+ messages in thread
From: Russell King @ 2002-01-03  9:57 UTC (permalink / raw)
  To: Andrew Morton
  Cc: H . J . Lu, Momchil Velikov, Oliver Xymoron, vda, linux-kernel

On Wed, Jan 02, 2002 at 11:56:25PM -0800, Andrew Morton wrote:
> Oh well.  Seems that disabling -fno-common and enabling
> --warn-common is the only way to autodetect bugs such as this.

You open another can of worms with variables in drivers that should be
static that aren't - you end up with no way to detect these without
-fno-common.

So, you have a choice:
1. Enable -fno-common
   - detect variables that should be marked static which aren't
   - don't detect size differences
2. Disable -fno-common
   - don't detect variables that should be marked static
   - detect size differences as long as the variables aren't marked extern

As soon as someone has int foo in one file, and extern char foo in another,
you've lost no matter which option you take.

The header file approach is the most reliable (and imho correct) method to
solve this problem.

-- 
Russell King (rmk@arm.linux.org.uk)                The developer of ARM Linux
             http://www.arm.linux.org.uk/personal/aboutme.html


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files (maintainers pls read this)
  2002-01-04  0:28               ` Extern variables in *.c files (maintainers pls read this) vda
@ 2002-01-03 23:14                 ` Olaf Dietsche
  0 siblings, 0 replies; 11+ messages in thread
From: Olaf Dietsche @ 2002-01-03 23:14 UTC (permalink / raw)
  To: vda; +Cc: linux-kernel

"vda@port.imtp.ilyichevsk.odessa.ua"  <vda@port.imtp.ilyichevsk.odessa.ua> writes:

> And this method is traditional for C. We have struct declarations and fn 
> propotypes in *.h, we should place extern vars there too. Always.

Agreed.

> If you are a kernel subsystem or driver maintainer, you may wish to check 
> whether *your* part of kernel has any extern variable defs. Just run this
> hunter script in top dir of kernel source:
> -----------------------
> #!/bin/sh
> 
> function do_grep() {
>     pattern="$1"
>     dir="$2"
>     shift;shift
>     
>     for i in $dir/$*; do
>         if ! test -d "$i"; then
>             if test -e "$i"; then
> 		grep -E "$pattern" "$i" /dev/null
> 	    fi
>         fi
>     done
>     for i in $dir/*; do
>         if test -d "$i"; then
> 	    do_grep "$pattern" "$i" $*
> 	fi
>     done
> }
> 
> do_grep 'extern [^()]*;' . "*.c" 2>&1 | tee ../extern.log
> ---------------------------------

FWIW, I suppose you meant:
$ find . -name '*.c' | xargs grep -E 'extern [^()]*;' 2>&1 | tee extern.log

Regards, Olaf.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Extern variables in *.c files (maintainers pls read this)
  2002-01-03  9:57             ` Russell King
@ 2002-01-04  0:28               ` vda
  2002-01-03 23:14                 ` Olaf Dietsche
  0 siblings, 1 reply; 11+ messages in thread
From: vda @ 2002-01-04  0:28 UTC (permalink / raw)
  To: H.J.Lu, Momchil Velikov, Oliver Xymoron, Russell King,
	Andrew Morton
  Cc: linux-kernel

> So, you have a choice:
> 1. Enable -fno-common
>    - detect variables that should be marked static which aren't
>    - don't detect size differences
> 2. Disable -fno-common
>    - don't detect variables that should be marked static
>    - detect size differences as long as the variables aren't marked extern
>
> As soon as someone has int foo in one file, and extern char foo in another,
> you've lost no matter which option you take.
>
> The header file approach is the most reliable (and imho correct) method to
> solve this problem.

And this method is traditional for C. We have struct declarations and fn 
propotypes in *.h, we should place extern vars there too. Always.

If you are a kernel subsystem or driver maintainer, you may wish to check 
whether *your* part of kernel has any extern variable defs. Just run this
hunter script in top dir of kernel source:
-----------------------
#!/bin/sh

function do_grep() {
    pattern="$1"
    dir="$2"
    shift;shift
    
    for i in $dir/$*; do
        if ! test -d "$i"; then
            if test -e "$i"; then
		grep -E "$pattern" "$i" /dev/null
	    fi
        fi
    done
    for i in $dir/*; do
        if test -d "$i"; then
	    do_grep "$pattern" "$i" $*
	fi
    done
}

do_grep 'extern [^()]*;' . "*.c" 2>&1 | tee ../extern.log
---------------------------------

Output is not attached here, it's too big: ~100 KB, ~1500 lines for 2.5.1-pre8
--
vda

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2002-01-03 23:15 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-01-02 18:18 Extern variables in *.c files vda
2002-01-02 19:24 ` Oliver Xymoron
2002-01-02 21:43   ` Andrew Morton
2002-01-02 22:07     ` Momchil Velikov
2002-01-03  7:19       ` Andrew Morton
2002-01-03  7:42         ` H . J . Lu
2002-01-03  7:56           ` Andrew Morton
2002-01-03  8:24             ` Keith Owens
2002-01-03  9:57             ` Russell King
2002-01-04  0:28               ` Extern variables in *.c files (maintainers pls read this) vda
2002-01-03 23:14                 ` Olaf Dietsche

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox