public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* macro conflict
@ 2001-08-23 19:03 J. Imlay
  2001-08-23 19:21 ` Alan Cox
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: J. Imlay @ 2001-08-23 19:03 UTC (permalink / raw)
  To: linux-kernel

IN getting the AFS kernel modules to compile under linux I dicovered that
the were useing the standard min(x,y) macro that whould evaluate which one
is smaller. However sometime between 2.4.6 and 2.4.9 a new macro was added
to linux/kernel.h

this one:

#define min(type,x,y) \
        ({ type __x = (x), __y = (y); __x < __y ? __x: __y; })

the old one is

#define min(x,y) ( (x)<(y)?(x):(y) )

has been around a lot longer and is in lots of header files.

The problem here with AFS is that it needs the old definition but the old
definition is being over written by the new one... you guys should know
all this. But I am just saying that I really think the new macro
min(type,x,y) should get a new name. like type_min or something.

Thanks,

Josie Imlay


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

* Re: macro conflict
  2001-08-23 19:03 macro conflict J. Imlay
@ 2001-08-23 19:21 ` Alan Cox
  2001-08-23 19:34 ` Tim Walberg
  2001-08-24 13:03 ` David Woodhouse
  2 siblings, 0 replies; 22+ messages in thread
From: Alan Cox @ 2001-08-23 19:21 UTC (permalink / raw)
  To: J. Imlay; +Cc: linux-kernel

> The problem here with AFS is that it needs the old definition but the old
> definition is being over written by the new one... you guys should know
> all this. But I am just saying that I really think the new macro
> min(type,x,y) should get a new name. like type_min or something.

Yep. Thats one of the reasons I've not yet moved to 2.4.9 derived trees
for -ac. Its going to require I schedule some time to fix up every single
bogus min/max change in Linus tree

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

* Re: macro conflict
  2001-08-23 19:03 macro conflict J. Imlay
  2001-08-23 19:21 ` Alan Cox
@ 2001-08-23 19:34 ` Tim Walberg
  2001-08-23 20:01   ` Alan Cox
  2001-08-23 20:02   ` raybry
  2001-08-24 13:03 ` David Woodhouse
  2 siblings, 2 replies; 22+ messages in thread
From: Tim Walberg @ 2001-08-23 19:34 UTC (permalink / raw)
  To: J. Imlay; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2441 bytes --]

There has already been **much** discussion about this, but I think
that the bottom line is that the new version is safer and more
robust than the old version, and thus is not likely to be changed
back.

Consider what happens if someone writes min(++x,y) - the old
version expands to (without some of the extra parens):

	++x < y ? ++x : y

which will increment x twice if the condition ++x < y is true.
There's all kinds of nasty side effects possible with the old
version, including having x > y at the end of the statement, which
definitely violates the semantics of min().

The new version avoids these side effects by only evaluating
the given arguments once (assigning them to temp variables,
which will be optimized away in almost all cases anyway), but
in order to do that, the macro needs to know the variable type,
hence the additional argument. In C++, this can be done using
typename or templates, but the kernel's not written in C++
for a number of very good reasons.

Bottom line, I think the new version of min() and friends is
here to stay and is definitely a positive move. One of the down
sides to that is that a lot of people have a lot of cleaning
up to do.

			tw

On 08/23/2001 12:03 -0700, J. Imlay wrote:
>>	IN getting the AFS kernel modules to compile under linux I dicovered that
>>	the were useing the standard min(x,y) macro that whould evaluate which one
>>	is smaller. However sometime between 2.4.6 and 2.4.9 a new macro was added
>>	to linux/kernel.h
>>	
>>	this one:
>>	
>>	#define min(type,x,y) \
>>	        ({ type __x = (x), __y = (y); __x < __y ? __x: __y; })
>>	
>>	the old one is
>>	
>>	#define min(x,y) ( (x)<(y)?(x):(y) )
>>	
>>	has been around a lot longer and is in lots of header files.
>>	
>>	The problem here with AFS is that it needs the old definition but the old
>>	definition is being over written by the new one... you guys should know
>>	all this. But I am just saying that I really think the new macro
>>	min(type,x,y) should get a new name. like type_min or something.
>>	
>>	Thanks,
>>	
>>	Josie Imlay
>>	
>>	-
>>	To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>>	the body of a message to majordomo@vger.kernel.org
>>	More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>	Please read the FAQ at  http://www.tux.org/lkml/
End of included message



-- 
twalberg@mindspring.com

[-- Attachment #2: Type: application/pgp-signature, Size: 175 bytes --]

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

* Re: macro conflict
  2001-08-23 19:34 ` Tim Walberg
@ 2001-08-23 20:01   ` Alan Cox
  2001-08-23 20:02   ` raybry
  1 sibling, 0 replies; 22+ messages in thread
From: Alan Cox @ 2001-08-23 20:01 UTC (permalink / raw)
  To: twalberg; +Cc: J. Imlay, linux-kernel

> Consider what happens if someone writes min(++x,y) - the old
> version expands to (without some of the extra parens):
> 
> 	++x < y ? ++x : y

That has nothing to do with it

a) nobody does it and its a known property
b) that was perfectly fixable anyway

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

* Re: macro conflict
  2001-08-23 19:34 ` Tim Walberg
  2001-08-23 20:01   ` Alan Cox
@ 2001-08-23 20:02   ` raybry
  2001-08-23 20:16     ` Magnus Naeslund(f)
  2001-08-24  1:42     ` Camiel Vanderhoeven
  1 sibling, 2 replies; 22+ messages in thread
From: raybry @ 2001-08-23 20:02 UTC (permalink / raw)
  To: Tim Walberg, linux-kernel

Without digging through the archives to see if this has already
been suggested (if so, I apologize), why can't the following be done:

min(x,y) = ({typeof((x)) __x=(x), __y=(y); (__x < __y) ? __x : __y})

That gets you the correct "evaluate the args once" semantics and gives
you control over typing (the comparison is done in the type of the 
first argument) and we don't have to change a zillion drivers.

(typeof() is a gcc extension.)

Tim Walberg wrote:
> 
> There has already been **much** discussion about this, but I think
> that the bottom line is that the new version is safer and more
> robust than the old version, and thus is not likely to be changed
> back.
> 
> Consider what happens if someone writes min(++x,y) - the old
> version expands to (without some of the extra parens):
> 
>         ++x < y ? ++x : y
> 
> which will increment x twice if the condition ++x < y is true.
> There's all kinds of nasty side effects possible with the old
> version, including having x > y at the end of the statement, which
> definitely violates the semantics of min().
> 
> The new version avoids these side effects by only evaluating
> the given arguments once (assigning them to temp variables,
> which will be optimized away in almost all cases anyway), but
> in order to do that, the macro needs to know the variable type,
> hence the additional argument. In C++, this can be done using
> typename or templates, but the kernel's not written in C++
> for a number of very good reasons.
> 
> Bottom line, I think the new version of min() and friends is
> here to stay and is definitely a positive move. One of the down
> sides to that is that a lot of people have a lot of cleaning
> up to do.
> 
>                         tw
> 
> On 08/23/2001 12:03 -0700, J. Imlay wrote:
> >>      IN getting the AFS kernel modules to compile under linux I
> dicovered that
> >>      the were useing the standard min(x,y) macro that whould evaluate
> which one
> >>      is smaller. However sometime between 2.4.6 and 2.4.9 a new macro
> was added
> >>      to linux/kernel.h
> >>
> >>      this one:
> >>
> >>      #define min(type,x,y) \
> >>              ({ type __x = (x), __y = (y); __x < __y ? __x: __y; })
> >>
> >>      the old one is
> >>
> >>      #define min(x,y) ( (x)<(y)?(x):(y) )
> >>
> >>      has been around a lot longer and is in lots of header files.
> >>
> >>      The problem here with AFS is that it needs the old definition
> but the old
> >>      definition is being over written by the new one... you guys
> should know
> >>      all this. But I am just saying that I really think the new macro
> >>      min(type,x,y) should get a new name. like type_min or something.
> >>
> >>      Thanks,
> >>
> >>      Josie Imlay
> >>
> >>      -
> >>      To unsubscribe from this list: send the line "unsubscribe
> linux-kernel" in
> >>      the body of a message to majordomo@vger.kernel.org
> >>      More majordomo info at
> http://vger.kernel.org/majordomo-info.html
> >>      Please read the FAQ at  http://www.tux.org/lkml/
> End of included message
> 
> --
> twalberg@mindspring.com

-- 
----------------------------------------------------------- 
  Ray Bryant,  Linux Performance Analyst, Times N Systems
   1908 Kramer Lane, Bldg. B, Suite P, Austin, TX 78758
              512-977-5366, raybry@timesn.com
-----------------------------------------------------------

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

* Re: macro conflict
  2001-08-23 20:02   ` raybry
@ 2001-08-23 20:16     ` Magnus Naeslund(f)
  2001-08-23 20:27       ` Alan Cox
                         ` (2 more replies)
  2001-08-24  1:42     ` Camiel Vanderhoeven
  1 sibling, 3 replies; 22+ messages in thread
From: Magnus Naeslund(f) @ 2001-08-23 20:16 UTC (permalink / raw)
  To: raybry, Tim Walberg, linux-kernel

From: <raybry@timesn.com>
> Without digging through the archives to see if this has already
> been suggested (if so, I apologize), why can't the following be done:
>
> min(x,y) = ({typeof((x)) __x=(x), __y=(y); (__x < __y) ? __x : __y})
>
> That gets you the correct "evaluate the args once" semantics and gives
> you control over typing (the comparison is done in the type of the
> first argument) and we don't have to change a zillion drivers.
>
> (typeof() is a gcc extension.)
>

But then again, how do you know it's the type of x we want, maybe we want
type of y, that is and signed char (not an int like x).
Talk about hidden buffer overflow stuff :)

Magnus

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 Programmer/Networker [|] Magnus Naeslund
 PGP Key: http://www.genline.nu/mag_pgp.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-




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

* Re: macro conflict
  2001-08-23 20:16     ` Magnus Naeslund(f)
@ 2001-08-23 20:27       ` Alan Cox
  2001-08-23 20:29         ` Magnus Naeslund(f)
  2001-08-23 23:18       ` Andrew Cannon
  2001-08-23 23:35       ` Roman Zippel
  2 siblings, 1 reply; 22+ messages in thread
From: Alan Cox @ 2001-08-23 20:27 UTC (permalink / raw)
  To: "Magnus Naeslund(f)"; +Cc: raybry, Tim Walberg, linux-kernel

> But then again, how do you know it's the type of x we want, maybe we want
> type of y, that is and signed char (not an int like x).
> Talk about hidden buffer overflow stuff :)

This is one of the big problems with min and max, you get deeply suprising
and unpleasant results if you don't consider sign propogation, sizes and
overruns carefully. In C there are some great evils in that area, and its
one reason a lot of people prefer to write such code explicitly.

Alan

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

* Re: macro conflict
  2001-08-23 20:27       ` Alan Cox
@ 2001-08-23 20:29         ` Magnus Naeslund(f)
  0 siblings, 0 replies; 22+ messages in thread
From: Magnus Naeslund(f) @ 2001-08-23 20:29 UTC (permalink / raw)
  To: Alan Cox; +Cc: raybry, Tim Walberg, linux-kernel

From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
> This is one of the big problems with min and max, you get deeply suprising
> and unpleasant results if you don't consider sign propogation, sizes and
> overruns carefully. In C there are some great evils in that area, and its
> one reason a lot of people prefer to write such code explicitly.
>


Yeah, been there, bitten by that. :)

Magnus

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 Programmer/Networker [|] Magnus Naeslund
 PGP Key: http://www.genline.nu/mag_pgp.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-



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

* Re: macro conflict
  2001-08-23 20:16     ` Magnus Naeslund(f)
  2001-08-23 20:27       ` Alan Cox
@ 2001-08-23 23:18       ` Andrew Cannon
  2001-08-23 23:37         ` Magnus Naeslund(f)
  2001-08-23 23:35       ` Roman Zippel
  2 siblings, 1 reply; 22+ messages in thread
From: Andrew Cannon @ 2001-08-23 23:18 UTC (permalink / raw)
  To: Magnus Naeslund(f); +Cc: linux-kernel



"Magnus Naeslund(f)" wrote:
> 
> From: <raybry@timesn.com>
> > Without digging through the archives to see if this has already
> > been suggested (if so, I apologize), why can't the following be done:
> >
> > min(x,y) = ({typeof((x)) __x=(x), __y=(y); (__x < __y) ? __x : __y})
> >
> > That gets you the correct "evaluate the args once" semantics and gives
> > you control over typing (the comparison is done in the type of the
> > first argument) and we don't have to change a zillion drivers.
> >
> > (typeof() is a gcc extension.)
> >
> 
> But then again, how do you know it's the type of x we want, maybe we want
> type of y, that is and signed char (not an int like x).
> Talk about hidden buffer overflow stuff :)


What about this then:

#define min(x,y) ({typeof(x) __x=(x); typeof(y) __y=(y); (__x < __y) ?
__x : __y})

This is guaranteed to work the same as the old min/max in all cases but
without side effects. You can still force the comparison to be done with
a certain type by casting the arguments first:

#define typed_min(type, x, y) (min((type)(x), (type)(y)))

...although, if the type used for the comparison is so critical you
maybe shouldn't be hiding it in a macro anyway.

Andrew

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

* Re: macro conflict
  2001-08-23 20:16     ` Magnus Naeslund(f)
  2001-08-23 20:27       ` Alan Cox
  2001-08-23 23:18       ` Andrew Cannon
@ 2001-08-23 23:35       ` Roman Zippel
  2 siblings, 0 replies; 22+ messages in thread
From: Roman Zippel @ 2001-08-23 23:35 UTC (permalink / raw)
  To: Magnus Naeslund(f); +Cc: raybry, Tim Walberg, linux-kernel

Hi,

"Magnus Naeslund(f)" wrote:

> > min(x,y) = ({typeof((x)) __x=(x), __y=(y); (__x < __y) ? __x : __y})
> >
> > That gets you the correct "evaluate the args once" semantics and gives
> > you control over typing (the comparison is done in the type of the
> > first argument) and we don't have to change a zillion drivers.
> >
> > (typeof() is a gcc extension.)

({...}) is also gcc extension.

> But then again, how do you know it's the type of x we want, maybe we want
> type of y, that is and signed char (not an int like x).
> Talk about hidden buffer overflow stuff :)

That's the reason I'm using this macro for affs:

#define MIN(a, b) ({            \
        typeof(a) _a = (a);     \
        typeof(b) _b = (b);     \
        _a < _b ? _a : _b;      \
})

I need a very good reason to use something else, so far I'm unconvinced.

bye, Roman

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

* Re: macro conflict
  2001-08-23 23:18       ` Andrew Cannon
@ 2001-08-23 23:37         ` Magnus Naeslund(f)
  0 siblings, 0 replies; 22+ messages in thread
From: Magnus Naeslund(f) @ 2001-08-23 23:37 UTC (permalink / raw)
  To: Andrew Cannon; +Cc: linux-kernel

From: "Andrew Cannon" <ajc@gmx.net>
>
> What about this then:
>
> #define min(x,y) ({typeof(x) __x=(x); typeof(y) __y=(y); (__x < __y) ?
> __x : __y})
>
> This is guaranteed to work the same as the old min/max in all cases but
> without side effects. You can still force the comparison to be done with
> a certain type by casting the arguments first:
>
[snip]

Well it's closer but not really what i want.
The min/max_type is maybe the way to go, but the above can still bit you if
the types differ. Consider max().

char lut[256];
int   c1 = 256+rand()%256;
char  c2 = rand()%256;
char dest = lut[max(c2,c1)];

Won't c1 still be returned untruncated?

Ofcourse one will use another construct for these kinds of checks, but maybe
your brain collapses just for a second and think that this will return a
char.

OK ok bad example, but maybe you see that i have a point here somewhere
(under my chair? :) ).

Magnus

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 Programmer/Networker [|] Magnus Naeslund
 PGP Key: http://www.genline.nu/mag_pgp.txt
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-



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

* RE: macro conflict
  2001-08-23 20:02   ` raybry
  2001-08-23 20:16     ` Magnus Naeslund(f)
@ 2001-08-24  1:42     ` Camiel Vanderhoeven
  1 sibling, 0 replies; 22+ messages in thread
From: Camiel Vanderhoeven @ 2001-08-24  1:42 UTC (permalink / raw)
  To: raybry, linux-kernel

A small detail; you min(x,y) fails if x and y are pointers.

Example: min(char * a, char * b) would evaluate to
char * __x = (a), __y = (b); etc...

Here __x is a pointer and __y is a char. A better solution (at least the
one that has my vote so far) would besomething like this:

typeof(x) __x=(x); typeof(y) __y=(y); (__x < __y) ? __x : __y

Camiel.

> Without digging through the archives to see if this has already
> been suggested (if so, I apologize), why can't the following be done:
> 
> min(x,y) = ({typeof((x)) __x=(x), __y=(y); (__x < __y) ? __x : __y})
> 
> That gets you the correct "evaluate the args once" semantics and gives
> you control over typing (the comparison is done in the type of the
> first argument) and we don't have to change a zillion drivers.
> 
> (typeof() is a gcc extension.)

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

* Re: macro conflict
  2001-08-23 19:03 macro conflict J. Imlay
  2001-08-23 19:21 ` Alan Cox
  2001-08-23 19:34 ` Tim Walberg
@ 2001-08-24 13:03 ` David Woodhouse
  2001-08-24 13:15   ` Keith Owens
                     ` (3 more replies)
  2 siblings, 4 replies; 22+ messages in thread
From: David Woodhouse @ 2001-08-24 13:03 UTC (permalink / raw)
  To: Tim Walberg; +Cc: J. Imlay, linux-kernel


twalberg@mindspring.com said:
> There has already been **much** discussion about this, but I think
> that the bottom line is that the new version is safer and more robust
> than the old version, and thus is not likely to be changed back. 

That's a completely separate issue. You can fix it while keeping sane 
semantics for min() and max().

#define real_min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; })

#define min(x,y) ({ if strcmp(STRINGIFY(typeof(x)), STRINGIFY(typeof(y))) BUG(); realmin(x,y) }) 

/me wonders if gcc would manage to optimise that.
--
dwmw2



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

* Re: macro conflict
  2001-08-24 13:03 ` David Woodhouse
@ 2001-08-24 13:15   ` Keith Owens
  2001-08-24 13:17     ` David Woodhouse
  2001-08-24 13:34   ` Richard B. Johnson
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 22+ messages in thread
From: Keith Owens @ 2001-08-24 13:15 UTC (permalink / raw)
  To: David Woodhouse; +Cc: linux-kernel

On Fri, 24 Aug 2001 14:03:34 +0100, 
David Woodhouse <dwmw2@infradead.org> wrote:
>#define min(x,y) ({ if strcmp(STRINGIFY(typeof(x)), STRINGIFY(typeof(y))) BUG(); realmin(x,y) }) 

Did you try that?  Firstly typeof() is only defined in declaration
context, it gets an error when used in an expression.  Secondly
typeof() is not expanded by cpp so the stringify tricks do not work.
typeof(x) is handled by cc, not cpp.


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

* Re: macro conflict
  2001-08-24 13:15   ` Keith Owens
@ 2001-08-24 13:17     ` David Woodhouse
  2001-08-24 14:20       ` Bill Pringlemeir
  0 siblings, 1 reply; 22+ messages in thread
From: David Woodhouse @ 2001-08-24 13:17 UTC (permalink / raw)
  To: Keith Owens; +Cc: linux-kernel


kaos@ocs.com.au said:
>  Did you try that?  Firstly typeof() is only defined in declaration
> context, it gets an error when used in an expression.  Secondly
> typeof() is not expanded by cpp so the stringify tricks do not work.
> typeof(x) is handled by cc, not cpp. 

No. It's far too silly for me to have actually tried it :)

--
dwmw2



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

* Re: macro conflict
  2001-08-24 13:03 ` David Woodhouse
  2001-08-24 13:15   ` Keith Owens
@ 2001-08-24 13:34   ` Richard B. Johnson
  2001-08-24 18:20     ` David Wagner
  2001-08-24 17:25   ` Alex Bligh - linux-kernel
  2001-08-24 17:34   ` David Woodhouse
  3 siblings, 1 reply; 22+ messages in thread
From: Richard B. Johnson @ 2001-08-24 13:34 UTC (permalink / raw)
  To: David Woodhouse; +Cc: Tim Walberg, J. Imlay, linux-kernel

On Fri, 24 Aug 2001, David Woodhouse wrote:

> 
> twalberg@mindspring.com said:
> > There has already been **much** discussion about this, but I think
> > that the bottom line is that the new version is safer and more robust
> > than the old version, and thus is not likely to be changed back. 
> 
> That's a completely separate issue. You can fix it while keeping sane 
> semantics for min() and max().
> 
> #define real_min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; })
> 
> #define min(x,y) ({ if strcmp(STRINGIFY(typeof(x)), STRINGIFY(typeof(y))) BUG(); realmin(x,y) }) 
> 
> /me wonders if gcc would manage to optimise that.
> --
> dwmw2
> 

Looking through the code, min() is most always used to find some value
that will not overflow some buffer, i.e.,

    len = min(user_request_len, sizeof(buffer));

The problem is that sizeof() returns an unsigned int (size_t), and the
user request length may be an integer. Everything works fine until
you get to lengths with the high bit set. Then, you are in trouble.

In this case, you could have a 'min()' that does:

#define min(a,b) (unsigned long)(a) < (unsigned long)(b) ? (a) : (b)

... where the comparison (only) is made unsigned, and you keep the
original values. This should work, perhaps in all the current uses.
However, min() is not the mathematical min() anymore. That's fine,
but it probably should not be called min() unless it is truly a min()
function.

So, I suggest that instead of using some macro in a header, if you
need min() you make one in your code called MIN(). Problem solved.
Your macro will do exactly what you want it to do. If It's broken,
you get to fix it (or keep the pieces).


Cheers,
Dick Johnson

Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).

    I was going to compile a list of innovations that could be
    attributed to Microsoft. Once I realized that Ctrl-Alt-Del
    was handled in the BIOS, I found that there aren't any.



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

* Re: macro conflict
  2001-08-24 13:17     ` David Woodhouse
@ 2001-08-24 14:20       ` Bill Pringlemeir
  2001-08-24 21:17         ` Roman Zippel
  0 siblings, 1 reply; 22+ messages in thread
From: Bill Pringlemeir @ 2001-08-24 14:20 UTC (permalink / raw)
  To: David Woodhouse; +Cc: Keith Owens, linux-kernel


>>>> kaos@ocs.com.au said:

 >> Did you try that?  Firstly typeof() is only defined in declaration
 >> context, it gets an error when used in an expression.  Secondly
 >> typeof() is not expanded by cpp so the stringify tricks do not
 >> work.  typeof(x) is handled by cc, not cpp.

>>>>> "David" == David Woodhouse <dwmw2@infradead.org> writes:

 David> No. It's far too silly for me to have actually tried it :)

David, you wild and crazy guy!  How crazy is this,

#define real_min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; })
#define min(x,y) ({extern void BUG(void); typeof(x) _x = 0; typeof(y) _y = 0;  \
        if (sizeof(typeof(x)) != sizeof(typeof(y)) ||   \
            (_x-1 > 0 && _y-1 < 0) || (_x-1<0 && _y-1>0)) \
                            BUG();                      \
        real_min(x,y); }) 

int main(int argc, char *argv[])
{
    int ix,iy;
    unsigned int ux,uy;
    long lx,ly;
    unsigned long Ux,Uy;

    ux = min(ix,uy);
    return 0;
}

sh> gcc -Wall test.c -O2 test

This is a little slimmy as the sizeof will evaluate the to same thing
on some architectures for long/int or short/int.  Even worse, it won't
handle pointers.  The macro is `physically correct' if a short/int are
the same.  Actually, you would probably want to cast up to which ever
is the bigger of the types to fully handle the precision.  Maybe the
sizeof() test isn't even needed due to promotion.  Just the signs are
important (afaik) and a test for pointer and integral mixing which I
cann't think of.  Maybe some clever use of arrays or "+ *x" or
something.

fwiw,
Bill Pringlemeir.





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

* Re: macro conflict
  2001-08-24 13:03 ` David Woodhouse
  2001-08-24 13:15   ` Keith Owens
  2001-08-24 13:34   ` Richard B. Johnson
@ 2001-08-24 17:25   ` Alex Bligh - linux-kernel
  2001-08-24 17:34   ` David Woodhouse
  3 siblings, 0 replies; 22+ messages in thread
From: Alex Bligh - linux-kernel @ 2001-08-24 17:25 UTC (permalink / raw)
  To: David Woodhouse, Tim Walberg
  Cc: J. Imlay, linux-kernel, Alex Bligh - linux-kernel

># define real_min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y);
># (_x>_y)?_y:_x; })
>
># define min(x,y) ({ if strcmp(STRINGIFY(typeof(x)), STRINGIFY(typeof(y)))
># BUG(); realmin(x,y) })
>
> /me wonders if gcc would manage to optimise that.

Will this work with things like

void test(unsigned int foo, char bar)
{
	printf ("%d %d\n", min(foo, 10), min (bar, 20));
}

Surely one of those must BUG().

--
Alex Bligh

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

* Re: macro conflict
  2001-08-24 13:03 ` David Woodhouse
                     ` (2 preceding siblings ...)
  2001-08-24 17:25   ` Alex Bligh - linux-kernel
@ 2001-08-24 17:34   ` David Woodhouse
  2001-08-24 18:12     ` Bill Pringlemeir
  3 siblings, 1 reply; 22+ messages in thread
From: David Woodhouse @ 2001-08-24 17:34 UTC (permalink / raw)
  To: Alex Bligh - linux-kernel; +Cc: Tim Walberg, J. Imlay, linux-kernel


linux-kernel@alex.org.uk said:
>  Will this work with things like
> void test(unsigned int foo, char bar) {
> 	printf ("%d %d\n", min(foo, 10), min (bar, 20)); }
> Surely one of those must BUG().

Well, ideally both of them would BUG() and the user would have to explicitly
cast one (or both) of the arguments so the types match. But as Keith 
pointed out, it won't work.

--
dwmw2



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

* Re: macro conflict
  2001-08-24 17:34   ` David Woodhouse
@ 2001-08-24 18:12     ` Bill Pringlemeir
  0 siblings, 0 replies; 22+ messages in thread
From: Bill Pringlemeir @ 2001-08-24 18:12 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Alex Bligh - linux-kernel, Tim Walberg, J. Imlay, linux-kernel

>>>>> "David" == David Woodhouse <dwmw2@infradead.org> writes:

> printf ("%d %d\n", min(foo, 10), min (bar, 20)); }

 David> Well, ideally both of them would BUG() and the user would have
 David> to explicitly cast one (or both) of the arguments so the types
 David> match. But as Keith pointed out, it won't work.

Why would both BUG? 20 is a signed integer and bar _could be_ a signed
char.  This is fine.  As a matter of fact, both constants are positive
and fit in the range so I don't really think this is a bug in either
case.  I guess the constants should be written as 10U and 20U.  There
are other problems as the code without a specifically type char will
have bugs on the ARM (and others with different sign default).  I
don't think that the casting handles this well either.

I did a little more beautification.  Gcc does warn if you compare a
pointer to an integral type.  Do you need more?  The bug_paste macro
would pollute the name-space, but it is nice to see where things go
wrong.

fwiw,
Bill Pringlemeir.

[test.c]
#define bug_paste_chain(a,b) a##b
#define bug_paste(a) bug_paste_chain(BUG_AT_LINE_,a)
#define min(x,y)                                       \
                                                       \
  ({extern void bug_paste(__LINE__) (void);            \
    typeof(x) _x = 0; typeof(y) _y = 0;                \
    if ((_x-1>0 && _y-1<0) || (_x-1<0 && _y-1>0))      \
            bug_paste(__LINE__)();                     \
        _x = (x), _y = (y); (_x>_y)?_y:_x;             \
   }) 

#include <stdio.h>
int main(int argc, char *argv[])
{
      signed char  cx = 1, cy = 2;
      signed short sx = 1, sy = 2;
      signed int   ix = 1, iy = 2;
      signed long  lx = 1, ly = 2;
    unsigned char  Cx = 1, Cy = 2;
    unsigned short Sx = 1, Sy = 2;
    unsigned int   Ix = 1, Iy = 2;
    unsigned long  Lx = 1, Ly = 2;

    cx = min(cx,cy);    Cx = min(Cy,Cx);    sx = min(sx,sy);
    Sx = min(Sx,Sy);    ix = min(iy,ix);    Ix = min(Iy,Ix);
    lx = min(ly,ly);    Lx = min(Lx,Ly);

    /* No warning. */
/*  Lx = (typeof(Lx))min(Lx,&Ly); */

    printf("%d %d %hd %hd %d %d %ld %ld\n", cx, Cx,
           sx,Sx,ix,Ix,lx,Lx);

    cx = -1;    Cx = 0;
    cx = min(cx,cy);    sx = min(cx,sy);
    ix = min(cx,ix);    lx = min(cx,ly);
    Cx = min(Cx,Cx);    Sx = min(Cx,Sy);
    Ix = min(Ly,Ix);    Lx = min(Ix,Ly);

    /* correctly gives warning! Promotion to int before compare. */
/*  Ix = min(Cy,Ix);    Lx = min(Cx,Ly); */

    printf("%d %d %hd %hd %d %d %ld %ld\n", cx, Cx,
           sx,Sx,ix,Ix,lx,Lx);
    
/* BUG? printf ("%d\n", min(Iy, 10)); */
    printf ("%d\n", min(cx, 20));

    return 0;
}



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

* Re: macro conflict
  2001-08-24 13:34   ` Richard B. Johnson
@ 2001-08-24 18:20     ` David Wagner
  0 siblings, 0 replies; 22+ messages in thread
From: David Wagner @ 2001-08-24 18:20 UTC (permalink / raw)
  To: linux-kernel

Richard B. Johnson wrote:
>Looking through the code, min() is most always used to find some value
>that will not overflow some buffer, i.e.,
>
>    len = min(user_request_len, sizeof(buffer));
>
>The problem is that sizeof() returns an unsigned int (size_t), and the
>user request length may be an integer. Everything works fine until
>you get to lengths with the high bit set. Then, you are in trouble.
>
>In this case, you could have a 'min()' that does:
>
>#define min(a,b) (unsigned long)(a) < (unsigned long)(b) ? (a) : (b)
>
>... where the comparison (only) is made unsigned, and you keep the
>original values. This should work, perhaps in all the current uses.

Just a small warning:  If anyone writes something like
    int len = min(user_request_len, sizeof(buffer));
    if (user_request_len > len)
        goto fail;
    memcpy(dst, user_src, len);
they can get into trouble even with your min() macro.
Ok, maybe this is crazy code that noone in their right
mind would ever write.

This is not intended as a criticism -- your approach may be
sufficient for existing code -- but it is something to watch
out for.

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

* Re: macro conflict
  2001-08-24 14:20       ` Bill Pringlemeir
@ 2001-08-24 21:17         ` Roman Zippel
  0 siblings, 0 replies; 22+ messages in thread
From: Roman Zippel @ 2001-08-24 21:17 UTC (permalink / raw)
  To: Bill Pringlemeir; +Cc: David Woodhouse, Keith Owens, linux-kernel

Hi,

> sizeof() test isn't even needed due to promotion.  Just the signs are
> important (afaik) and a test for pointer and integral mixing which I
> cann't think of.  Maybe some clever use of arrays or "+ *x" or
> something.

Try '-W' or '-Wsign-compare'. pointer/integer compare already results in
a warning without any option.

bye, Roman

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

end of thread, other threads:[~2001-08-24 21:18 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-08-23 19:03 macro conflict J. Imlay
2001-08-23 19:21 ` Alan Cox
2001-08-23 19:34 ` Tim Walberg
2001-08-23 20:01   ` Alan Cox
2001-08-23 20:02   ` raybry
2001-08-23 20:16     ` Magnus Naeslund(f)
2001-08-23 20:27       ` Alan Cox
2001-08-23 20:29         ` Magnus Naeslund(f)
2001-08-23 23:18       ` Andrew Cannon
2001-08-23 23:37         ` Magnus Naeslund(f)
2001-08-23 23:35       ` Roman Zippel
2001-08-24  1:42     ` Camiel Vanderhoeven
2001-08-24 13:03 ` David Woodhouse
2001-08-24 13:15   ` Keith Owens
2001-08-24 13:17     ` David Woodhouse
2001-08-24 14:20       ` Bill Pringlemeir
2001-08-24 21:17         ` Roman Zippel
2001-08-24 13:34   ` Richard B. Johnson
2001-08-24 18:20     ` David Wagner
2001-08-24 17:25   ` Alex Bligh - linux-kernel
2001-08-24 17:34   ` David Woodhouse
2001-08-24 18:12     ` Bill Pringlemeir

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