* [IDEA+RFC] Possible solution for min()/max() war @ 2001-08-24 22:42 Brad Chapman 2001-08-24 23:21 ` Ben LaHaise 0 siblings, 1 reply; 95+ messages in thread From: Brad Chapman @ 2001-08-24 22:42 UTC (permalink / raw) To: linux-kernel Everyone, At the risk of igniting another long-drawn-out flamewar over the min()/max() macros, I have an idea. There is a section in the config dialogs labeled "Kernel hacking." Under it there is the SysRQ option. Why don't we put an entry under that dialog and label it "Use new min()/max() macros" and make it a y/n field. Then we can add dozens of warnings to the help dialog about it, and allow the user/hacker to select the macro they want. In any code which uses the macros, you can simply do this: #include <linux/config.h> .... #ifdef CONFIG_USE_NEW_MINMAX minimum = min(int, number[0], number[1]); #else minimum = min(number[0], number[1]); #endif This way, some hackers can use the two-arg min()/max() inside an #ifdef block, other hackers can use the three-arg min()/max() inside an #ifdef block, and people who don't care can select either. Comments, flames, suggestions, anyone? If the output is good, I'll publish a patch which will add the Config.in option and default it to CONFIG_USE_NEW_MINMAX=y, since that was the decree of the Great Penguin Overlord ;) Brad ===== Brad Chapman Permanent e-mail: kakadu_croc@yahoo.com Current e-mail: kakadu@adelphia.net Alternate e-mail: kakadu@netscape.net __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-24 22:42 [IDEA+RFC] Possible solution for min()/max() war Brad Chapman @ 2001-08-24 23:21 ` Ben LaHaise 2001-08-24 23:58 ` Brad Chapman ` (2 more replies) 0 siblings, 3 replies; 95+ messages in thread From: Ben LaHaise @ 2001-08-24 23:21 UTC (permalink / raw) To: Brad Chapman; +Cc: linux-kernel On Fri, 24 Aug 2001, Brad Chapman wrote: > This way, some hackers can use the two-arg min()/max() inside an #ifdef block, > other hackers can use the three-arg min()/max() inside an #ifdef block, > and people who don't care can select either. Have you no taste? Use of #ifdef's should be minimised as much as possible. For this kind of construct, the spurious preprocessor usage just makes me want to vomit. -ben ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-24 23:21 ` Ben LaHaise @ 2001-08-24 23:58 ` Brad Chapman 2001-08-25 0:13 ` Alexander Viro 2001-08-24 23:59 ` Brad Chapman 2001-08-25 0:07 ` David S. Miller 2 siblings, 1 reply; 95+ messages in thread From: Brad Chapman @ 2001-08-24 23:58 UTC (permalink / raw) To: Ben LaHaise; +Cc: linux-kernel --- Ben LaHaise <bcrl@redhat.com> wrote: > On Fri, 24 Aug 2001, Brad Chapman wrote: > > > This way, some hackers can use the two-arg min()/max() inside an #ifdef block, > > other hackers can use the three-arg min()/max() inside an #ifdef block, > > and people who don't care can select either. > > Have you no taste? Use of #ifdef's should be minimised as much as > possible. For this kind of construct, the spurious preprocessor usage > just makes me want to vomit. > > -ben Mr. LaHaise, Eeek! Sorry. That was just a preliminary. As I see it, there are several ways to wire this up: - make everyone use the new macros (some people are thinking :P) - make everyone use #ifdef blocks with a config option (you think it's :P) - make min()/max() typeof() wrappers for a switch-style stack of comparison functions which work on the various types, i.e: __u8 minimum = min(one, two) -> __u8 minimum = __u8_min(one, two) (this may be too complex and is probably :P) - make min()/max() inline functions, cast things to void, and use memcmp() (this might almost be reasonable, but is probably also :P) - stay with the old-style macros (:P, :P, :P) What do you think, sir? Brad ===== Brad Chapman Permanent e-mail: kakadu_croc@yahoo.com Current e-mail: kakadu@adelphia.net Alternate e-mail: kakadu@netscape.net __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-24 23:58 ` Brad Chapman @ 2001-08-25 0:13 ` Alexander Viro 2001-08-25 0:25 ` Brad Chapman 0 siblings, 1 reply; 95+ messages in thread From: Alexander Viro @ 2001-08-25 0:13 UTC (permalink / raw) To: Brad Chapman; +Cc: Ben LaHaise, linux-kernel On Fri, 24 Aug 2001, Brad Chapman wrote: > - make everyone use the new macros (some people are thinking :P) > > - make everyone use #ifdef blocks with a config option (you think it's :P) > > - make min()/max() typeof() wrappers for a switch-style stack of comparison > functions which work on the various types, i.e: > > __u8 minimum = min(one, two) -> __u8 minimum = __u8_min(one, two) > > (this may be too complex and is probably :P) > > - make min()/max() inline functions, cast things to void, and use memcmp() > (this might almost be reasonable, but is probably also :P) > > - stay with the old-style macros (:P, :P, :P) > > What do you think, sir? Use different inline functions for signed and unsigned. Explicitly. Any scheme trying to imitate polymorphism with use of cpp/ GNU extensions/whatever is missing the point. There is _no_ common operation to extend on several types. Choice between signed and unsigned max should be explicit - they are different operations. Trying to hide that is C++itis of the worst kind - false polymorphism that hides only one thing: subtle bugs. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 0:13 ` Alexander Viro @ 2001-08-25 0:25 ` Brad Chapman 2001-08-25 0:34 ` Alexander Viro 0 siblings, 1 reply; 95+ messages in thread From: Brad Chapman @ 2001-08-25 0:25 UTC (permalink / raw) To: Alexander Viro; +Cc: linux-kernel --- Alexander Viro <viro@math.psu.edu> wrote: > On Fri, 24 Aug 2001, Brad Chapman wrote: > > > - make everyone use the new macros (some people are thinking :P) > > > > - make everyone use #ifdef blocks with a config option (you think it's :P) > > > > - make min()/max() typeof() wrappers for a switch-style stack of comparison > > functions which work on the various types, i.e: > > > > __u8 minimum = min(one, two) -> __u8 minimum = __u8_min(one, two) > > > > (this may be too complex and is probably :P) > > > > - make min()/max() inline functions, cast things to void, and use memcmp() > > (this might almost be reasonable, but is probably also :P) > > > > - stay with the old-style macros (:P, :P, :P) > > > > What do you think, sir? > > Use different inline functions for signed and unsigned. > Explicitly. OK. That sounds reasonable, but do we want to do another forced change, or do we want to hide it? That seems to be the root of the problem: keeping the same API but making it work _right_. > > Any scheme trying to imitate polymorphism with use of cpp/ > GNU extensions/whatever is missing the point. There is _no_ common > operation to extend on several types. Choice between signed and > unsigned max should be explicit - they are different operations. Well, IIRC I remember someone saying that it was legal to compare signed/unsigned ints, if you did it in the right order. IMHO that might be incorrect. And none of the ideas I have suggested use any fancy cpp/GNU rubbish. The most evil-sounding thing I suggested was #4. > > Trying to hide that is C++itis of the worst kind - false > polymorphism that hides only one thing: subtle bugs. > Ack. (IMHO) I don't like C++ either :P Brad ===== Brad Chapman Permanent e-mail: kakadu_croc@yahoo.com Current e-mail: kakadu@adelphia.net Alternate e-mail: kakadu@netscape.net __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 0:25 ` Brad Chapman @ 2001-08-25 0:34 ` Alexander Viro 2001-08-25 0:53 ` Brad Chapman 0 siblings, 1 reply; 95+ messages in thread From: Alexander Viro @ 2001-08-25 0:34 UTC (permalink / raw) To: Brad Chapman; +Cc: linux-kernel On Fri, 24 Aug 2001, Brad Chapman wrote: > > > > > > What do you think, sir? > > > > Use different inline functions for signed and unsigned. > > Explicitly. > > OK. That sounds reasonable, but do we want to do another forced > change, or do we want to hide it? That seems to be the root of the problem: > keeping the same API but making it work _right_. Existing API is wrong. "Hiding" is precisely what's wrong here - we use the same name for two subtly different functions. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 0:34 ` Alexander Viro @ 2001-08-25 0:53 ` Brad Chapman 2001-08-25 1:15 ` Alexander Viro 2001-08-26 17:59 ` Bill Pringlemeir 0 siblings, 2 replies; 95+ messages in thread From: Brad Chapman @ 2001-08-25 0:53 UTC (permalink / raw) To: Alexander Viro; +Cc: linux-kernel --- Alexander Viro <viro@math.psu.edu> wrote: > On Fri, 24 Aug 2001, Brad Chapman wrote: > > > > What do you think, sir? > > > > > > Use different inline functions for signed and unsigned. > > > Explicitly. > > > > OK. That sounds reasonable, but do we want to do another forced > > change, or do we want to hide it? That seems to be the root of the problem: > > keeping the same API but making it work _right_. > > Existing API is wrong. "Hiding" is precisely what's wrong here - we > use the same name for two subtly different functions. Mr. Viro, OK. The existing API is wrong and the new min()/max() macros are the right way to properly compare values. However, we could always add a config option to enable a compatibility macro, which would use typeof() on one of the two variables and then call the real min()/max(). Something like this (just an example): #ifdef CONFIG_ALLOW_COMPAT_MINMAX #define proper_min(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) #define proper_max(t, a, b) ((t)(a) > (t)(b) ? (a) : (b)) #define min(a, b) proper_min(typeof(a), a, b) #define max(a, b) proper_max(typeof(a), a, b) #else #define min(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) #define max(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) #endif Unfortunately, this would violate your idea that "hiding" the real code behind compatibility stuff is C++esque, and, IYO, an Evil Thing(tm). That just leaves me with one question to everybody: <rant type="question" intensity="30%"> Why did Linus change this out of /dev/null and suddenly run off!? </rant> Brad ===== Brad Chapman Permanent e-mail: kakadu_croc@yahoo.com Current e-mail: kakadu@adelphia.net Alternate e-mail: kakadu@netscape.net __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 0:53 ` Brad Chapman @ 2001-08-25 1:15 ` Alexander Viro 2001-08-25 11:21 ` Brad Chapman 2001-08-27 0:02 ` Rusty Russell 2001-08-26 17:59 ` Bill Pringlemeir 1 sibling, 2 replies; 95+ messages in thread From: Alexander Viro @ 2001-08-25 1:15 UTC (permalink / raw) To: Brad Chapman; +Cc: linux-kernel On Fri, 24 Aug 2001, Brad Chapman wrote: > OK. The existing API is wrong and the new min()/max() macros are the > right way to properly compare values. However, we could always add a config > option to enable a compatibility macro, which would use typeof() on one of the > two variables and then call the real min()/max(). Something like this (just an > example): > > #ifdef CONFIG_ALLOW_COMPAT_MINMAX > #define proper_min(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) > #define proper_max(t, a, b) ((t)(a) > (t)(b) ? (a) : (b)) > #define min(a, b) proper_min(typeof(a), a, b) > #define max(a, b) proper_max(typeof(a), a, b) _THAT_ _IS_ _WRONG_. Who the fuck said that we always want type of _first_ argument? Mind you, IMNSHO Dave had been on a seriously bad trip when he had added that "type" argument - separate names would be cleaner. And yes, it'd be better in prepatch instead of 2.4.9-final. However, no matter which variant you pick, old code with min/max was broken. Unless you are carefully giving right types (preferanly - with casts) it works only by accidents (if it works at all). "Compatibility option" is exactly the worst thing in such cases. It's either changing the whole codebase or not bothering at all. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 1:15 ` Alexander Viro @ 2001-08-25 11:21 ` Brad Chapman 2001-08-27 0:02 ` Rusty Russell 1 sibling, 0 replies; 95+ messages in thread From: Brad Chapman @ 2001-08-25 11:21 UTC (permalink / raw) To: Alexander Viro; +Cc: linux-kernel --- Alexander Viro <viro@math.psu.edu> wrote: > > > On Fri, 24 Aug 2001, Brad Chapman wrote: > > > OK. The existing API is wrong and the new min()/max() macros are the > > right way to properly compare values. However, we could always add a config > > option to enable a compatibility macro, which would use typeof() on one of the > > two variables and then call the real min()/max(). Something like this (just an > > example): > > > > #ifdef CONFIG_ALLOW_COMPAT_MINMAX > > #define proper_min(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) > > #define proper_max(t, a, b) ((t)(a) > (t)(b) ? (a) : (b)) > > #define min(a, b) proper_min(typeof(a), a, b) > > #define max(a, b) proper_max(typeof(a), a, b) > > _THAT_ _IS_ _WRONG_. Who the fuck said that we always want type of _first_ > argument? Mind you, IMNSHO Dave had been on a seriously bad trip when he > had added that "type" argument - separate names would be cleaner. And yes, > it'd be better in prepatch instead of 2.4.9-final. I never said we had to use the _first_ argument. We could always do the _second_. Or we could scrap the whole idea of compatibility with any of the old, "broken" type-unsafe code and make everybody use the new macros. Period. > > However, no matter which variant you pick, old code with min/max > was broken. Unless you are carefully giving right types (preferanly - > with casts) it works only by accidents (if it works at all). > > "Compatibility option" is exactly the worst thing in such cases. > It's either changing the whole codebase or not bothering at all. > Ack. Seems like the best way to fix this is to either make everybody use the new macros, or wait for Linus to show up ;-) Brad ===== Brad Chapman Permanent e-mail: kakadu_croc@yahoo.com Current e-mail: kakadu@adelphia.net Alternate e-mail: kakadu@netscape.net __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 1:15 ` Alexander Viro 2001-08-25 11:21 ` Brad Chapman @ 2001-08-27 0:02 ` Rusty Russell 2001-08-28 4:59 ` Linus Torvalds 1 sibling, 1 reply; 95+ messages in thread From: Rusty Russell @ 2001-08-27 0:02 UTC (permalink / raw) To: Alexander Viro; +Cc: linux-kernel In message <Pine.GSO.4.21.0108242055410.19796-100000@weyl.math.psu.edu> you wri te: > _THAT_ _IS_ _WRONG_. Who the fuck said that we always want type of _first_ > argument? Mind you, IMNSHO Dave had been on a seriously bad trip when he > had added that "type" argument - separate names would be cleaner. And yes, > it'd be better in prepatch instead of 2.4.9-final. We're going in circles. Linus requested that the explicit type arg be added. IIUC Dave's original patch (and I just want to say that Dave is my hero for pushing this) looked vaguely like the existing code in include/linux/netfilter.h. He's mentioned it before but noone bothered to read it, so I'll quote for you: /* From arch/i386/kernel/smp.c: * * Why isn't this somewhere standard ?? * * Maybe because this procedure is horribly buggy, and does * not deserve to live. Think about signedness issues for five * seconds to see why. - Linus */ /* Two signed, return a signed. */ #define SMAX(a,b) ((ssize_t)(a)>(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) #define SMIN(a,b) ((ssize_t)(a)<(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) /* Two unsigned, return an unsigned. */ #define UMAX(a,b) ((size_t)(a)>(size_t)(b) ? (size_t)(a) : (size_t)(b)) #define UMIN(a,b) ((size_t)(a)<(size_t)(b) ? (size_t)(a) : (size_t)(b)) /* Two unsigned, return a signed. */ #define SUMAX(a,b) ((size_t)(a)>(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) #define SUMIN(a,b) ((size_t)(a)<(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) Cheers, Rusty. -- Premature optmztion is rt of all evl. --DK ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-27 0:02 ` Rusty Russell @ 2001-08-28 4:59 ` Linus Torvalds 2001-08-28 5:20 ` Alexander Viro 2001-08-28 12:42 ` Roman Zippel 0 siblings, 2 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-28 4:59 UTC (permalink / raw) To: linux-kernel In article <E15b9rU-0002vE-00@localhost>, Rusty Russell <rusty@rustcorp.com.au> wrote: >In message <Pine.GSO.4.21.0108242055410.19796-100000@weyl.math.psu.edu> you wri >te: >> _THAT_ _IS_ _WRONG_. Who the fuck said that we always want type of _first_ >> argument? Mind you, IMNSHO Dave had been on a seriously bad trip when he >> had added that "type" argument - separate names would be cleaner. And yes, >> it'd be better in prepatch instead of 2.4.9-final. > >We're going in circles. Linus requested that the explicit type arg be >added. Yes. "requested" is a bit too politic. It was not davem who added the type argument. It was me who _required_ that min/max be very much explicitly type-aware, as I consider any other alternative to be inherently buggy. Yes, the new Linux min/max macros are different from the ones people are used to. Yes, I expected a lot of flamage. And no, I don't care one whit. Unlike EVERY SINGLE other C version of min/max I've ever seen, the new Linux kernel versions at least have a fighting chance in hell of generating correct code. And that's to a large degree because they force the user to specify what type he _thinks_ the comparison should be done in. I know people don't understand about the difference between signed and unsigned compares, and people may not even realize that just by doing the patches David ended up fixing a few real bugs that were uncovered simply by virtue of having to think about what kind of comparison it was supposed to be. There were a few alternatives that we looked at (or rather, David implemented, and I ended up rejecting due to various reasons), but they all boiled down to "how do we sanely generate min/max functions while at the same time forcing people to understand the types in question". Some of the intermediate patches had the type in the macro name, ie things like "min_uint()" and "min_slong()". The final version (ie the one in 2.4.9) was deemed to be the most flexible. The problem with putting the "type" in the name of the function/macro is/was that - there's a _lot_ of types. David actually had a version for this, and there were separate versions for everything ranging from "int" to "uint", to "s32" to "u32", to "size_t" etc etc. - Some people would _still_ not understand what the advantage of explicit typing would be, so we'd have drivers doing their own min/max functions, not understanding the issues about signs and C type conversion. Thus the current "min(type,x,y)" approach, which fixes both problems. I have one thing to say to people who do not like the new min/max functions: most of them probably never even _understood_ the multitude of bugs that are inherent in the classical #define min(x,y) ((x) < (y) ? (x) : (y)) but even so I'm somewhat surprised that this is still debated. I hoped it would be over by the time I came back ;) Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 4:59 ` Linus Torvalds @ 2001-08-28 5:20 ` Alexander Viro 2001-08-28 5:51 ` Linus Torvalds 2001-08-28 12:42 ` Roman Zippel 1 sibling, 1 reply; 95+ messages in thread From: Alexander Viro @ 2001-08-28 5:20 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel On Tue, 28 Aug 2001, Linus Torvalds wrote: > It was not davem who added the type argument. It was me who _required_ > that min/max be very much explicitly type-aware, as I consider any other > alternative to be inherently buggy. Sure. Any attempt to keep the old min/max and make them automagically do the right thing is doomed since there is no _single_ right thing we want from them and choice should be deliberate and explicit. No arguments here. > generating correct code. And that's to a large degree because they > force the user to specify what type he _thinks_ the comparison should be > done in. <nod> > The problem with putting the "type" in the name of the function/macro > is/was that > > - there's a _lot_ of types. David actually had a version for this, and > there were separate versions for everything ranging from "int" to > "uint", to "s32" to "u32", to "size_t" etc etc. Ugh. I have a serious feeling that most of them would be redundant, but... OK, I guess that somebody might want "unsigned max of x and y % 256" (x being unsigned char and y - unsigned long). Yes, with stuff like that we'd really need a function for every type, but I would be very surprised if somebody actually needed that (and I'd rather see it written explicitly, regardless of the mechanism we use). > - Some people would _still_ not understand what the advantage of > explicit typing would be, so we'd have drivers doing their own > min/max functions, not understanding the issues about signs and C > type conversion. Well, that's what grep is for. Bet that we'll see MAX, __max, m4x and all sorts of similar "workarounds", so grep'n'LART will be needed anyway. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 5:20 ` Alexander Viro @ 2001-08-28 5:51 ` Linus Torvalds 2001-08-28 11:10 ` Alan Cox 0 siblings, 1 reply; 95+ messages in thread From: Linus Torvalds @ 2001-08-28 5:51 UTC (permalink / raw) To: Alexander Viro; +Cc: linux-kernel On Tue, 28 Aug 2001, Alexander Viro wrote: > > > The problem with putting the "type" in the name of the function/macro > > is/was that > > > > - there's a _lot_ of types. David actually had a version for this, and > > there were separate versions for everything ranging from "int" to > > "uint", to "s32" to "u32", to "size_t" etc etc. > > Ugh. I have a serious feeling that most of them would be redundant, but... > OK, I guess that somebody might want "unsigned max of x and y % 256" (x > being unsigned char and y - unsigned long). It doesn't matter if the two things are of a different type - there is always just one type that the comparison is done in, anyway (and returning any other type doesn't make any sense to me, at least). And yes, they _are_ redundant in the sense that "size_t" is obviously the same as "unsigned int" or "unsigned long" on just about all architectures: but we obviously don't know that on a source level, so you do end up needing various different versions. You could, of course, just always do the type expansion, and really boil it all down to just "large enough" types, the obvious ones being "unsigned long" and "signed long". However, that implies either depending on a smart compiler or accepting an extra type expansion in the resulting binary, and it also wouldn't work on 64-bit quantities (which NTFS actually _does_ use, for example), so you'd still have to have at least - umin()/umax()/smin()/smax() - for "long" and shorter - u64min()/u64max()/s64min()s64max() - for "long long" and "u64/s64" to make sure that the min/max operations do not truncate any bits. Even so, I'd really want to make sure it gets truncated down too - I'd be nervous about doing "umax()" on two "char" entities: it's MUCH more clear what you get from x = max(unsigned char, char, char) than if you have signed chars that are expanded to unsigned long's and then compared (the compare gets the same result, but how is the final result of "min()" then expanded, if at all?). It gets worse if one of the sides is unsigned and the other signed, at which point the "extend to a larger type" approach doesn't work at all. In short, I really think you want to have the exact types. And a quick grep of the 2.4.9 diff shows that at least for "min()" we have at least the following types already being used: "int" "long" "s64" "u32" "unsigned int" "unsigned long". So that's at _least_ 6 different versions of "min()" if you want to make them different functions. Or, with the 2.4.9 approach, it's just a single macro (well, and another one for "max()"). And when somebody needs a new type, he doesn't have to worry about creating a new instantiation of the macro. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 5:51 ` Linus Torvalds @ 2001-08-28 11:10 ` Alan Cox 2001-08-28 14:15 ` Linus Torvalds 2001-08-28 20:06 ` John Alvord 0 siblings, 2 replies; 95+ messages in thread From: Alan Cox @ 2001-08-28 11:10 UTC (permalink / raw) To: Linus Torvalds; +Cc: Alexander Viro, linux-kernel > Or, with the 2.4.9 approach, it's just a single macro (well, and another > one for "max()"). And when somebody needs a new type, he doesn't have to > worry about creating a new instantiation of the macro. The unfortunate thing is that its min and max as opposed to typed_min and typed_max (with min/max set up to error), since its now a nightmare to maintain compatibility between two allegedly stable releases of the same kernel, as well as with 2.2 Had it been typed_min(a,b,c) then 2.2 could have stayed compatible and the glue would have been simple ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 11:10 ` Alan Cox @ 2001-08-28 14:15 ` Linus Torvalds 2001-08-28 20:06 ` John Alvord 1 sibling, 0 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-28 14:15 UTC (permalink / raw) To: Alan Cox; +Cc: Alexander Viro, linux-kernel On Tue, 28 Aug 2001, Alan Cox wrote: > > The unfortunate thing is that its min and max as opposed to typed_min and > typed_max (with min/max set up to error), since its now a nightmare to > maintain compatibility between two allegedly stable releases of the same > kernel, as well as with 2.2 Note that 2.2.x does not HAVE a "min/max" function, so that cannot be an issue. Yes, some drivers and filesystems did their own private version, but if they are maintained in both 2.2.x and 2.4.x, then it's obviously very easy for them to change their private version to match the 2.4.x tree, so I think this particular argument is rather bogus. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 11:10 ` Alan Cox 2001-08-28 14:15 ` Linus Torvalds @ 2001-08-28 20:06 ` John Alvord 1 sibling, 0 replies; 95+ messages in thread From: John Alvord @ 2001-08-28 20:06 UTC (permalink / raw) To: Alan Cox; +Cc: Linus Torvalds, Alexander Viro, linux-kernel On Tue, 28 Aug 2001 12:10:12 +0100 (BST), Alan Cox <alan@lxorguk.ukuu.org.uk> wrote: >> Or, with the 2.4.9 approach, it's just a single macro (well, and another >> one for "max()"). And when somebody needs a new type, he doesn't have to >> worry about creating a new instantiation of the macro. > >The unfortunate thing is that its min and max as opposed to typed_min and >typed_max (with min/max set up to error), since its now a nightmare to >maintain compatibility between two allegedly stable releases of the same >kernel, as well as with 2.2 > >Had it been typed_min(a,b,c) then 2.2 could have stayed compatible and the >glue would have been simple Does the new min/max definitions hurt portability to and from Linux? john alvord ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 4:59 ` Linus Torvalds 2001-08-28 5:20 ` Alexander Viro @ 2001-08-28 12:42 ` Roman Zippel 2001-08-28 13:27 ` Linus Torvalds 1 sibling, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-28 12:42 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel Hi, Linus Torvalds wrote: > I know people don't understand about the difference between signed and > unsigned compares, and people may not even realize that just by doing > the patches David ended up fixing a few real bugs that were uncovered > simply by virtue of having to think about what kind of comparison it was > supposed to be. What's wrong with "-Wsign-compare"? You just fixed only a minor amount of compares. An explicit type is maintenance problem and cause of other subtle bugs. When types are changing, the type in the macro is too easily missed and can cause these funny "but it works on ia32..." errors. What's wrong with this version? #define min(a, b) ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ _a < _b ? _a : _b; \ }) With "-Wsign-compare" the compiler will warn you about wrong usage and will otherwise automatically do the right thing. Explicit casts are not good, but such half hidden casts are worse. You are hiding the problem instead of really fixing it. Why won't you let the compiler help you? bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 12:42 ` Roman Zippel @ 2001-08-28 13:27 ` Linus Torvalds 2001-08-28 14:19 ` Roman Zippel 0 siblings, 1 reply; 95+ messages in thread From: Linus Torvalds @ 2001-08-28 13:27 UTC (permalink / raw) To: Roman Zippel; +Cc: linux-kernel On Tue, 28 Aug 2001, Roman Zippel wrote: > > Linus Torvalds wrote: > > > I know people don't understand about the difference between signed and > > unsigned compares, and people may not even realize that just by doing > > the patches David ended up fixing a few real bugs that were uncovered > > simply by virtue of having to think about what kind of comparison it was > > supposed to be. > > What's wrong with "-Wsign-compare"? You just fixed only a minor amount > of compares. -Wsign-compare is TOTALLY useless. The problem with signed compares is not just comparing a signed entity against a unsigned one. It's quite common to have signed quantities on both sides, but _intending_ a unsigned comparison or vice versa. This is simply an area where it's better to make people think about the types, than to magically try to do the "right" thing. > What's wrong with this version? [ Standard stupid min() removed ] You just fixed the "re-use arguments" bug - which is a bug, but doesn't address the fact that most of the min/max bugs are due to the programmer _indending_ a unsigned compare because he didn't even think about the type. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 13:27 ` Linus Torvalds @ 2001-08-28 14:19 ` Roman Zippel 2001-08-28 15:14 ` Linus Torvalds 2001-08-28 16:09 ` Andreas Schwab 0 siblings, 2 replies; 95+ messages in thread From: Roman Zippel @ 2001-08-28 14:19 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel Hi, Linus Torvalds wrote: > The problem with signed compares is not just comparing a signed entity > against a unsigned one. It's quite common to have signed quantities on > both sides, but _intending_ a unsigned comparison or vice versa. Then it's a bug that should _not_ be fixed in the min macro. Unsigned values should be hold in unsigned variables. If it's that common, please show me a sane and realistic example. > This is simply an area where it's better to make people think about the > types, than to magically try to do the "right" thing. > > > What's wrong with this version? > > [ Standard stupid min() removed ] It's not stupid, it does the right thing for the majority of the cases. A cast just hides the problem. If you need a broken min macro to get people thinking, you have a much bigger problem. > You just fixed the "re-use arguments" bug - which is a bug, but doesn't > address the fact that most of the min/max bugs are due to the programmer > _indending_ a unsigned compare because he didn't even think about the > type. You maybe fixed a few bugs, but this new macro will only cause new problems in the future. If we change only a single type, you have to scan all min/max users if they possibly need to be changed too. Thanks to the cast, the compiler won't even remotely help you finding them. bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 14:19 ` Roman Zippel @ 2001-08-28 15:14 ` Linus Torvalds 2001-08-28 15:44 ` Henning P. Schmiedehausen ` (2 more replies) 2001-08-28 16:09 ` Andreas Schwab 1 sibling, 3 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-28 15:14 UTC (permalink / raw) To: Roman Zippel; +Cc: linux-kernel On Tue, 28 Aug 2001, Roman Zippel wrote: > > Linus Torvalds wrote: > > > The problem with signed compares is not just comparing a signed entity > > against a unsigned one. It's quite common to have signed quantities on > > both sides, but _intending_ a unsigned comparison or vice versa. > > Then it's a bug that should _not_ be fixed in the min macro. Unsigned > values should be hold in unsigned variables. If it's that common, please > show me a sane and realistic example. I'll show you a real example from drivers/acorn/scsi/acornscsi.c: min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); this_residual is "int", and "DMAC_BUFFER_SIZE" is just a #define for an integer constant. So the above is actually a signed comparison, and I'll bet you that was not what the author intended. Now, this_residual is hopefully never negative, so it doesn't matter. But how many security bugs have you seen where people just didn't even _think_ of the user giving invalid values? Think of code like #define BUFFER_SIZE (10) char buf[BUFFER_SIZE]; len = min(user_len, BUFFER_SIZE); if (copy_from_user(buf, user, len)) return -EFAULT; which is not all that broken. Sure, maybe you _should_ have marked BUFFER_SIZE explicitly unsigned, but face it, how many people actually do that? So "BUFFER_SIZE" is actually a signed value (never mind that it is obviously positive), and if "user_len" is signed too the above doesn't actually do what the programmer obviously _meant_ to do. Does code like the above happen? Sure it does. The input can be signed because often the user interfaces are defined outside the kernel (think of the arguments to "bind()" or "setsockopt()", and realize that "socklen_t" is "int" - the programmer may not even SEE the signedness of the arguments exactly because they are typedefs). And did you realize, for example, that of the existing "min()" implementations, some were inline functions that implicitly cast their arguments to "int" (and one to "unsigned int")? This way we could also maintain those kinds of local conventions - where the programmer had originally (at least in the case of the unsigned int) on purpose made all "min()" functions unsigned. That, together with different pieces of code really wanting different semantics. Let me quote something that got removed: <include/net/sock.h>: -static __inline__ int min(unsigned int a, unsigned int b) -{ - if (a > b) - a = b; - return a; -} - <net/khttpd/prototypes.h>: -/* the TCP/IP stack defines a __BROKEN__ set of min/max functions !! */ -/* So we better define our own. */ - -/* Broken means: working on unsigned data only, which is not acceptable - for kHTTPd and probably a lot of other functions. */ - -#undef min -#undef max -#define min(a,b) ( (a) < (b) ? (a) : (b) ) -#define max(a,b) ( (a) > (b) ? (a) : (b) ) Now, just _imagine_ the set of bugs implicit in the fact that part of networking wants "min()" to be unsigned, while another part (that _uses_ the code that depends on the unsigned "min()") re-defines min() to be "whatever the arguments are". Now isn't it better to have a nice macro that _can_ be used for all of this, and that _does_ explicitly handle the issue of signedness that different parts of the code has very different opinions on, and that clearly encodes the assumptions that you have at the exact point of use? Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 15:14 ` Linus Torvalds @ 2001-08-28 15:44 ` Henning P. Schmiedehausen 2001-08-28 15:55 ` Russell King 2001-08-28 16:05 ` Alan Cox 2001-08-28 16:39 ` Roman Zippel 2001-08-29 0:33 ` Daniel Phillips 2 siblings, 2 replies; 95+ messages in thread From: Henning P. Schmiedehausen @ 2001-08-28 15:44 UTC (permalink / raw) To: linux-kernel Linus Torvalds <torvalds@transmeta.com> writes: >I'll show you a real example from drivers/acorn/scsi/acornscsi.c: > min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); >this_residual is "int", and "DMAC_BUFFER_SIZE" is just a #define for >an integer constant. So the above is actually a signed comparison, and >I'll bet you that was not what the author intended. And the mistake of the author was not to write "unsigned int this_residual". That's the bug. Not the min() function. Regards Henning -- Dipl.-Inf. (Univ.) Henning P. Schmiedehausen -- Geschaeftsfuehrer INTERMETA - Gesellschaft fuer Mehrwertdienste mbH hps@intermeta.de Am Schwabachgrund 22 Fon.: 09131 / 50654-0 info@intermeta.de D-91054 Buckenhof Fax.: 09131 / 50654-20 ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 15:44 ` Henning P. Schmiedehausen @ 2001-08-28 15:55 ` Russell King 2001-08-28 16:05 ` Alan Cox 1 sibling, 0 replies; 95+ messages in thread From: Russell King @ 2001-08-28 15:55 UTC (permalink / raw) To: hps; +Cc: linux-kernel On Tue, Aug 28, 2001 at 03:44:53PM +0000, Henning P. Schmiedehausen wrote: > >I'll show you a real example from drivers/acorn/scsi/acornscsi.c: > > min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); > > >this_residual is "int", and "DMAC_BUFFER_SIZE" is just a #define for > >an integer constant. So the above is actually a signed comparison, and > >I'll bet you that was not what the author intended. > > And the mistake of the author was not to write "unsigned int this_residual". > That's the bug. Not the min() function. Hmm, everyone's talking about my code. And I agree with Henning that "this_residual" should be unsigned. Unfortunately, it's defined in the generic SCSI layer. I'd really like it to be fixed in the SCSI layer no matter what the outcome of the min/max debarcle^wdebate is. -- 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] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 15:44 ` Henning P. Schmiedehausen 2001-08-28 15:55 ` Russell King @ 2001-08-28 16:05 ` Alan Cox 2001-08-28 16:53 ` Roman Zippel 1 sibling, 1 reply; 95+ messages in thread From: Alan Cox @ 2001-08-28 16:05 UTC (permalink / raw) To: hps; +Cc: linux-kernel > > min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); > > >this_residual is "int", and "DMAC_BUFFER_SIZE" is just a #define for > >an integer constant. So the above is actually a signed comparison, and > >I'll bet you that was not what the author intended. > > And the mistake of the author was not to write "unsigned int this_residual". > That's the bug. Not the min() function. Or more likely the author knew that this_residual was going to be positive in all cases anyway. Its just sloppy typing by the scsi layer. The typing of min() is something I do agree with Linus about (for once 8)), and making people think about them is a good idea. When DaveM proposed the original his patches showed up a bug in the older ixj driver immediately. Alan ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 16:05 ` Alan Cox @ 2001-08-28 16:53 ` Roman Zippel 0 siblings, 0 replies; 95+ messages in thread From: Roman Zippel @ 2001-08-28 16:53 UTC (permalink / raw) To: Alan Cox; +Cc: hps, linux-kernel Hi, Alan Cox wrote: > The typing of min() is something I do agree with Linus about (for once 8)), > and making people think about them is a good idea. When DaveM proposed the > original his patches showed up a bug in the older ixj driver immediately. No doubt, that it fixed bugs now. What I'm worried about is whether it really avoids bugs in the future and isn't a new source of bugs. bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 15:14 ` Linus Torvalds 2001-08-28 15:44 ` Henning P. Schmiedehausen @ 2001-08-28 16:39 ` Roman Zippel 2001-08-28 21:51 ` Mike Castle 2001-08-29 0:33 ` Daniel Phillips 2 siblings, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-28 16:39 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel Hi, Linus Torvalds wrote: > I'll show you a real example from drivers/acorn/scsi/acornscsi.c: > > min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); > > this_residual is "int", and "DMAC_BUFFER_SIZE" is just a #define for > an integer constant. So the above is actually a signed comparison, and > I'll bet you that was not what the author intended. > > Now, this_residual is hopefully never negative, so it doesn't matter. Let's assume it does. Joe Hacker uses the new min macro and uses int because this_residual is an int. Later he realizes that this_residual must be an unsigned int. Will he now also automatically change the type in the min macro? > But how many security bugs have you seen where people just didn't even > _think_ of the user giving invalid values? > > Think of code like > > #define BUFFER_SIZE (10) > > char buf[BUFFER_SIZE]; > > len = min(user_len, BUFFER_SIZE); > if (copy_from_user(buf, user, len)) > return -EFAULT; > > which is not all that broken. Sure, maybe you _should_ have marked > BUFFER_SIZE explicitly unsigned, but face it, how many people actually do > that? How does the new macro help here? A negative value is invalid and so should be tested _explicitly_. What about code like this: if (len > BUFFER_SIZE) return -EINVAL; This is not automagically fixed by this macro. So your new macro fixes a few problems and hides other problems. I can't call this a solution. > And did you realize, for example, that of the existing "min()" > implementations, some were inline functions that implicitly cast their > arguments to "int" (and one to "unsigned int")? This way we could also > maintain those kinds of local conventions - where the programmer had > originally (at least in the case of the unsigned int) on purpose made all > "min()" functions unsigned. I'm not arguing against a single (and correct) definition of min/max. This had to be fixed of course. > Now isn't it better to have a nice macro that _can_ be used for all of > this, and that _does_ explicitly handle the issue of signedness that > different parts of the code has very different opinions on, and that > clearly encodes the assumptions that you have at the exact point of use? But this assumption is only encoded once. Are you going to change the min interface every second release, just to keep people thinking about the types they're using? Breaking interfaces is fine, but it only works _once_ and is simply forgotten afterwards. To quote my other argument, that is still unanswered: You maybe fixed a few bugs, but this new macro will only cause new problems in the future. If we change only a single type, you have to scan all min/max users if they possibly need to be changed too. Thanks to the cast, the compiler won't even remotely help you finding them. bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 16:39 ` Roman Zippel @ 2001-08-28 21:51 ` Mike Castle 0 siblings, 0 replies; 95+ messages in thread From: Mike Castle @ 2001-08-28 21:51 UTC (permalink / raw) To: linux-kernel On Tue, Aug 28, 2001 at 06:39:43PM +0200, Roman Zippel wrote: > Let's assume it does. Joe Hacker uses the new min macro and uses int > because this_residual is an int. Later he realizes that this_residual > must be an unsigned int. Will he now also automatically change the type > in the min macro? min (typeof(this_residual), this_residual, foo); Though I'm not sure this would be accepted into the kernel. :-> mrc -- Mike Castle dalgoda@ix.netcom.com www.netcom.com/~dalgoda/ We are all of us living in the shadow of Manhattan. -- Watchmen fatal ("You are in a maze of twisty compiler features, all different"); -- gcc ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 15:14 ` Linus Torvalds 2001-08-28 15:44 ` Henning P. Schmiedehausen 2001-08-28 16:39 ` Roman Zippel @ 2001-08-29 0:33 ` Daniel Phillips 2001-08-29 1:13 ` Linus Torvalds 2 siblings, 1 reply; 95+ messages in thread From: Daniel Phillips @ 2001-08-29 0:33 UTC (permalink / raw) To: Linus Torvalds, Roman Zippel; +Cc: linux-kernel On August 28, 2001 05:14 pm, Linus Torvalds wrote: > I'll show you a real example from drivers/acorn/scsi/acornscsi.c: > > min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); > > this_residual is "int", and "DMAC_BUFFER_SIZE" is just a #define for > an integer constant. So the above is actually a signed comparison, and > I'll bet you that was not what the author intended. > > Now, this_residual is hopefully never negative, so it doesn't matter. min(host->scsi.SCp.this_residual, (unsigned) DMAC_BUFFER_SIZE / 2); -- Daniel ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-29 0:33 ` Daniel Phillips @ 2001-08-29 1:13 ` Linus Torvalds 2001-08-29 15:42 ` Daniel Phillips 0 siblings, 1 reply; 95+ messages in thread From: Linus Torvalds @ 2001-08-29 1:13 UTC (permalink / raw) To: Daniel Phillips; +Cc: Roman Zippel, linux-kernel On Wed, 29 Aug 2001, Daniel Phillips wrote: > > min(host->scsi.SCp.this_residual, (unsigned) DMAC_BUFFER_SIZE / 2); Sure. If you put the type information explicitly, you can get it right. Which is, btw, _exactly_ why the min() function takes the type explicitly. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-29 1:13 ` Linus Torvalds @ 2001-08-29 15:42 ` Daniel Phillips 2001-08-29 16:02 ` David Lang 0 siblings, 1 reply; 95+ messages in thread From: Daniel Phillips @ 2001-08-29 15:42 UTC (permalink / raw) To: Linus Torvalds; +Cc: Roman Zippel, linux-kernel On August 29, 2001 03:13 am, Linus Torvalds wrote: > On Wed, 29 Aug 2001, Daniel Phillips wrote: > > > > min(host->scsi.SCp.this_residual, (unsigned) DMAC_BUFFER_SIZE / 2); > > Sure. > > If you put the type information explicitly, you can get it right. > > Which is, btw, _exactly_ why the min() function takes the type explicitly. My point is that proper programming discipline would have prevented the problem from arising in the first place. It would be far more appropriate for kernel programmers to exercise such discpline than to treat them like babies, breaking well-known syntax in the process. It seems trivial to pick up all potential min/max problems with the Stanford Checker in the case some programmer has been too clueless to think about their code as they write it. A simple policy statement for users of min/max would have avoided this entire mess. Not that I you're going to back down, it just made me feel better to get this off my chest ;-) -- Daniel ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-29 15:42 ` Daniel Phillips @ 2001-08-29 16:02 ` David Lang 2001-08-29 23:49 ` Daniel Phillips 0 siblings, 1 reply; 95+ messages in thread From: David Lang @ 2001-08-29 16:02 UTC (permalink / raw) To: Daniel Phillips; +Cc: Linus Torvalds, Roman Zippel, linux-kernel one question that I thought of in context with the other e-mails in this thread. when you write a signed/unsigned comparison is it defined in any standard which type the compiler should generate or is it somethign that could be different in different compilers (and versions) (also when comparing different size items same question) if there are cases that are not defined in a standard and could vary by compiler/version then we definantly need to have the current version with the type argument. David Lang On Wed, 29 Aug 2001, Daniel Phillips wrote: > Date: Wed, 29 Aug 2001 17:42:39 +0200 > From: Daniel Phillips <phillips@bonn-fries.net> > To: Linus Torvalds <torvalds@transmeta.com> > Cc: Roman Zippel <zippel@linux-m68k.org>, linux-kernel@vger.kernel.org > Subject: Re: [IDEA+RFC] Possible solution for min()/max() war > > On August 29, 2001 03:13 am, Linus Torvalds wrote: > > On Wed, 29 Aug 2001, Daniel Phillips wrote: > > > > > > min(host->scsi.SCp.this_residual, (unsigned) DMAC_BUFFER_SIZE / 2); > > > > Sure. > > > > If you put the type information explicitly, you can get it right. > > > > Which is, btw, _exactly_ why the min() function takes the type explicitly. > > My point is that proper programming discipline would have prevented the > problem from arising in the first place. It would be far more appropriate > for kernel programmers to exercise such discpline than to treat them like > babies, breaking well-known syntax in the process. > > It seems trivial to pick up all potential min/max problems with the Stanford > Checker in the case some programmer has been too clueless to think about > their code as they write it. A simple policy statement for users of min/max > would have avoided this entire mess. > > Not that I you're going to back down, it just made me feel better to get this > off my chest ;-) > > -- > Daniel > - > 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/ > ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-29 16:02 ` David Lang @ 2001-08-29 23:49 ` Daniel Phillips 2001-08-30 2:05 ` Bill Rugolsky Jr. 2001-08-30 3:28 ` Linus Torvalds 0 siblings, 2 replies; 95+ messages in thread From: Daniel Phillips @ 2001-08-29 23:49 UTC (permalink / raw) To: David Lang; +Cc: Linus Torvalds, Roman Zippel, linux-kernel On August 29, 2001 06:02 pm, David Lang wrote: > one question that I thought of in context with the other e-mails in this > thread. > > when you write a signed/unsigned comparison is it defined in any standard > which type the compiler should generate or is it somethign that could be > different in different compilers (and versions) Yes, in the signed/unsigned case the comparison generated is always unsigned. This is something that all c programmers are supposed to have tattoed on the insides of their eyelids, because if you don't know it there are all kinds of situations that can bite you, not just min and max. > (also when comparing different size items same question) The narrower is expanded to the size of the wider before being compared. > if there are cases that are not defined in a standard and could vary by > compiler/version then we definantly need to have the current version with > the type argument. No, these cases are defined perfectly clearly and have been at least since K&R. > David Lang > > > On Wed, 29 Aug 2001, > Daniel Phillips wrote: > > > Date: Wed, 29 Aug 2001 17:42:39 +0200 > > From: Daniel Phillips <phillips@bonn-fries.net> > > To: Linus Torvalds <torvalds@transmeta.com> > > Cc: Roman Zippel <zippel@linux-m68k.org>, linux-kernel@vger.kernel.org > > Subject: Re: [IDEA+RFC] Possible solution for min()/max() war > > > > On August 29, 2001 03:13 am, Linus Torvalds wrote: > > > On Wed, 29 Aug 2001, Daniel Phillips wrote: > > > > > > > > min(host->scsi.SCp.this_residual, (unsigned) DMAC_BUFFER_SIZE / 2); > > > > > > Sure. > > > > > > If you put the type information explicitly, you can get it right. > > > > > > Which is, btw, _exactly_ why the min() function takes the type explicitly. > > > > My point is that proper programming discipline would have prevented the > > problem from arising in the first place. It would be far more appropriate > > for kernel programmers to exercise such discpline than to treat them like > > babies, breaking well-known syntax in the process. > > > > It seems trivial to pick up all potential min/max problems with the Stanford > > Checker in the case some programmer has been too clueless to think about > > their code as they write it. A simple policy statement for users of min/max > > would have avoided this entire mess. > > > > Not that I you're going to back down, it just made me feel better to get this > > off my chest ;-) > > > > -- > > Daniel > > - > > 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/ > > > - > 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/ > > ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-29 23:49 ` Daniel Phillips @ 2001-08-30 2:05 ` Bill Rugolsky Jr. 2001-08-30 3:28 ` Linus Torvalds 1 sibling, 0 replies; 95+ messages in thread From: Bill Rugolsky Jr. @ 2001-08-30 2:05 UTC (permalink / raw) To: Daniel Phillips; +Cc: David Lang, Linus Torvalds, Roman Zippel, linux-kernel On Thu, Aug 30, 2001 at 01:49:54AM +0200, Daniel Phillips wrote: > On August 29, 2001 06:02 pm, David Lang wrote: > > when you write a signed/unsigned comparison is it defined in any standard > > which type the compiler should generate or is it somethign that could be > > different in different compilers (and versions) > > Yes, in the signed/unsigned case the comparison generated is always > unsigned. This is something that all c programmers are supposed to have > tattoed on the insides of their eyelids, because if you don't know it > there are all kinds of situations that can bite you, not just min and > max. > > > (also when comparing different size items same question) > > The narrower is expanded to the size of the wider before being compared. Careful. Operands of relational operators undergo "usual arithmetic conversions," which are value-preserving, so unsigned char and unsigned short are promoted to int on platforms where int is value-preserving. Similarly, unsigned int is promoted to long where long is value-preserving, as I pointed out earlier in this thread. (This wasn't always the case, see below.) The problem here, of course, is that if you don't know the widths of the operands, you can't determine the type of the compare. Change the width of the operand (to steal some bits in a structure, say) and the signedness of the comparison changes. > > > if there are cases that are not defined in a standard and could vary by > > compiler/version then we definantly need to have the current version with > > the type argument. > > No, these cases are defined perfectly clearly and have been at least > since K&R. K&R 1st Edition and the UNIX 7th Edition C reference manual specify that unsigned dominates. The "value-preserving" language was crafted for C89, and appears in K&R, 2nd Edition. C99 introduces the notion of integer type "rank" to generalize the rules to extended precision types. Regards, Bill Rugolsky ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-29 23:49 ` Daniel Phillips 2001-08-30 2:05 ` Bill Rugolsky Jr. @ 2001-08-30 3:28 ` Linus Torvalds 2001-08-30 13:10 ` Ion Badulescu ` (2 more replies) 1 sibling, 3 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-30 3:28 UTC (permalink / raw) To: Daniel Phillips; +Cc: David Lang, Roman Zippel, linux-kernel On Thu, 30 Aug 2001, Daniel Phillips wrote: > > Yes, in the signed/unsigned case the comparison generated is always > unsigned. Well... No. If you compare a signed integer with a unsigned char, the char gets promoted to a _signed_ integer, and the comparison is signed. It is NOT a unsigned comparison. And THIS is one example of why it gets complicated. The C logic for type expansion is just a tad too easy to get wrong, and the strict type-checking you normally have with well-written ANSI C simply does not exist for integer types. The compiler will silently just do the promotion.. Somebody mentioned -Wsign-compare. Try it with the example above. It won't warn at all, exactly because under C both sides of such a compare have the _same_ sign, even if one is a "unsigned char", and the other is a "signed int". Try it yourself if you don't believe me. Please guys. The issue of sign in comparisons are a LOT more complicated than most of you seem to think. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 3:28 ` Linus Torvalds @ 2001-08-30 13:10 ` Ion Badulescu 2001-08-30 13:17 ` David Woodhouse 2001-08-30 16:09 ` Linus Torvalds 2001-08-30 13:49 ` Roman Zippel 2001-08-30 17:01 ` Daniel Phillips 2 siblings, 2 replies; 95+ messages in thread From: Ion Badulescu @ 2001-08-30 13:10 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel On Wed, 29 Aug 2001 20:28:20 -0700 (PDT), Linus Torvalds <torvalds@transmeta.com> wrote: > If you compare a signed integer with a unsigned char, the char gets > promoted to a _signed_ integer, and the comparison is signed. It is NOT > a unsigned comparison. > [...] > > Somebody mentioned -Wsign-compare. Try it with the example above. It won't > warn at all, exactly because under C both sides of such a compare have the > _same_ sign, even if one is a "unsigned char", and the other is a "signed > int". And why should the compiler warn at all? The range of "int" completely covers the range of "unsigned char", so the result of the comparison will always be correct if the types were chosen correctly. ... unless of course the programmer used an unsigned char when what he really wanted was a signed char. But in that case even your typed min macro won't save him, because what should the forced type be anyway? If it's "int", nothing changes; if it's "signed char", you risk truncating the int. So you end up with something like min(int, a, (char)b) and I fail to see how this is any better than min(a, (char)b) Ion -- It is better to keep your mouth shut and be thought a fool, than to open it and remove all doubt. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 13:10 ` Ion Badulescu @ 2001-08-30 13:17 ` David Woodhouse 2001-08-30 13:26 ` Ion Badulescu 2001-08-30 16:09 ` Linus Torvalds 1 sibling, 1 reply; 95+ messages in thread From: David Woodhouse @ 2001-08-30 13:17 UTC (permalink / raw) To: Ion Badulescu; +Cc: Linus Torvalds, linux-kernel ionut@cs.columbia.edu said: > ... unless of course the programmer used an unsigned char when what he > really wanted was a signed char. But in that case even your typed min > macro won't save him, because what should the forced type be anyway? > If it's "int", nothing changes; if it's "signed char", you risk > truncating the int. So you end up with something like > min(int, a, (char)b) If the programmer wrote that when he really wanted a signed char, he has more fundamental brokenness to worry about than the min/max fun. -- dwmw2 ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 13:17 ` David Woodhouse @ 2001-08-30 13:26 ` Ion Badulescu 0 siblings, 0 replies; 95+ messages in thread From: Ion Badulescu @ 2001-08-30 13:26 UTC (permalink / raw) To: David Woodhouse; +Cc: Linus Torvalds, linux-kernel On Thu, 30 Aug 2001, David Woodhouse wrote: > > > ionut@cs.columbia.edu said: > > ... unless of course the programmer used an unsigned char when what he > > really wanted was a signed char. But in that case even your typed min > > macro won't save him, because what should the forced type be anyway? > > If it's "int", nothing changes; if it's "signed char", you risk > > truncating the int. So you end up with something like > > > min(int, a, (char)b) > > If the programmer wrote that when he really wanted a signed char, he has > more fundamental brokenness to worry about than the min/max fun. Which is precisely my point, we're in violent agreement here... Ion -- It is better to keep your mouth shut and be thought a fool, than to open it and remove all doubt. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 13:10 ` Ion Badulescu 2001-08-30 13:17 ` David Woodhouse @ 2001-08-30 16:09 ` Linus Torvalds 2001-08-30 16:28 ` Ion Badulescu ` (2 more replies) 1 sibling, 3 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-30 16:09 UTC (permalink / raw) To: Ion Badulescu; +Cc: linux-kernel On Thu, 30 Aug 2001, Ion Badulescu wrote: > > > > Somebody mentioned -Wsign-compare. Try it with the example above. It won't > > warn at all, exactly because under C both sides of such a compare have the > > _same_ sign, even if one is a "unsigned char", and the other is a "signed > > int". > > And why should the compiler warn at all? The range of "int" completely > covers the range of "unsigned char", so the result of the comparison will > always be correct if the types were chosen correctly. You obviously do not understand the issue at all. It doesn't _matter_ that the int covers the whole space of "unsigned char". What if the "int" happens to be negative? Right. You get _totally_ different results for a unsigned and a signed compare. For the signed compare, you do obviously get the "logical" result, that the negative int is smaller than the unsigned char. But if you're not _aware_ of the signedness, you may not think about the issues. Basically, when you compare a "long" to a "xxx", and the xxxx is unsigned, WHAT ARE THE RESULTS? And the answer is that you simply DO NOT KNOW! If the xxxx is "unsigned int", the sign of the compare actually depends on whether "int" is smaller than "long" on the particular architecture you're compiling for. So the sign of the compare actually ends up being different on an alpha than on a x86. Stating the type you compare in explicitly means that you do not get surprised. And not getting surprisied is a good thing. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:09 ` Linus Torvalds @ 2001-08-30 16:28 ` Ion Badulescu 2001-08-31 12:50 ` Jamie Lokier 2001-08-30 16:31 ` Ben LaHaise 2001-08-30 16:38 ` Peter T. Breuer 2 siblings, 1 reply; 95+ messages in thread From: Ion Badulescu @ 2001-08-30 16:28 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel On Thu, 30 Aug 2001, Linus Torvalds wrote: > You obviously do not understand the issue at all. No offence, but you obviously assume too much. > It doesn't _matter_ that the int covers the whole space of "unsigned > char". > > What if the "int" happens to be negative? If the "int" happens to be negative, the comparison will say that the "int" is smaller than the "unsigned char". This is the expected result. What exactly is wrong with this? So I have this number, -200, which is stored in an int. I have this other number, 200, which is stored in an unsigned char. Everybody in his right mind will agree that -200 is smaller than 200, the compiler will do just that, yet you disagree??? > Basically, when you compare a "long" to a "xxx", and the xxxx is unsigned, > WHAT ARE THE RESULTS? So now you're turning it around. If you compare a long with unsigned char, there is no issue. If you compare long with unsigned int, you get the right result on the alpha and a warning on x86. If you compare long with unsigned long, you get a warning period. > And the answer is that you simply DO NOT KNOW! If the xxxx is "unsigned > int", the sign of the compare actually depends on whether "int" is smaller > than "long" on the particular architecture you're compiling for. So the > sign of the compare actually ends up being different on an alpha than on a > x86. And read above. You get the right result on the alpha and a warning on the x86. I don't see the problem with that. If you want to be 100% paranoid, change the sign-compare warning into an error, so people don't ignore it. That's a much better alternative, and gcc supports it. > Stating the type you compare in explicitly means that you do not get > surprised. No. It means I suppress the gcc warning before I get a chance to see it. It does NOT necessarily mean I (and by "I" I mean your average programmer) think about the range issues, I just think Linux min/max are broken. > And not getting surprisied is a good thing. Duplicating types all over the place is a bad thing, however. Ion -- It is better to keep your mouth shut and be thought a fool, than to open it and remove all doubt. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:28 ` Ion Badulescu @ 2001-08-31 12:50 ` Jamie Lokier 2001-08-31 13:45 ` Roman Zippel 0 siblings, 1 reply; 95+ messages in thread From: Jamie Lokier @ 2001-08-31 12:50 UTC (permalink / raw) To: Ion Badulescu; +Cc: Linus Torvalds, linux-kernel Ion Badulescu wrote: > So now you're turning it around. If you compare a long with unsigned char, > there is no issue. This is _not_ true. What Linus said about long vs. unsigned int depending on the architecture also applies to unsigned char, on those old 32-bit Crays. It is legitimate for unsigned char to have the same size as signed long. > If you compare long with unsigned int, you get the right result on the > alpha and a warning on x86. If you compare long with unsigned long, > you get a warning period. Precisely. Buggy code (read: architecture-specific bug) is written, and the bug isn't noticed until somebody compiles that code on a different architecture. Far better to have GCC warn even on the alpha. > And read above. You get the right result on the alpha and a warning on the > x86. I don't see the problem with that. > > If you want to be 100% paranoid, change the sign-compare warning into an > error, so people don't ignore it. That's a much better alternative, and > gcc supports it. See example with sizeof(). Something similar applies with PAGE_SIZE and other unsigned constants. > > Stating the type you compare in explicitly means that you do not get > > surprised. > > No. It means I suppress the gcc warning before I get a chance to see it. I have to agree with Ion here. The explicit type is very helpful, but if it reduces argument range, it masks a real bug. Not that the old macros were any better. Ideally, there should be some way to get a warning out of GCC when a bug is masked in this way. This is what I see as the closest to ideal: 1. min/max with type argument, as in new kernels. 2. Warning added to GCC for casts which reduce argument range, but only when explicitly requested by an attribute on the cast... 3. Warning added to GCC for signed vs. unsigned comparisons _regardless_ of type size. This would also catch erroneous unsigned char vs. EOF checks in misuses of stdio. However, a type attribute must be provided to make the result of sizeof() not return a warning. (size_t _should_ return a warning, though, so it is not that simple). As you can see, at least the kernel part is done :) -- Jamie ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 12:50 ` Jamie Lokier @ 2001-08-31 13:45 ` Roman Zippel 2001-08-31 16:27 ` Jamie Lokier 0 siblings, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-31 13:45 UTC (permalink / raw) To: Jamie Lokier; +Cc: Ion Badulescu, Linus Torvalds, linux-kernel Hi, Jamie Lokier wrote: > 2. Warning added to GCC for casts which reduce argument range, but > only when explicitly requested by an attribute on the cast... How many false positives will this produce? I think, Linus will hate this warning even more than -Wsign-compare. > 3. Warning added to GCC for signed vs. unsigned comparisons > _regardless_ of type size. This would also catch erroneous > unsigned char vs. EOF checks in misuses of stdio. Do you know of such bug in the context of min()? bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 13:45 ` Roman Zippel @ 2001-08-31 16:27 ` Jamie Lokier 0 siblings, 0 replies; 95+ messages in thread From: Jamie Lokier @ 2001-08-31 16:27 UTC (permalink / raw) To: Roman Zippel; +Cc: Ion Badulescu, Linus Torvalds, linux-kernel Roman Zippel wrote: > > 3. Warning added to GCC for signed vs. unsigned comparisons > > _regardless_ of type size. This would also catch erroneous > > unsigned char vs. EOF checks in misuses of stdio. > > Do you know of such bug in the context of min()? I don't know of an actual example. This one is made up: min (int, len, big_size) Now if big_size has unsigned type, and does not fit in the range of int, this expression will return the value of big_size cast to int, i.e. a negative value. The suggested warning would catch this potential bug. I don't know if it would warn for too many other things. Certainly, a sizeof() exception (don't warn about signed comparison with sizeof() result) is essential; perhaps too many other exceptions are required too. -- Jamie ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:09 ` Linus Torvalds 2001-08-30 16:28 ` Ion Badulescu @ 2001-08-30 16:31 ` Ben LaHaise 2001-08-30 16:38 ` Peter T. Breuer 2 siblings, 0 replies; 95+ messages in thread From: Ben LaHaise @ 2001-08-30 16:31 UTC (permalink / raw) To: Linus Torvalds; +Cc: Ion Badulescu, linux-kernel On Thu, 30 Aug 2001, Linus Torvalds wrote: > And not getting surprisied is a good thing. Most of us don't really care about the details of the whole min/max thing (my only real care is that it should've been called anything other than min or max, typed_min perhaps, but that's a secondary issue, more relevant to forwards compatibility of 2.4/2.2/2.0 hybrid drivers). What we do care about is the fact that a release was done without a prepatch to look over to give people a chance to fix any resulting breakage. -ben ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:09 ` Linus Torvalds 2001-08-30 16:28 ` Ion Badulescu 2001-08-30 16:31 ` Ben LaHaise @ 2001-08-30 16:38 ` Peter T. Breuer 2001-08-30 19:51 ` David Weinehall [not found] ` <mit.lcs.mail.linux-kernel/200108301638.SAA04923@nbd.it.uc3m.es> 2 siblings, 2 replies; 95+ messages in thread From: Peter T. Breuer @ 2001-08-30 16:38 UTC (permalink / raw) To: linux kernel "Linus Torvalds wrote:" > What if the "int" happens to be negative? if sizeof(typeof(a)) != sizeof(typeof(b)) BUG() // sizes differ const (typeof(a)) _a = ~(typeof(a))0 const (typeof(b)) _b = ~(typeof(b))0 if _a < 0 && _b > 0 || _a > 0 && b < 0 BUG() // one signed, the other unsigned standard_max(a,b) Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:38 ` Peter T. Breuer @ 2001-08-30 19:51 ` David Weinehall 2001-08-30 20:16 ` Peter T. Breuer 2001-08-30 20:31 ` Daniel Phillips [not found] ` <mit.lcs.mail.linux-kernel/200108301638.SAA04923@nbd.it.uc3m.es> 1 sibling, 2 replies; 95+ messages in thread From: David Weinehall @ 2001-08-30 19:51 UTC (permalink / raw) To: Peter T. Breuer; +Cc: linux kernel On Thu, Aug 30, 2001 at 06:38:40PM +0200, Peter T. Breuer wrote: > "Linus Torvalds wrote:" > > What if the "int" happens to be negative? > > if sizeof(typeof(a)) != sizeof(typeof(b)) > BUG() // sizes differ > const (typeof(a)) _a = ~(typeof(a))0 > const (typeof(b)) _b = ~(typeof(b))0 > if _a < 0 && _b > 0 || _a > 0 && b < 0 > BUG() // one signed, the other unsigned > standard_max(a,b) <disgusting vomit-sound>Do you really want code like that in the kernel (yes, I know that there are code that can compete with it in ugliness</disgusting vomit-sound> /David Weinehall _ _ // David Weinehall <tao@acc.umu.se> /> Northern lights wander \\ // Project MCA Linux hacker // Dance across the winter sky // \> http://www.acc.umu.se/~tao/ </ Full colour fire </ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 19:51 ` David Weinehall @ 2001-08-30 20:16 ` Peter T. Breuer 2001-08-30 20:31 ` Daniel Phillips 1 sibling, 0 replies; 95+ messages in thread From: Peter T. Breuer @ 2001-08-30 20:16 UTC (permalink / raw) To: David Weinehall; +Cc: Peter T. Breuer, linux kernel "A month of sundays ago David Weinehall wrote:" > On Thu, Aug 30, 2001 at 06:38:40PM +0200, Peter T. Breuer wrote: > > "Linus Torvalds wrote:" > > > What if the "int" happens to be negative? > > > > if sizeof(typeof(a)) != sizeof(typeof(b)) > > BUG() // sizes differ > > const (typeof(a)) _a = ~(typeof(a))0 > > const (typeof(b)) _b = ~(typeof(b))0 > > if _a < 0 && _b > 0 || _a > 0 && b < 0 > > BUG() // one signed, the other unsigned > > standard_max(a,b) > > <disgusting vomit-sound>Do you really want code like that in the > kernel (yes, I know that there are code that can compete with it in Have you read it? Do you not realize That it optimizes down to BUG() or the standard min/max? By BUG(), I was hoping that somebody could produce some magic that doesn't even compile when it reduces to that, but maybe that's too much to hope for from gcc. > ugliness</disgusting vomit-sound> If that's the limit of the audiences intelligence, I don't think I'll bother bothering to think next time! I rather hoped instead for people to pick up the idea and tell me about the problem left to cover (void* ? what if the arch does not have 2's complement arithmetic?) Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 19:51 ` David Weinehall 2001-08-30 20:16 ` Peter T. Breuer @ 2001-08-30 20:31 ` Daniel Phillips 1 sibling, 0 replies; 95+ messages in thread From: Daniel Phillips @ 2001-08-30 20:31 UTC (permalink / raw) To: David Weinehall, Peter T. Breuer; +Cc: linux kernel On August 30, 2001 09:51 pm, David Weinehall wrote: > On Thu, Aug 30, 2001 at 06:38:40PM +0200, Peter T. Breuer wrote: > > "Linus Torvalds wrote:" > > > What if the "int" happens to be negative? > > > > if sizeof(typeof(a)) != sizeof(typeof(b)) > > BUG() // sizes differ > > const (typeof(a)) _a = ~(typeof(a))0 > > const (typeof(b)) _b = ~(typeof(b))0 > > if _a < 0 && _b > 0 || _a > 0 && b < 0 > > BUG() // one signed, the other unsigned > > standard_max(a,b) > > <disgusting vomit-sound>Do you really want code like that in the > kernel (yes, I know that there are code that can compete with it in > ugliness</disgusting vomit-sound> Well, loook, if the signedness and widths match all the tests get optimized out as constant expressions, if they don't it barfs with BUG and the author has to insert specify saner types for the input variables. It's nice. This accomplishes what 3arg_min/max set out to do without messing up the syntax. -- Daniel ^ permalink raw reply [flat|nested] 95+ messages in thread
[parent not found: <mit.lcs.mail.linux-kernel/200108301638.SAA04923@nbd.it.uc3m.es>]
* Re: [IDEA+RFC] Possible solution for min()/max() war [not found] ` <mit.lcs.mail.linux-kernel/200108301638.SAA04923@nbd.it.uc3m.es> @ 2001-08-30 22:42 ` Patrick J. LoPresti 2001-08-30 23:27 ` Peter T. Breuer 0 siblings, 1 reply; 95+ messages in thread From: Patrick J. LoPresti @ 2001-08-30 22:42 UTC (permalink / raw) To: linux-kernel, torvalds "Peter T. Breuer" <ptb@it.uc3m.es> writes: > "Linus Torvalds wrote:" > > What if the "int" happens to be negative? > > if sizeof(typeof(a)) != sizeof(typeof(b)) > BUG() // sizes differ > const (typeof(a)) _a = ~(typeof(a))0 > const (typeof(b)) _b = ~(typeof(b))0 > if _a < 0 && _b > 0 || _a > 0 && b < 0 > BUG() // one signed, the other unsigned > standard_max(a,b) This is a MUCH nicer solution. max() is a well-defined mathematical concept; it is simply the larger of its two arguments, period. It is C's *promotion* rules that kill you, especially signed->unsigned promotion. So just forbid them, at least when they implicit. You can argue about whether the "differing sizes" case should be a BUG(), since the output will still be mathematically correct. It depends on how often it is useful to compare (say) unsigned chars against ints, and on whether the compiler warns about cases where you try to stuff the return value into a too-small container. I bet that just forbidding signed->unsigned promotion would be enough. In general, types should work for the programmer, not the other way around. Force people to "think hard" about their types when they are making a likely mistake, not *every* time they call max(). Littering all those calls with types is just gross. - Pat ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 22:42 ` Patrick J. LoPresti @ 2001-08-30 23:27 ` Peter T. Breuer 2001-08-31 0:55 ` Linus Torvalds ` (2 more replies) 0 siblings, 3 replies; 95+ messages in thread From: Peter T. Breuer @ 2001-08-30 23:27 UTC (permalink / raw) To: Patrick J. LoPresti; +Cc: linux-kernel, torvalds "A month of sundays ago Patrick J. LoPresti wrote:" > This is a MUCH nicer solution. max() is a well-defined mathematical > concept; it is simply the larger of its two arguments, period. It is > C's *promotion* rules that kill you, especially signed->unsigned > promotion. So just forbid them, at least when they implicit. > > You can argue about whether the "differing sizes" case should be a > BUG(), since the output will still be mathematically correct. It To give you all something definite to look at, here's some test code: // standard good 'ol faithful version #define __MIN(x,y) ({\ typeof(x) _x = x; \ typeof(y) _y = y; \ _x < _y ? _x : _y ; \ }) // possible implemetation with type sanity checks - alter to taste #define MIN(x,y) ({\ const typeof(x) _x = ~(typeof(x))0; \ const typeof(y) _y = ~(typeof(y))0; \ void MIN_BUG(); \ if (sizeof(_x) != sizeof(_y)) \ MIN_BUG(); \ if ((_x > 0 && _y < 0) || (_x < 0 && _y > 0)) \ MIN_BUG(); \ __MIN(x,y); \ }) // test code that compiles with no complaints with -O1 -Wall int main() { unsigned i = 1; unsigned j = -2; return MIN(i,j); } // test code that complains at link time (in this version) with .. // gcc -o test -O1 -Wall test.c // /tmp/cczJbwv5.o: In function `main': // /tmp/cczJbwv5.o(.text+0x7): undefined reference to `MIN_BUG' // collect2: ld returned 1 exit status // int main() { unsigned i = 1; signed j = -2; return MIN(i,j); } > depends on how often it is useful to compare (say) unsigned chars > against ints, and on whether the compiler warns about cases where you > try to stuff the return value into a too-small container. I bet that > just forbidding signed->unsigned promotion would be enough. Possibly. I have little clue as to the real extent of the problem. Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 23:27 ` Peter T. Breuer @ 2001-08-31 0:55 ` Linus Torvalds 2001-08-31 1:28 ` Peter T. Breuer 2001-08-31 13:22 ` Peter T. Breuer 2001-08-31 12:01 ` [IDEA+RFC] Possible solution for min()/max() war Roman Zippel 2001-09-07 0:52 ` Bill Pringlemeir 2 siblings, 2 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-31 0:55 UTC (permalink / raw) To: Peter T. Breuer; +Cc: Patrick J. LoPresti, linux-kernel On Fri, 31 Aug 2001, Peter T. Breuer wrote: > > To give you all something definite to look at, here's some test code: Hmm.. This might be a good idea, actually. Have you tried whether it finds something in the existing tree (you could just take the existing macro and ignore the first argument)? This would definitely be acceptable to me, and should (assuming no gcc optimization bugs) work with no run-time overhead. Thanks, Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 0:55 ` Linus Torvalds @ 2001-08-31 1:28 ` Peter T. Breuer 2001-08-31 13:22 ` Peter T. Breuer 1 sibling, 0 replies; 95+ messages in thread From: Peter T. Breuer @ 2001-08-31 1:28 UTC (permalink / raw) To: Linus Torvalds; +Cc: Peter T. Breuer, Patrick J. LoPresti, linux-kernel "A month of sundays ago Linus Torvalds wrote:" > > On Fri, 31 Aug 2001, Peter T. Breuer wrote: > > > > To give you all something definite to look at, here's some test code: > > Hmm.. This might be a good idea, actually. Have you tried whether it finds > something in the existing tree (you could just take the existing macro and Yes. I just tried it. The first warning thrown up for 2.4.8 was in tun.c, when I did a make modules. Obviously it all depends on my .config as to what it finds! I put in a asm(".error_here") instead of BUG() so the compilation stops at every problem instead of warning and continuing. Hence I don't kow the total. I can try and see .. It's very late here (spain) so I don't trust myself to do much hacking of code right now .. I corrected the tun.c code (it was harmless) and posted the first bit of output a little while ago. It should be down your mail client page a bit. > ignore the first argument)? > > This would definitely be acceptable to me, and should (assuming no gcc > optimization bugs) work with no run-time overhead. Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 0:55 ` Linus Torvalds 2001-08-31 1:28 ` Peter T. Breuer @ 2001-08-31 13:22 ` Peter T. Breuer 2001-08-31 14:02 ` Linus Torvalds 1 sibling, 1 reply; 95+ messages in thread From: Peter T. Breuer @ 2001-08-31 13:22 UTC (permalink / raw) To: Linus Torvalds; +Cc: Peter T. Breuer, Patrick J. LoPresti, linux-kernel "A month of sundays ago Linus Torvalds wrote:" > > On Fri, 31 Aug 2001, Peter T. Breuer wrote: > > > > To give you all something definite to look at, here's some test code: > > Hmm.. This might be a good idea, actually. Have you tried whether it finds > something in the existing tree (you could just take the existing macro and > ignore the first argument)? I only have source for 2.4.8 plus xfs 1.0 patches here. I removed MIN/min/MAX/max definitions from about a dozen header files in include/linux, and added an #include <linux/minmax.h> to them. That file goes below. The test are fairly alarmist. On doing a make bzImage no errors showed. On make modules, 4 errors showed, one in tun.c and 3 in pagebuf_io.c (I presume that's from xfs). I probably covered about 25% of the kernel code in that trial. The tun.c one was safe as it was .. the signed value was always positive at the point where the macro was applied. I'm not at all sure about the pagebuf_io.c ones because there was deep iovec and iobuf and skb magic about, but that's not of interest to you. I made the comparisons signed and added an if (value out of signed range) BUG(); just above. The macros below seem to show up the line number perfectly in the compiletime error. I guess one can add a __FILE__ to them someway. One thing that worries me is that these should have triggered on the signed/unsigned char comparisons that you were worried about in -Wsigned-compare, and no, they didn't. They did find other signed/unsigned mixes, but not char. Peter #ifndef MINMAX_H #define MINMAX_H 1 #define __MINMAX_S(x) #x #define MINMAX_S(x) __MINMAX_S(x) #define MINMAX_BUG asm(".unsafe_min_or_max_at_line_" MINMAX_S(__LINE__)) #define __MIN(x,y) ({\ typeof(x) _x = x; \ typeof(y) _y = y; \ _x < _y ? _x : _y ; \ }) #define MIN(x,y) ({\ const typeof(x) _x = ~(typeof(x))0; \ const typeof(y) _y = ~(typeof(y))0; \ if (sizeof(_x) != sizeof(_y)) \ MINMAX_BUG; \ if ((_x > (typeof(x))0 && _y < (typeof(y))0) \ || (_x < (typeof(x))0 && _y > (typeof(y))0)) \ MINMAX_BUG; \ __MIN(x,y); \ }) #define __MAX(x,y) ({\ typeof(x) _x = x; \ typeof(y) _y = y; \ _x > _y ? _x : _y ; \ }) #define MAX(x,y) ({\ const typeof(x) _x = ~(typeof(x))0; \ const typeof(y) _y = ~(typeof(y))0; \ if (sizeof(_x) != sizeof(_y)) \ MINMAX_BUG; \ if ((_x > (typeof(x))0 && _y < (typeof(y))0) \ || (_x < (typeof(x))0 && _y > (typeof(y))0)) \ MINMAX_BUG; \ __MAX(x,y); \ }) #ifndef min #define min(x,y) MIN(x,y) #endif #ifndef max #define max(x,y) MAX(x,y) #endif #endif ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 13:22 ` Peter T. Breuer @ 2001-08-31 14:02 ` Linus Torvalds 2001-08-31 15:34 ` Peter T. Breuer 2001-08-31 22:25 ` [PATCH] i386 SA_INTERRUPT logic Jonathan Lundell 0 siblings, 2 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-31 14:02 UTC (permalink / raw) To: Peter T. Breuer; +Cc: Patrick J. LoPresti, linux-kernel On Fri, 31 Aug 2001, Peter T. Breuer wrote: > > On doing a make bzImage no errors showed. On make modules, 4 errors > showed, one in tun.c and 3 in pagebuf_io.c (I presume that's from > xfs). > > I probably covered about 25% of the kernel code in that trial. Good. This implies that the test itself is "reasonable and safe" - it doesn't get nasty false positives, and assuming people en dup being happy about it never causing surprising sign changes, I think this is a good idea. I _would_ suggest that you change the MIN_BUG() thing to the traditional #define compile_time_assert(x) \ do { switch (0) { case 0: case (x) != 0: ; } } while (0) which gives the error from the compiler, and does not depend on the assembler. (Admittedly the error message isn't the nicest in the world, but it gives file and line number and include depth etc.. ) > The tun.c one was safe as it was .. the signed value was always > positive at the point where the macro was applied. Note that a _few_ false positives are fine - we can fix them up, and people will be happy. The problems happen if the false positives are so numerous that it makes common code uglier and harder to read because of work-arounds for checkers. So adding a cast or using an unsigned constant or whatever is fine. > One thing that worries me is that these should have triggered on > the signed/unsigned char comparisons that you were worried about in > -Wsigned-compare, and no, they didn't. They did find other > signed/unsigned mixes, but not char. What I _really_ think might be interesting is a -Wsign-promote warnign that hits outside compares (at any implicit promotion that changes the sign - ie exactly the cases where K&R v1 and v2 differ), but I suspect that it will have even _more_ problems than -Wsign-compare in the sense that it probably really needs the compiler to do range analysis for any amount of sane output.. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 14:02 ` Linus Torvalds @ 2001-08-31 15:34 ` Peter T. Breuer 2001-08-31 22:25 ` [PATCH] i386 SA_INTERRUPT logic Jonathan Lundell 1 sibling, 0 replies; 95+ messages in thread From: Peter T. Breuer @ 2001-08-31 15:34 UTC (permalink / raw) To: Linus Torvalds; +Cc: Peter T. Breuer, Patrick J. LoPresti, linux-kernel "A month of sundays ago Linus Torvalds wrote:" > I _would_ suggest that you change the MIN_BUG() thing to the traditional > > #define compile_time_assert(x) \ > do { switch (0) { case 0: case (x) != 0: ; } } while (0) > > which gives the error from the compiler, and does not depend on the > assembler. OK. I did that here (inverting the logic from the if blah then bug form). It goes just as well. Do you want this made up as a patch for 2.4.9? Leaving code that thereby becomes non-compiling to its owner's tender care? What assertions on the types do you want, btw? People have been saying that unequal size types are ok, and that it's just signed vs unsigned that's the problem, and even then only when it's the longer type that's unsigned and the shorter that's signed. I'd be inclined to be paranoid and leave the alarms ringing when sizes or signs don't match exactly. > What I _really_ think might be interesting is a > > -Wsign-promote > > warnign that hits outside compares (at any implicit promotion that > changes the sign - ie exactly the cases where K&R v1 and v2 differ), but I > suspect that it will have even _more_ problems than -Wsign-compare in the Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* [PATCH] i386 SA_INTERRUPT logic 2001-08-31 14:02 ` Linus Torvalds 2001-08-31 15:34 ` Peter T. Breuer @ 2001-08-31 22:25 ` Jonathan Lundell 1 sibling, 0 replies; 95+ messages in thread From: Jonathan Lundell @ 2001-08-31 22:25 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel Herewith a patch to arch/i386/kernel/irq.c:handle_IRQ_event(). To belabor the obvious, the SA_INTERRUPT flag ought to affect just the handler it's set (or not) for. The existing code can enable interrupts for drivers that don't want them enabled, or disable them for drivers that do. We've done cursory testing, but can't test all possible cases; it looks straightforward enough, though. I notice that this is fixed in alpha, broken in arm, cris, ia64, mips, ppc, sh. The respective architecture maintainers might like to have a closer look. --- /usr/src/linux-2.4.9/arch/i386/kernel/irq.c Wed Jun 20 11:06:38 2001 +++ irq.c Fri Aug 31 14:29:11 2001 @@ -443,17 +443,16 @@ status = 1; /* Force the "do bottom halves" bit */ - if (!(action->flags & SA_INTERRUPT)) - __sti(); - do { status |= action->flags; + if (!(action->flags & SA_INTERRUPT)) + __sti(); action->handler(irq, action->dev_id, regs); + __cli(); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); irq_exit(cpu, irq); -- /Jonathan Lundell. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 23:27 ` Peter T. Breuer 2001-08-31 0:55 ` Linus Torvalds @ 2001-08-31 12:01 ` Roman Zippel 2001-08-31 12:13 ` Peter T. Breuer 2001-09-07 0:52 ` Bill Pringlemeir 2 siblings, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-31 12:01 UTC (permalink / raw) To: Peter T. Breuer; +Cc: Patrick J. LoPresti, linux-kernel, torvalds Hi, On Fri, 31 Aug 2001, Peter T. Breuer wrote: > if (sizeof(_x) != sizeof(_y)) \ > MIN_BUG(); \ What bug are you trying to fix here? > int main() { > unsigned i = 1; > signed j = -2; > return MIN(i,j); > } Try -Wsign-compare. bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 12:01 ` [IDEA+RFC] Possible solution for min()/max() war Roman Zippel @ 2001-08-31 12:13 ` Peter T. Breuer 2001-08-31 12:58 ` Roman Zippel 0 siblings, 1 reply; 95+ messages in thread From: Peter T. Breuer @ 2001-08-31 12:13 UTC (permalink / raw) To: Roman Zippel; +Cc: Peter T. Breuer, Patrick J. LoPresti, linux-kernel "A month of sundays ago Roman Zippel wrote:" > On Fri, 31 Aug 2001, Peter T. Breuer wrote: > > > if (sizeof(_x) != sizeof(_y)) \ > > MIN_BUG(); \ > > What bug are you trying to fix here? Wake up! > > int main() { > > unsigned i = 1; > > signed j = -2; > > return MIN(i,j); > > } > > Try -Wsign-compare. Wake up harder! Try reading the last 10 days kernel messages. The last 48 hours are particularly rewarding. To be honest, nobody has precisely formulated the problem. I'll attempt a quick summary of the most salient: C silently transforms signed int to unsigned int in cross-signed comparisons. This results in 1U < -2, and gives rise to all kinds of error paths from min/max codes (in particular, but they're not all) of the form min(unsigned_positive_constant, signed_ok_or_error_value) whose authors were expecting to get the error value out when the error value went in! There are apparently more problems too, but nobody has explained them to me in a manner that I can comprehend. I suspect that nobody knows the full range of possible faults. I put in the size comparison that you remarked upon so that people could tell me about it. Tell me about it. Linus wants possible mistakes flagged. He specifically does not want -Wsign-compare because it apparently gives false positives. Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 12:13 ` Peter T. Breuer @ 2001-08-31 12:58 ` Roman Zippel 2001-08-31 13:29 ` Peter T. Breuer 0 siblings, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-31 12:58 UTC (permalink / raw) To: Peter T. Breuer; +Cc: Roman Zippel, Patrick J. LoPresti, linux-kernel Hi, On Fri, 31 Aug 2001, Peter T. Breuer wrote: > > What bug are you trying to fix here? > > Wake up! I'm trying. > Try reading the last 10 days kernel messages. The last 48 hours are > particularly rewarding. I have, but I only get the feeling, we're hunting here for imaginary bugs. Real bugs could be found with -Wsign-compare, but nobody wants to use it because our master doesn't want it... Please define the bugs first, you're trying to fix! If you don't like -Wsign-compare, consider defining rules for the Stanford checker. This way you can check all compares and not just the few uses of min. > C silently transforms signed int to unsigned int in cross-signed > comparisons. This results in 1U < -2, and gives rise to all kinds > of error paths from min/max codes (in particular, but they're not > all) of the form Care to give an example? For the cases I tried gcc gave a warning. > Linus wants possible mistakes flagged. He specifically does not want > -Wsign-compare because it apparently gives false positives. diff -u -r1.1.1.23 Makefile --- Makefile 16 Aug 2001 20:50:22 -0000 1.1.1.23 +++ Makefile 31 Aug 2001 11:15:21 -0000 @@ -87,7 +87,11 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH) -CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ +WFLAGS := -Wall -Wstrict-prototypes -Wno-trigraphs +ifdef CONFIG_EXTRA_WARNINGS +WFLAGS := $(WFLAGS) -Wsign-compare +endif +CFLAGS := $(CPPFLAGS) $(WFLAGS) -O2 \ -fomit-frame-pointer -fno-strict-aliasing -fno-common AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) diff -u -r1.1.1.15 config.in --- arch/i386/config.in 21 Jul 2001 12:48:20 -0000 1.1.1.15 +++ arch/i386/config.in 31 Aug 2001 11:12:56 -0000 @@ -390,4 +390,5 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Extra compile warnings' CONFIG_EXTRA_WARNINGS endmenu diff -u -r1.1.1.23 Configure.help --- Documentation/Configure.help 16 Aug 2001 20:55:53 -0000 1.1.1.23 +++ Documentation/Configure.help 31 Aug 2001 11:21:10 -0000 @@ -15766,6 +15766,15 @@ keys are documented in Documentation/sysrq.txt. Don't say Y unless you really know what this hack does. +Extra compile warnings +CONFIG_EXTRA_WARNINGS + If you say Y here, the compilation will generate lots of extra + warnings. Some of them warn about constructions that users generally + do not consider questionable, but which occasionally you might wish + to check for; others warn about constructions that are necessary or + hard to avoid in some cases, and there is no simple way to modify the + code to suppress the warning. Unless you look for bugs, say N. + ISDN subsystem CONFIG_ISDN ISDN ("Integrated Services Digital Networks", called RNIS in France) bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 12:58 ` Roman Zippel @ 2001-08-31 13:29 ` Peter T. Breuer 2001-08-31 14:12 ` Roman Zippel 0 siblings, 1 reply; 95+ messages in thread From: Peter T. Breuer @ 2001-08-31 13:29 UTC (permalink / raw) To: Roman Zippel; +Cc: Peter T. Breuer, Patrick J. LoPresti, linux-kernel "Roman Zippel wrote:" > On Fri, 31 Aug 2001, Peter T. Breuer wrote: > > Try reading the last 10 days kernel messages. The last 48 hours are > > particularly rewarding. > > I have, but I only get the feeling, we're hunting here for imaginary bugs. As I said, nobody has been too precise about the bugs to me either! I just want to provide an alternative to the 3arg min/max that would otherwise have been imposed. Whether we really need either of these alternatives is another argument. > Real bugs could be found with -Wsign-compare, but nobody wants to use it > because our master doesn't want it... > Please define the bugs first, you're trying to fix! If you don't like > -Wsign-compare, consider defining rules for the Stanford checker. This way Stanford checker? Is that a programmable C type checker? If so, lemmee at it. Have you a URL, btw? Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 13:29 ` Peter T. Breuer @ 2001-08-31 14:12 ` Roman Zippel 2001-08-31 14:28 ` Peter T. Breuer 0 siblings, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-31 14:12 UTC (permalink / raw) To: ptb; +Cc: Patrick J. LoPresti, linux-kernel Hi, "Peter T. Breuer" wrote: > As I said, nobody has been too precise about the bugs to me either! So let's be precise first! Please? I've asked Linus about examples, so far I've seen only buggy implementations of min() or an example, where min() shouldn't be used in first place. Maybe I missed something, then I'm deeply sorry for this, but all I want to know is, what are we fixing here? > Stanford checker? Is that a programmable C type checker? If so, lemmee > at it. Have you a URL, btw? http://verify.stanford.edu/SVC/ You should search the archive to look for some good examples, how it can help. bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 14:12 ` Roman Zippel @ 2001-08-31 14:28 ` Peter T. Breuer 2001-08-31 16:30 ` Roman Zippel 0 siblings, 1 reply; 95+ messages in thread From: Peter T. Breuer @ 2001-08-31 14:28 UTC (permalink / raw) To: Roman Zippel; +Cc: linux kernel "Roman Zippel wrote:" > [ptb wrote] > > Stanford checker? Is that a programmable C type checker? If so, lemmee > > at it. Have you a URL, btw? > > http://verify.stanford.edu/SVC/ > You should search the archive to look for some good examples, how it can > help. Hmm .. it looks like a model checker, and only for 1st order logic (i.e. not CTL). It seems very primitive. What's the point of using this instead of the many sphisticated model checkers and theorem provers out there? Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 14:28 ` Peter T. Breuer @ 2001-08-31 16:30 ` Roman Zippel 0 siblings, 0 replies; 95+ messages in thread From: Roman Zippel @ 2001-08-31 16:30 UTC (permalink / raw) To: ptb; +Cc: linux kernel Hi, "Peter T. Breuer" wrote: > Hmm .. it looks like a model checker, and only for 1st order logic > (i.e. not CTL). It seems very primitive. What's the point of using this > instead of the many sphisticated model checkers and theorem provers out > there? We already have good experience with it. Feel free to try something else, the more the better. Nevertheless you have to define the bug and its context first. The problem with defining some fancy min macro is you have too little information about the context, so you can mostly only restrict the use of min, possibly preventing legal uses of it (signed/unsigned compare is AFAIK the only exception). bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 23:27 ` Peter T. Breuer 2001-08-31 0:55 ` Linus Torvalds 2001-08-31 12:01 ` [IDEA+RFC] Possible solution for min()/max() war Roman Zippel @ 2001-09-07 0:52 ` Bill Pringlemeir 2001-09-07 7:26 ` Peter T. Breuer 2001-09-07 10:58 ` Peter T. Breuer 2 siblings, 2 replies; 95+ messages in thread From: Bill Pringlemeir @ 2001-09-07 0:52 UTC (permalink / raw) To: ptb; +Cc: Patrick J. LoPresti, linux-kernel, torvalds >>>>> Peter T Breuer <ptb@it.uc3m.es> writes: > To give you all something definite to look at, here's some test > code: > // standard good 'ol faithful version > #define __MIN(x,y) ({\ > typeof(x) _x = x; \ > typeof(y) _y = y; \ > _x < _y ? _x : _y ; \ > }) > // possible implemetation with type sanity checks - alter to taste > #define MIN(x,y) ({\ > const typeof(x) _x = ~(typeof(x))0; \ > const typeof(y) _y = ~(typeof(y))0; \ > void MIN_BUG(); \ > if (sizeof(_x) != sizeof(_y)) \ > MIN_BUG(); \ > if ((_x > 0 && _y < 0) || (_x < 0 && _y > 0)) \ > MIN_BUG(); \ > __MIN(x,y); \ > }) [snip] Sorry, I have been away for a while. I think that I was talking about a similar approach when Linus was away and David introduced the 3 arg min/max. I just went through 1800 LKML emails and I am not quite clear what happened. I have put my code that I posted earlier at the end of this email. This was the result of someone's `fanciful comment' `what if gcc could handle "if(strcmp(typeof(a),typeof(b))!=0)"'. So here is the important part. The code Peter has introduced a cast in the lines "const typeof(x) _x = ~(typeof(x))0;" etc. I think that the approach of declaring a variable of the type and initializing to zero and then comparing "x - 1" _might_ be better. The version of min() at the end calls the following an error, were Peter's does not [after removing the sizeof() restriction]. unsigned char Cx = 1; unsigned int Ix = 1; unsigned long Lx = 1; Ix = min(Cx,Ix); Lx = min(Cx,Lx); Here the unsigned char is being promoted to int as discussed before. I think that this is `more faithful' as what we are try to achieve is to check the sign that will be used in the min comparison; almost like applying a proper warned signed selectively to the min/max macros. Otherwise, I think we have independently came up with the same thing and the `error' throwing can of course be changed to whatever. fwiw, Bill Pringlemeir. [start code] #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! */ /* 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); min((unsigned)ix,sizeof(ix)); /* BUG? printf ("%d\n", min(Iy, 10)); */ printf ("%d\n", min(cx, 20)); printf("min(3,4,5) %d\n", min(min(5,4),3)); return 0; } /* gcc -Wall -O2 -o test test.c */ [end code] ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-09-07 0:52 ` Bill Pringlemeir @ 2001-09-07 7:26 ` Peter T. Breuer 2001-09-07 12:28 ` Horst von Brand 2001-09-07 10:58 ` Peter T. Breuer 1 sibling, 1 reply; 95+ messages in thread From: Peter T. Breuer @ 2001-09-07 7:26 UTC (permalink / raw) To: Bill Pringlemeir; +Cc: ptb, Patrick J. LoPresti, linux-kernel "A month of sundays ago Bill Pringlemeir wrote:" > > // possible implemetation with type sanity checks - alter to taste > > #define MIN(x,y) ({\ > > const typeof(x) _x = ~(typeof(x))0; \ > > const typeof(y) _y = ~(typeof(y))0; \ > > void MIN_BUG(); \ > > if (sizeof(_x) != sizeof(_y)) \ > > MIN_BUG(); \ > > if ((_x > 0 && _y < 0) || (_x < 0 && _y > 0)) \ > > MIN_BUG(); \ > > __MIN(x,y); \ > > }) > > min/max. I just went through 1800 LKML emails and I am not quite > clear what happened. I have put my code that I posted earlier at the The final version evoked a compile-time error instead of BUG(), and also was more careful about the kind of zero it compares with! Linus okayed it in principle and "real life" tests showed that it works and catches what it's supposed to catch. For me it turned up one kernel report (in tun.c) and three more in the xfs patches. The trial covered about a quarter of the kernel. Some people spotted that the error case can probably be reduced to large signed versus small unsigned, both of size at least int. > end of this email. This was the result of someone's `fanciful comment' > `what if gcc could handle "if(strcmp(typeof(a),typeof(b))!=0)"'. > > So here is the important part. The code Peter has introduced a cast > in the lines "const typeof(x) _x = ~(typeof(x))0;" etc. I think that > the approach of declaring a variable of the type and initializing to > zero and then comparing "x - 1" _might_ be better. I don't know. I intended only to turn the sign bit on. I'm not sure how 1's complement arithmetic works, so I don't know if it works for 1's complement arithmetic. > The version of min() at the end calls the following an error, were > Peter's does not [after removing the sizeof() restriction]. > > unsigned char Cx = 1; unsigned int Ix = 1; unsigned long Lx = 1; > Ix = min(Cx,Ix); Lx = min(Cx,Lx); > > Here the unsigned char is being promoted to int as discussed before. > I think that this is `more faithful' as what we are try to achieve is When someone states what the problem is exactly, and what portion of it they want to test for, then the test can be modified to suit. I intended to show that the test can be performed and a two arg min thereby retained. > to check the sign that will be used in the min comparison; almost > like applying a proper warned signed selectively to the min/max > macros. > > Otherwise, I think we have independently came up with the same thing > and the `error' throwing can of course be changed to whatever. Probably! Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-09-07 7:26 ` Peter T. Breuer @ 2001-09-07 12:28 ` Horst von Brand 2001-09-07 18:03 ` Mark H. Wood 0 siblings, 1 reply; 95+ messages in thread From: Horst von Brand @ 2001-09-07 12:28 UTC (permalink / raw) To: ptb; +Cc: Bill Pringlemeir, Patrick J. LoPresti, linux-kernel "Peter T. Breuer" <ptb@it.uc3m.es> said: [...] > I don't know. I intended only to turn the sign bit on. I'm not sure how > 1's complement arithmetic works, so I don't know if it works for 1's > complement arithmetic. C's unsigned arithmetic is 2-complement. Never even seen a 1-complement machine. -- Dr. Horst H. von Brand Usuario #22616 counter.li.org Departamento de Informatica Fono: +56 32 654431 Universidad Tecnica Federico Santa Maria +56 32 654239 Casilla 110-V, Valparaiso, Chile Fax: +56 32 797513 ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-09-07 12:28 ` Horst von Brand @ 2001-09-07 18:03 ` Mark H. Wood 0 siblings, 0 replies; 95+ messages in thread From: Mark H. Wood @ 2001-09-07 18:03 UTC (permalink / raw) Cc: linux-kernel On Fri, 7 Sep 2001, Horst von Brand wrote: [quote snipped] > C's unsigned arithmetic is 2-complement. Never even seen a 1-complement > machine. CDC big iron. Seymour Cray found he could get a little more speed out of his design that way. IIRC SPSS on CDC gear used the -0 value to indicate a missing case. -- Mark H. Wood, Lead System Programmer mwood@IUPUI.Edu Make a good day. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-09-07 0:52 ` Bill Pringlemeir 2001-09-07 7:26 ` Peter T. Breuer @ 2001-09-07 10:58 ` Peter T. Breuer 2001-09-07 14:39 ` Bill Pringlemeir 1 sibling, 1 reply; 95+ messages in thread From: Peter T. Breuer @ 2001-09-07 10:58 UTC (permalink / raw) To: Bill Pringlemeir; +Cc: linux kernel "A month of sundays ago Bill Pringlemeir wrote:" > Otherwise, I think we have independently came up with the same thing > and the `error' throwing can of course be changed to whatever. If you are interested, the last version I had is the following. The compile_time_assert is linus' idea. We had an illegal assembler statement there originally, containing the line number and the error statement. One or the other will do until gcc gets the __builtin_ct_assert() function. #define compile_time_assert(x) \ do { switch (0) { case 0: case (x) != 0: ; } } while (0) #define __MIN(x,y) ({\ typeof(x) _x = x; \ typeof(y) _y = y; \ _x < _y ? _x : _y ; \ }) #define MIN(x,y) ({\ const typeof(x) _x = ~(typeof(x))0; \ const typeof(y) _y = ~(typeof(y))0; \ compile_time_assert(sizeof(_x) == sizeof(_y));\ compile_time_assert( (_x > (typeof(x))0 && _y > (typeof(y))0) \ || (_x < (typeof(x))0 && _y < (typeof(y))0)); \ __MIN(x,y); \ }) Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-09-07 10:58 ` Peter T. Breuer @ 2001-09-07 14:39 ` Bill Pringlemeir 2001-09-07 15:17 ` Peter T. Breuer 0 siblings, 1 reply; 95+ messages in thread From: Bill Pringlemeir @ 2001-09-07 14:39 UTC (permalink / raw) To: ptb; +Cc: linux kernel >>>>> Peter T Breuer <ptb@it.uc3m.es> writes: > If you are interested, the last version I had is the > following. The compile_time_assert is linus' idea. We had an > illegal assembler statement there originally, containing the line > number and the error statement. One or the other will do until gcc > gets the __builtin_ct_assert() function. #define compile_time_assert(x) \ do { switch (0) { case 0: case (x) != 0: ; } } while (0) #define __MIN(x,y) ({\ typeof(x) _x = x; \ typeof(y) _y = y; \ _x < _y ? _x : _y ; \ }) #define MIN(x,y) ({\ const typeof(x) _x = ~(typeof(x))0; \ const typeof(y) _y = ~(typeof(y))0; \ compile_time_assert(sizeof(_x) == sizeof(_y));\ compile_time_assert( (_x > (typeof(x))0 && _y > (typeof(y))0) \ || (_x < (typeof(x))0 && _y < (typeof(y))0)); \ __MIN(x,y); \ }) As Horst von Brand noted, most modern machines use 2's complement arithmetic. AFAIK, all the Linux targets use 2's complement. The use of ones complement, probably pre-dates MMUs. At any rate, I think that this might be a little clearer as sign, not complement is what is being checked. #define MIN(x,y) ({\ const typeof(x) _x = 0; \ const typeof(y) _y = 0; \ compile_time_assert(sizeof(_x) == sizeof(_y));\ compile_time_assert( (_x - 1 > 0 && _y - 1 > 0) \ || (_x - 1 < 0 && _y - 1 < 0)); \ __MIN(x,y); \ }) This should prevent all cases where the __MIN(x,y) macro can screw up due to sign issues (on that machine). If you do this, the `sizeof' check isn't needed. A MIN(int, long) etc should probably be ok. The only caveats are the promotion in the __MIN itself create a sign mismatch. However, if the `sizeof' check remains, then you don't have to worry about this and both versions are equivalent. Some other things to worry about is what if the type is already const? Maybe that works... What if you try `MIN(x,_x);'. I think that this is something that David took care of in the "3 arg min". regards, Bill Pringlemeir. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-09-07 14:39 ` Bill Pringlemeir @ 2001-09-07 15:17 ` Peter T. Breuer 0 siblings, 0 replies; 95+ messages in thread From: Peter T. Breuer @ 2001-09-07 15:17 UTC (permalink / raw) To: Bill Pringlemeir; +Cc: linux kernel "Bill Pringlemeir wrote:" > compile_time_assert( (_x - 1 > 0 && _y - 1 > 0) \ > || (_x - 1 < 0 && _y - 1 < 0)); \ > > This should prevent all cases where the __MIN(x,y) macro can screw up > due to sign issues (on that machine). If you do this, the `sizeof' Eh? "0" is a signed integer constant. So your comparisons force promotion to int when x is smaller size. I'm not sure what type "unsigned foo - signed int" would have either! It seems to me that you are making things very murky, which is precisely what you want to avoid. > check isn't needed. A MIN(int, long) etc should probably be ok. The > only caveats are the promotion in the __MIN itself create a sign > mismatch. > > However, if the `sizeof' check remains, then you don't have to worry > about this and both versions are equivalent. Some other things to > worry about is what if the type is already const? Maybe that works... No parsum. > What if you try `MIN(x,_x);'. I think that this is something that > David took care of in the "3 arg min". You can't take care of it. A macro is always vulnerable to name clashes. Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 3:28 ` Linus Torvalds 2001-08-30 13:10 ` Ion Badulescu @ 2001-08-30 13:49 ` Roman Zippel 2001-08-30 16:21 ` Linus Torvalds 2001-08-30 17:01 ` Daniel Phillips 2 siblings, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-30 13:49 UTC (permalink / raw) To: Linus Torvalds; +Cc: Daniel Phillips, David Lang, linux-kernel [-- Attachment #1: Type: text/plain, Size: 1933 bytes --] Hi, > Please guys. The issue of sign in comparisons are a LOT more complicated > than most of you seem to think. So why won't you let the compiler help you, even if it's not perfect in every case? This is my last attempt to get things IMO right. Most of the arguments for the new macro were about bugs of the past. No question about this, this had to be fixed, I'm not arguing about this at all. I'm trying to get your attention to the bugs of the future. I still don't understand why you think the new macro will be any better. Why do you think the average kernel hacker will think about the type of the compare and will come to the correct conclusion? It's far to easy to use an int as type argument and forget about it. gcc won't warn about this, so someone first has to hit this bug, before it gets fixed. Maybe I'm too dumb, but I still fail to see, what sense it should make to turn a signed compare into an unsigned one. Either one knows both signed values are only positive, then the sign of the compare and the destination doesn't matter at all. If the value could be negative, better test it explicit: if (len < 0 || len > MAX) len = MAX; First, it's far more readable and makes the intention so clear, that even your average kernel hacker understands it. Second, gcc produces exactly the same code with this, so there is no need to play type tricks with the min macro. Just for fun I enabled -Wsign-compare, enabled most of the drivers and I got this: $ grep 'comparison between signed and unsigned' make.log | sort | uniq | wc -l 3211 So if you want to get people thinking about the types they are using, here you have at least 3211 chances. Please reconsider your decision. IMVHO the new macros are a mistake and will cause only more trouble than they are worth. If you want to keep the new macros, please apply the attached patch, as I prefer this version in the source I'm responsible for. bye, Roman [-- Attachment #2: affs.diff --] [-- Type: text/plain, Size: 4223 bytes --] Index: include/linux/amigaffs.h =================================================================== RCS file: /cvsroot/linux-apus/2.3/include/linux/amigaffs.h,v retrieving revision 1.1.1.3 diff -u -r1.1.1.3 amigaffs.h --- include/linux/amigaffs.h 2001/07/22 23:22:24 1.1.1.3 +++ include/linux/amigaffs.h 2001/08/30 13:38:24 @@ -122,7 +122,7 @@ } -#define MIN(a, b) ({ \ +#define affs_min(a, b) ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ _a < _b ? _a : _b; \ Index: fs/affs/amigaffs.c =================================================================== RCS file: /cvsroot/linux-apus/2.3/fs/affs/amigaffs.c,v retrieving revision 1.6 diff -u -r1.6 amigaffs.c --- fs/affs/amigaffs.c 2001/08/20 13:23:07 1.6 +++ fs/affs/amigaffs.c 2001/08/30 13:38:24 @@ -507,7 +507,7 @@ int affs_copy_name(unsigned char *bstr, struct dentry *dentry) { - int len = MIN(dentry->d_name.len, 30); + int len = affs_min(dentry->d_name.len, 30); *bstr++ = len; memcpy(bstr, dentry->d_name.name, len); Index: fs/affs/dir.c =================================================================== RCS file: /cvsroot/linux-apus/2.3/fs/affs/dir.c,v retrieving revision 1.1.1.6 diff -u -r1.1.1.6 dir.c --- fs/affs/dir.c 2001/07/22 23:18:04 1.1.1.6 +++ fs/affs/dir.c 2001/08/30 13:38:24 @@ -135,7 +135,7 @@ goto readdir_done; } - namelen = MIN(AFFS_TAIL(sb, fh_bh)->name[0], 30); + namelen = affs_min(AFFS_TAIL(sb, fh_bh)->name[0], 30); name = AFFS_TAIL(sb, fh_bh)->name + 1; pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n", namelen, name, ino, hash_pos, f_pos); Index: fs/affs/file.c =================================================================== RCS file: /cvsroot/linux-apus/2.3/fs/affs/file.c,v retrieving revision 1.1.1.8 diff -u -r1.1.1.8 file.c --- fs/affs/file.c 2001/08/20 23:44:37 1.1.1.8 +++ fs/affs/file.c 2001/08/30 13:38:25 @@ -528,7 +528,7 @@ bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) return PTR_ERR(bh); - tmp = MIN(bsize - boff, from - to); + tmp = affs_min(bsize - boff, from - to); memcpy(data + from, AFFS_DATA(bh) + boff, tmp); affs_brelse(bh); bidx++; @@ -558,7 +558,7 @@ bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) return PTR_ERR(bh); - tmp = MIN(bsize - boff, newsize - size); + tmp = affs_min(bsize - boff, newsize - size); memset(AFFS_DATA(bh) + boff, 0, tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); affs_fix_checksum(sb, bh); @@ -576,7 +576,7 @@ bh = affs_getzeroblk_ino(inode, bidx); if (IS_ERR(bh)) goto out; - tmp = MIN(bsize, newsize - size); + tmp = affs_min(bsize, newsize - size); AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); @@ -685,7 +685,7 @@ bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) return PTR_ERR(bh); - tmp = MIN(bsize - boff, to - from); + tmp = affs_min(bsize - boff, to - from); memcpy(AFFS_DATA(bh) + boff, data + from, tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); affs_fix_checksum(sb, bh); @@ -731,7 +731,7 @@ bh = affs_bread_ino(inode, bidx, 1); if (IS_ERR(bh)) goto out; - tmp = MIN(bsize, to - from); + tmp = affs_min(bsize, to - from); memcpy(AFFS_DATA(bh), data + from, tmp); if (bh->b_state & (1UL << BH_New)) { AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); Index: fs/affs/namei.c =================================================================== RCS file: /cvsroot/linux-apus/2.3/fs/affs/namei.c,v retrieving revision 1.9 diff -u -r1.9 namei.c --- fs/affs/namei.c 2001/08/21 17:57:27 1.9 +++ fs/affs/namei.c 2001/08/30 13:38:25 @@ -81,7 +81,7 @@ return i; hash = init_name_hash(); - i = MIN(qstr->len, 30); + i = affs_min(qstr->len, 30); for (; i > 0; name++, i--) hash = partial_name_hash(toupper(*name), hash); qstr->hash = end_name_hash(hash); @@ -172,7 +172,7 @@ toupper_t toupper = affs_get_toupper(sb); int hash; - hash = len = MIN(len, 30); + hash = len = affs_min(len, 30); for (; len > 0; len--) hash = (hash * 13 + toupper(*name++)) & 0x7ff; ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 13:49 ` Roman Zippel @ 2001-08-30 16:21 ` Linus Torvalds 2001-08-30 16:41 ` Christopher Friesen ` (2 more replies) 0 siblings, 3 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-30 16:21 UTC (permalink / raw) To: Roman Zippel; +Cc: Daniel Phillips, David Lang, linux-kernel On Thu, 30 Aug 2001, Roman Zippel wrote: > > So why won't you let the compiler help you, even if it's not perfect in > every case? I considered enabling -Wsign-compare a long time ago, and it's not a question of being "perfect", but a question of being _so_ broken that it's not funny. For example, let's look at this perfectly natural code: static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp) { if (len <= sizeof(short) || len > sizeof(*sunaddr)) return -EINVAL; ... Would you agree that the above is _good_ code, and code that makes perfect sense, and code that does exactly the right thing in testing its arguments? Try to compile it with -Wsign-compare. You'll get not one, but TWO warnings for code that is totally correct, and that it would make _no_ sense in writing any other way. In short, -Wsign-compare (at least with a _lot_ of gcc versions) warns for totally sane and reasonable code - for code that exists all over the kernel. The above snippet is in fact directly from the kernel, go look and see for yourself. In short, -Wsign-compare is totally useless. The warnings are mostly _so_ bogus that nobody has the energy to even try to figure out which of them might actually be worthwhile. Face it, you don't know what you're talking about. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:21 ` Linus Torvalds @ 2001-08-30 16:41 ` Christopher Friesen 2001-08-30 16:50 ` Linus Torvalds 2001-08-30 17:13 ` Roman Zippel 2001-08-31 1:28 ` Ion Badulescu 2 siblings, 1 reply; 95+ messages in thread From: Christopher Friesen @ 2001-08-30 16:41 UTC (permalink / raw) To: Linus Torvalds; +Cc: Roman Zippel, Daniel Phillips, David Lang, linux-kernel Linus Torvalds wrote: > For example, let's look at this perfectly natural code: > > static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp) > { > if (len <= sizeof(short) || len > sizeof(*sunaddr)) > return -EINVAL; > ... > > Would you agree that the above is _good_ code, and code that makes > perfect sense, and code that does exactly the right thing in testing its > arguments? Wouldn't it have made more sense to make the 'len' parameter an unsigned int? Presumably we can't have a negative length for a name. In this case the warnings should just go away, no? -- Chris Friesen | MailStop: 043/33/F10 Nortel Networks | work: (613) 765-0557 3500 Carling Avenue | fax: (613) 765-2986 Nepean, ON K2H 8E9 Canada | email: cfriesen@nortelnetworks.com ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:41 ` Christopher Friesen @ 2001-08-30 16:50 ` Linus Torvalds 0 siblings, 0 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-30 16:50 UTC (permalink / raw) To: Christopher Friesen Cc: Roman Zippel, Daniel Phillips, David Lang, linux-kernel On Thu, 30 Aug 2001, Christopher Friesen wrote: > > Wouldn't it have made more sense to make the 'len' parameter an unsigned int? Oh yes. And wouldn't it be nicer if the sky was pink, and God came personally down to earth and stopped all wrans and made you king? You do realize that many things are signed, whether you want them to be or not? Like "off_t", which on the face of it sounds like it should be unsigned ("offset within a file - oh, that can obviously never be negative"). Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:21 ` Linus Torvalds 2001-08-30 16:41 ` Christopher Friesen @ 2001-08-30 17:13 ` Roman Zippel 2001-08-31 1:28 ` Ion Badulescu 2 siblings, 0 replies; 95+ messages in thread From: Roman Zippel @ 2001-08-30 17:13 UTC (permalink / raw) To: Linus Torvalds; +Cc: Daniel Phillips, David Lang, linux-kernel Hi, Linus Torvalds wrote: > static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp) > { > if (len <= sizeof(short) || len > sizeof(*sunaddr)) > return -EINVAL; > ... > > Would you agree that the above is _good_ code, and code that makes > perfect sense, and code that does exactly the right thing in testing its > arguments? Where is the problem to change the type into "unsigned int"? > Face it, you don't know what you're talking about. Sorry, but what makes you so sure about it? Anyway, forget -Wsign-compare, but could you _please_ give me an answer to my other arguments? Maybe I'm a stupid idiot, but then please enlighten me and show me the right way. So here is the important part of my mail again: This is my last attempt to get things IMO right. Most of the arguments for the new macro were about bugs of the past. No question about this, this had to be fixed, I'm not arguing about this at all. I'm trying to get your attention to the bugs of the future. I still don't understand why you think the new macro will be any better. Why do you think the average kernel hacker will think about the type of the compare and will come to the correct conclusion? It's far too easy to use an int as type argument and forget about it. gcc won't warn about this, so someone first has to hit this bug, before it gets fixed. Maybe I'm too dumb, but I still fail to see, what sense it should make to turn a signed compare into an unsigned one. Either one knows both signed values are only positive, then the sign of the compare and the destination doesn't matter at all. If the value could be negative, better test it explicit: if (len < 0 || len > MAX) len = MAX; First, it's far more readable and makes the intention so clear, that even your average kernel hacker understands it. Second, gcc produces exactly the same code with this, so there is no need to play type tricks with the min macro. Please reconsider your decision. IMVHO the new macros are a mistake and will cause only more trouble than they are worth. bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 16:21 ` Linus Torvalds 2001-08-30 16:41 ` Christopher Friesen 2001-08-30 17:13 ` Roman Zippel @ 2001-08-31 1:28 ` Ion Badulescu 2001-08-31 5:08 ` Linus Torvalds 2 siblings, 1 reply; 95+ messages in thread From: Ion Badulescu @ 2001-08-31 1:28 UTC (permalink / raw) To: Linus Torvalds; +Cc: linux-kernel On Thu, 30 Aug 2001 09:21:12 -0700 (PDT), Linus Torvalds <torvalds@transmeta.com> wrote: > For example, let's look at this perfectly natural code: > > static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp) > { > if (len <= sizeof(short) || len > sizeof(*sunaddr)) > return -EINVAL; > ... > > Would you agree that the above is _good_ code, and code that makes > perfect sense, and code that does exactly the right thing in testing its > arguments? Ugh. I must confess I am disappointed, Linus. I thought you had better taste. Yes, the above code is correct. And yes, gcc should be more aggressive to recognize that the above code is unambiguous. But that doesn't change the fact that the code is UGLY AS HELL. Nor does it change the fact that each comparison is broken if taken separately. You make two UNSIGNED comparisons when you clearly mean to make two SIGNED comparisons, and you call that _good_ code? Hmm. > Try to compile it with -Wsign-compare. > > You'll get not one, but TWO warnings for code that is totally correct, and > that it would make _no_ sense in writing any other way. Really? How so? We _know_ that the result of sizeof() fits confortably within "int"'s range. So the natural way to write that comparison would be if (len <= (int) sizeof(short) || len > (int) sizeof(*sunaddr)) which is 100% correct, 100% obvious, and does not break horribly if you remove one of the comparisons. The compiler also _knows_ that. But the compiler can't change the implicit cast, because it would make it incompatible with every other compiler on the planet. Yes, standards suck sometimes. So compiler warns us instead. I consider that a feature. Ion -- It is better to keep your mouth shut and be thought a fool, than to open it and remove all doubt. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 1:28 ` Ion Badulescu @ 2001-08-31 5:08 ` Linus Torvalds 2001-08-31 12:37 ` Jamie Lokier 0 siblings, 1 reply; 95+ messages in thread From: Linus Torvalds @ 2001-08-31 5:08 UTC (permalink / raw) To: Ion Badulescu; +Cc: linux-kernel On Thu, 30 Aug 2001, Ion Badulescu wrote: > > Really? How so? We _know_ that the result of sizeof() fits confortably within > "int"'s range. So the natural way to write that comparison would be > > if (len <= (int) sizeof(short) || len > (int) sizeof(*sunaddr)) You're so full of shit that it's incredible. I'mnot going to argue this, when people call stuff like the above the "natural way". This is not worth it. The fact is, the way gcc currently does things, -Wsign-compare is useless. Anybody who is honest would admit that. In order for the warning to become useful, gcc would need to do value range analysis - which people have been talking about, but which is not there yet. There have been some constructive comments here (the automatic detection of bad comparisons etc), but yours is just stupid. Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 5:08 ` Linus Torvalds @ 2001-08-31 12:37 ` Jamie Lokier 2001-08-31 13:54 ` Linus Torvalds 0 siblings, 1 reply; 95+ messages in thread From: Jamie Lokier @ 2001-08-31 12:37 UTC (permalink / raw) To: Linus Torvalds; +Cc: Ion Badulescu, linux-kernel Linus Torvalds wrote: > > if (len <= (int) sizeof(short) || len > (int) sizeof(*sunaddr)) > > You're so full of shit that it's incredible. > > I'mnot going to argue this, when people call stuff like the above the > "natural way". This is not worth it. While I agree with Linus that the above line is ugly, there is a problem with the original line: if (len <= sizeof(short) || len > sizeof(*sunaddr)) The problem? Thinking this is natural, suppose you decide you only need to check len against sizeof(short), perhaps here, perhaps copying this idea to another part of the program: if (len <= sizeof(short)) _This_ code has a bug. The comparison is unsigned; i.e. len is converted to unsigned int first, so if the user passes a negative value, the comparison returns false and the code will break. It only works in the original example because the second comparison checks the bogus results of the first one. Now, any later use of len should not lead to a buffer overflow or anything, because you always check against a maximum size for copying, yes? No. Consider this hypothetical code to copy things up to a page at a time. len is a signed type s.t. sizeof(len) <= sizeof(size_t): if (len <= sizeof(struct thing) || len > MAX_BUFFER_SIZE) { printk(KERN_ERR "Sanity check failed!\n"); goto out; } memcpy (to, from, len); Inexperienced C programmers, and sleepy ones, may not see the fault. cheers, -- Jamie ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-31 12:37 ` Jamie Lokier @ 2001-08-31 13:54 ` Linus Torvalds 0 siblings, 0 replies; 95+ messages in thread From: Linus Torvalds @ 2001-08-31 13:54 UTC (permalink / raw) To: Jamie Lokier; +Cc: Ion Badulescu, linux-kernel On Fri, 31 Aug 2001, Jamie Lokier wrote: > > While I agree with Linus that the above line is ugly, there is a problem > with the original line: > > if (len <= sizeof(short) || len > sizeof(*sunaddr)) > > The problem? Thinking this is natural, suppose you decide you only need > to check len against sizeof(short), perhaps here, perhaps copying this > idea to another part of the program: > > if (len <= sizeof(short)) > > _This_ code has a bug. I agree. The difference is subtle, and maybe too subtle. The fact is, that _ranges_ are "stable" in different types. If a value "x" is in the range [a,b] in type A, then it will also be in range [a,b] in type B (assuming, of course, that 'a' and 'b' are valid values in both types). This is why range comparisons are different from normal comparisons. But C doesn't have the notion of a range, which is why you can't write (while lots of people have _tried_ to write, including in the kernel) a < x < b or x in [a,b] or similar. So you end up having to use a more "complex" setup, where the individual parts might not be safe even though the totality is safe. In fact, if gcc never becomes good enough to do that kind of range checking, I won't be _too_ unhappy. I selected a special example on bad grounds - it's not actually the most common case of range checking, and the most common case by far tends to be something like if (len < 0) return -EINVAL; if (len > sizeof(buffer)) len = sizeof(buffer); copy_from_user(buffer, ..., len); where the operation is safe for _another_ range check reason, namely the fact that we check that "len" is within the domain of the second check. Right now gcc will complain about the second comparison, exactly because gcc does not do range analysis. Now, the good news is that gcc people have already worked on range analysis, because it is very useful for other things too (not the least of which is optimization). So I bet gcc _will_ be able to do a much better job of this in the future, and if we have to help it by hand in only a few places, then that will be a good thing. However, right now gcc complains _way_ too much about perfectly valid and good code. If it was a few small cases, I'd be happy to fix them in the kernel. But last time I tried -Wsign-compare, the false positives were just too damn numerous. (Now, we may have fixed some of them anyway, and I haven't tried it in a _loong_ time. If somebody decides to try to see what happens if you try to clean them up, that would probably not be a bad idea per se. Proving me wrong is always a good sport ;) Linus ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 3:28 ` Linus Torvalds 2001-08-30 13:10 ` Ion Badulescu 2001-08-30 13:49 ` Roman Zippel @ 2001-08-30 17:01 ` Daniel Phillips 2001-08-30 17:03 ` Peter T. Breuer 2001-08-30 21:16 ` Graham Murray 2 siblings, 2 replies; 95+ messages in thread From: Daniel Phillips @ 2001-08-30 17:01 UTC (permalink / raw) To: Linus Torvalds; +Cc: David Lang, Roman Zippel, linux-kernel On August 30, 2001 05:28 am, Linus Torvalds wrote: > On Thu, 30 Aug 2001, Daniel Phillips wrote: > > > > Yes, in the signed/unsigned case the comparison generated is always > > unsigned. > > Well... No. > > If you compare a signed integer with a unsigned char, the char gets > promoted to a _signed_ integer, and the comparison is signed. It is NOT > a unsigned comparison. Lets not go into how stupid that is. Yes, things changed between K&R editions 1 and 2, in a misguided attempt to make things less "surprising" the drafters just introduced additional confusion. > And THIS is one example of why it gets complicated. > > The C logic for type expansion is just a tad too easy to get wrong, and > the strict type-checking you normally have with well-written ANSI C simply > does not exist for integer types. The compiler will silently just do the > promotion.. > > Somebody mentioned -Wsign-compare. Try it with the example above. It won't > warn at all, exactly because under C both sides of such a compare have the > _same_ sign, even if one is a "unsigned char", and the other is a "signed > int". > > Try it yourself if you don't believe me. > > Please guys. The issue of sign in comparisons are a LOT more complicated > than most of you seem to think. More than anything, it shows that education is needed, not macro patch-ups. We have exactly the same issues with < and >, should we introduce three-argument macros to replace them? -- Daniel ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 17:01 ` Daniel Phillips @ 2001-08-30 17:03 ` Peter T. Breuer 2001-08-30 17:26 ` Daniel Phillips 2001-08-31 8:04 ` Kai Henningsen 2001-08-30 21:16 ` Graham Murray 1 sibling, 2 replies; 95+ messages in thread From: Peter T. Breuer @ 2001-08-30 17:03 UTC (permalink / raw) To: Daniel Phillips; +Cc: linux kernel "Daniel Phillips wrote:" > More than anything, it shows that education is needed, not macro patch-ups. > We have exactly the same issues with < and >, should we introduce > three-argument macros to replace them? # define le(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) == _a ; }) # define ge(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) == _b ; }) ;-) Peter ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 17:03 ` Peter T. Breuer @ 2001-08-30 17:26 ` Daniel Phillips 2001-08-31 8:04 ` Kai Henningsen 1 sibling, 0 replies; 95+ messages in thread From: Daniel Phillips @ 2001-08-30 17:26 UTC (permalink / raw) To: ptb; +Cc: linux kernel On August 30, 2001 07:03 pm, Peter T. Breuer wrote: > "Daniel Phillips wrote:" > > More than anything, it shows that education is needed, not macro patch-ups. > > We have exactly the same issues with < and >, should we introduce > > three-argument macros to replace them? > > # define le(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) == _a ; }) > # define ge(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) == _b ; }) Oh, you are one sick puppy. For completeness: # define lt(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) != _b ; }) # define gt(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) != _a ; }) -- Daniel ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 17:03 ` Peter T. Breuer 2001-08-30 17:26 ` Daniel Phillips @ 2001-08-31 8:04 ` Kai Henningsen 1 sibling, 0 replies; 95+ messages in thread From: Kai Henningsen @ 2001-08-31 8:04 UTC (permalink / raw) To: linux-kernel phillips@bonn-fries.net (Daniel Phillips) wrote on 30.08.01 in <20010830171934Z16012-32384+1116@humbolt.nl.linux.org>: > On August 30, 2001 07:03 pm, Peter T. Breuer wrote: > > "Daniel Phillips wrote:" > > > More than anything, it shows that education is needed, not macro > patch-ups. > > > We have exactly the same issues with < and >, should we introduce > > > three-argument macros to replace them? > > > > # define le(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) == _a ; }) > > # define ge(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) == _b ; }) > > Oh, you are one sick puppy. > > For completeness: > > # define lt(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) != _b ; }) > # define gt(t,a,b) ({ t _a = a; t _b = b; min(t,_a,_b) != _a ; }) Does it give the right answers for floating point? MfG Kai ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 17:01 ` Daniel Phillips 2001-08-30 17:03 ` Peter T. Breuer @ 2001-08-30 21:16 ` Graham Murray 2001-08-30 21:47 ` David Weinehall [not found] ` <mit.lcs.mail.linux-kernel/m266b51c5c.fsf@barnowl.demon.co.uk> 1 sibling, 2 replies; 95+ messages in thread From: Graham Murray @ 2001-08-30 21:16 UTC (permalink / raw) To: linux-kernel Daniel Phillips <phillips@bonn-fries.net> writes: > More than anything, it shows that education is needed, not macro patch-ups. > We have exactly the same issues with < and >, should we introduce > three-argument macros to replace them? Would it not have been much more "obvious" if the rules for unsigned/signed integer comparisons (irrespective of the widths involved) were 1) If the signed element is negative then it is always less than the unsigned element. 2) If the unsigned element is greater than then maximum positive value expressible by the signed one then it is always greater. 3) Only if both values are positive and within the range of the smaller element are the actual values compared. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 21:16 ` Graham Murray @ 2001-08-30 21:47 ` David Weinehall 2001-08-31 10:10 ` Helge Hafting [not found] ` <mit.lcs.mail.linux-kernel/m266b51c5c.fsf@barnowl.demon.co.uk> 1 sibling, 1 reply; 95+ messages in thread From: David Weinehall @ 2001-08-30 21:47 UTC (permalink / raw) To: Graham Murray; +Cc: linux-kernel On Thu, Aug 30, 2001 at 09:16:47PM +0000, Graham Murray wrote: > Daniel Phillips <phillips@bonn-fries.net> writes: > > > More than anything, it shows that education is needed, not macro patch-ups. > > We have exactly the same issues with < and >, should we introduce > > three-argument macros to replace them? > > Would it not have been much more "obvious" if the rules for > unsigned/signed integer comparisons (irrespective of the widths > involved) were > > 1) If the signed element is negative then it is always less than the > unsigned element. > > 2) If the unsigned element is greater than then maximum positive value > expressible by the signed one then it is always greater. > > 3) Only if both values are positive and within the range of the > smaller element are the actual values compared. Possibly, but changing the C specification is not really an option here... /David Weinehall _ _ // David Weinehall <tao@acc.umu.se> /> Northern lights wander \\ // Project MCA Linux hacker // Dance across the winter sky // \> http://www.acc.umu.se/~tao/ </ Full colour fire </ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-30 21:47 ` David Weinehall @ 2001-08-31 10:10 ` Helge Hafting 0 siblings, 0 replies; 95+ messages in thread From: Helge Hafting @ 2001-08-31 10:10 UTC (permalink / raw) To: David Weinehall, graham, linux-kernel David Weinehall wrote: > > On Thu, Aug 30, 2001 at 09:16:47PM +0000, Graham Murray wrote: > > Daniel Phillips <phillips@bonn-fries.net> writes: > > > > > More than anything, it shows that education is needed, not macro patch-ups. > > > We have exactly the same issues with < and >, should we introduce > > > three-argument macros to replace them? > > > > Would it not have been much more "obvious" if the rules for > > unsigned/signed integer comparisons (irrespective of the widths > > involved) were > > > > 1) If the signed element is negative then it is always less than the > > unsigned element. > > > > 2) If the unsigned element is greater than then maximum positive value > > expressible by the signed one then it is always greater. > > > > 3) Only if both values are positive and within the range of the > > smaller element are the actual values compared. > > Possibly, but changing the C specification is not really an option here... Even worse: most microprosessors don't do comparisons that way. They compare either two signed or two unsigned items and do that reasonably fast. This is why C also works this way. A compiler can be made to use the above standard, but it would generate slow code for all signed/unsigned compares because now there is 3 tests instead of one. This is why language designers don't do that. You can of course do this explicitly in code if you need that sort of comparison, e.g. signed a; unsigned b; if (a<0) case1() else if (b>MAX_SIGNED) case2() else if (a<b) case1() else case2(); A nice feature of C is that ugly time-consuming stuff tends to look ugly and time-consuming in code too. So it is easier to avoid. :-) Helge Hafting ^ permalink raw reply [flat|nested] 95+ messages in thread
[parent not found: <mit.lcs.mail.linux-kernel/m266b51c5c.fsf@barnowl.demon.co.uk>]
* Re: [IDEA+RFC] Possible solution for min()/max() war [not found] ` <mit.lcs.mail.linux-kernel/m266b51c5c.fsf@barnowl.demon.co.uk> @ 2001-08-30 22:26 ` Patrick J. LoPresti 0 siblings, 0 replies; 95+ messages in thread From: Patrick J. LoPresti @ 2001-08-30 22:26 UTC (permalink / raw) To: linux-kernel Graham Murray <graham@barnowl.demon.co.uk> writes: > Daniel Phillips <phillips@bonn-fries.net> writes: > > > More than anything, it shows that education is needed, not macro patch-ups. > > We have exactly the same issues with < and >, should we introduce > > three-argument macros to replace them? > > Would it not have been much more "obvious" if the rules for > unsigned/signed integer comparisons (irrespective of the widths > involved) were > > 1) If the signed element is negative then it is always less than the > unsigned element. > > 2) If the unsigned element is greater than then maximum positive value > expressible by the signed one then it is always greater. > > 3) Only if both values are positive and within the range of the > smaller element are the actual values compared. With infinite-precision arithmetic, yes; of course min() should just return the smaller value. But what would the C type of "min" be for comparing, say, signed and unsigned longs? The range of possible results does not fit in any integral type. (Repeat the question for signed/unsigned "long long" if "long long" is your answer.) - Pat ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 14:19 ` Roman Zippel 2001-08-28 15:14 ` Linus Torvalds @ 2001-08-28 16:09 ` Andreas Schwab 2001-08-28 16:47 ` Roman Zippel 2001-08-28 17:29 ` Richard B. Johnson 1 sibling, 2 replies; 95+ messages in thread From: Andreas Schwab @ 2001-08-28 16:09 UTC (permalink / raw) To: Roman Zippel; +Cc: Linus Torvalds, linux-kernel Roman Zippel <zippel@linux-m68k.org> writes: |> Hi, |> |> Linus Torvalds wrote: [...] |> > You just fixed the "re-use arguments" bug - which is a bug, but doesn't |> > address the fact that most of the min/max bugs are due to the programmer |> > _indending_ a unsigned compare because he didn't even think about the |> > type. |> |> You maybe fixed a few bugs, but this new macro will only cause new |> problems in the future. If we change only a single type, you have to |> scan all min/max users if they possibly need to be changed too. Thanks |> to the cast, the compiler won't even remotely help you finding them. There is no cast in the min/max macros. Andreas. -- Andreas Schwab "And now for something SuSE Labs completely different." Andreas.Schwab@suse.de SuSE GmbH, Schanzäckerstr. 10, D-90443 Nürnberg Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 16:09 ` Andreas Schwab @ 2001-08-28 16:47 ` Roman Zippel 2001-08-28 17:12 ` Bill Rugolsky Jr. 2001-08-28 17:29 ` Richard B. Johnson 1 sibling, 1 reply; 95+ messages in thread From: Roman Zippel @ 2001-08-28 16:47 UTC (permalink / raw) To: Andreas Schwab; +Cc: Linus Torvalds, linux-kernel Hi, Andreas Schwab wrote: > There is no cast in the min/max macros. Ok, it uses an assignment, but it has almost the same effect (except for pointer/integer values). bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 16:47 ` Roman Zippel @ 2001-08-28 17:12 ` Bill Rugolsky Jr. 2001-08-28 17:28 ` Roman Zippel 0 siblings, 1 reply; 95+ messages in thread From: Bill Rugolsky Jr. @ 2001-08-28 17:12 UTC (permalink / raw) To: Roman Zippel; +Cc: Andreas Schwab, Linus Torvalds, linux-kernel On Tue, Aug 28, 2001 at 06:47:23PM +0200, Roman Zippel wrote: > Ok, it uses an assignment, but it has almost the same effect (except for > pointer/integer values). Wrong. A cast throws away information, making meaningful warnings impossible. The assignment allows the compiler to apply the usual C integral promotions and catch narrowing and non-value-preserving conversions, like unsigned int to int, or an even more common bug, unsigned int to long, which behaves differently depending on whether long is 32 or 64 bits. Regards, Bill Rugolsky ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 17:12 ` Bill Rugolsky Jr. @ 2001-08-28 17:28 ` Roman Zippel 0 siblings, 0 replies; 95+ messages in thread From: Roman Zippel @ 2001-08-28 17:28 UTC (permalink / raw) To: Bill Rugolsky Jr.; +Cc: Andreas Schwab, Linus Torvalds, linux-kernel Hi, "Bill Rugolsky Jr." wrote: > > Ok, it uses an assignment, but it has almost the same effect (except for > > pointer/integer values). > > Wrong. A cast throws away information, making meaningful warnings impossible. > The assignment allows the compiler to apply the usual C integral > promotions and catch narrowing and non-value-preserving conversions, > like unsigned int to int, or an even more common bug, unsigned int to > long, which behaves differently depending on whether long is 32 or 64 > bits. Do you have an example? AFAIK this can only be done for constants and mosts constants used with min are within usual integer limits. bye, Roman ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-28 16:09 ` Andreas Schwab 2001-08-28 16:47 ` Roman Zippel @ 2001-08-28 17:29 ` Richard B. Johnson 1 sibling, 0 replies; 95+ messages in thread From: Richard B. Johnson @ 2001-08-28 17:29 UTC (permalink / raw) To: Andreas Schwab; +Cc: Roman Zippel, Linus Torvalds, linux-kernel On 28 Aug 2001, Andreas Schwab wrote: > Roman Zippel <zippel@linux-m68k.org> writes: > > |> Hi, > |> > |> Linus Torvalds wrote: > [...] > |> > You just fixed the "re-use arguments" bug - which is a bug, but doesn't > |> > address the fact that most of the min/max bugs are due to the programmer > |> > _indending_ a unsigned compare because he didn't even think about the > |> > type. #if 0 If the comparison was made unsigned, cast to the largest natural value on the target, while keeping the types and sizes of the input variables the same, this macro does about what 99.9999999 percent of what everybody wants: #endif #include <stdio.h> #define min(a,b) ((size_t)(a) < (size_t)(b) ? (a) : (b)) int main() { printf("%d\n", min(1,2)); printf("%d\n", min(-1,2)); printf("%d\n", min(0xffffffff,3)); printf("%d\n", min(0x8000,4)); printf("%d\n", min(0x7fff,5)); printf("%d\n", min(0x80000000,6)); printf("%d\n", min(0x7fffffff,7)); printf("%ld\n", min(1L,2L)); printf("%ld\n", min(-1L,2L)); printf("%ld\n", min(0xffffffff,3L)); printf("%ld\n", min(0x8000,4L)); printf("%ld\n", min(0x7fff,5L)); printf("%ld\n", min(0x80000000,6L)); printf("%ld\n", min(0x7fffffff,7L)); printf("%lu\n", min(1L,2LU)); printf("%lu\n", min(-1L,2LU)); printf("%lu\n", min(0xffffffff,3LU)); printf("%lu\n", min(0x8000,4LU)); printf("%lu\n", min(0x7fff,5LU)); printf("%lu\n", min(0x80000000,6LU)); printf("%lu\n", min(0x7fffffff,7LU)); printf("%d\n", min(-1, -2)); printf("%d\n", min(-1, 0)); printf("%p\n", min((void *)0x80000000, (void *)0x7fffffff)); return 0; } 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] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 0:53 ` Brad Chapman 2001-08-25 1:15 ` Alexander Viro @ 2001-08-26 17:59 ` Bill Pringlemeir 1 sibling, 0 replies; 95+ messages in thread From: Bill Pringlemeir @ 2001-08-26 17:59 UTC (permalink / raw) To: Brad Chapman; +Cc: Alexander Viro, linux-kernel >>>>> "Brad" == Brad Chapman <kakadu_croc@yahoo.com> writes: Brad> OK. The existing API is wrong and the new min()/max() macros Brad> are the right way to properly compare values. However, we could Brad> always add a config option to enable a compatibility macro, Brad> which would use typeof() on one of the two variables and then Brad> call the real min()/max(). Something like this (just an Brad> example): #ifdef CONFIG_ALLOW_COMPAT_MINMAX #define proper_min(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) #define proper_max(t, a, b) ((t)(a) > (t)(b) ? (a) : (b)) #define min(a, b) proper_min(typeof(a), a, b) #define max(a, b) proper_max(typeof(a), a, b) #else #define min(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) #define max(t, a, b) ((t)(a) < (t)(b) ? (a) : (b)) #endif Conditionals are bad. Casting is bad. In my opinion the only semantically correct version would be something like this, #define min(x,y) \ \ ({typeof(x) _x = 0; typeof(y) _y = 0; \ if ((_x-1>0 && _y-1<0) || (_x-1<0 && _y-1>0)) { \ if((x) < 0 || (y) < 0) \ exit(SIGNED_UNSIGNED_CONFLICT); \ } \ _x = (x), _y = (y); (_x>_y)?_y:_x; \ }) I think that if you are mixing signed and unsigned you should have had a check before hand to gaurentee that any casting away of the sign is ok. It is ok if the variable is in range, it is not if they are out of range. However, this incurs a runtime check which is not appropriate for kernel level code. As several other people have noted, the casting is bad from a maintainability prospective. This is slapping your best friend in the face; the compiler. Also, the three arg macro breaks compatibility with a long standing `C' min/max macro convention. Probably we should just shutup for now until Linus can clarify what it is that he wants to achieve and avoid. Since there is probably no way to make a universally correct min/max macro in `C', you need to have some sort of goal to achieve. regards, Bill Pringlemeir. ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-24 23:21 ` Ben LaHaise 2001-08-24 23:58 ` Brad Chapman @ 2001-08-24 23:59 ` Brad Chapman 2001-08-25 0:07 ` David S. Miller 2 siblings, 0 replies; 95+ messages in thread From: Brad Chapman @ 2001-08-24 23:59 UTC (permalink / raw) To: Ben LaHaise; +Cc: linux-kernel --- Ben LaHaise <bcrl@redhat.com> wrote: > On Fri, 24 Aug 2001, Brad Chapman wrote: > > > This way, some hackers can use the two-arg min()/max() inside an #ifdef block, > > other hackers can use the three-arg min()/max() inside an #ifdef block, > > and people who don't care can select either. > > Have you no taste? Use of #ifdef's should be minimised as much as > possible. For this kind of construct, the spurious preprocessor usage > just makes me want to vomit. > > -ben Mr. LaHaise, Eeek! Sorry. That was just a preliminary. As I see it, there are several ways to wire this up: - make everyone use the new macros (some people are thinking :P) - make everyone use #ifdef blocks with a config option (you think it's :P) - make min()/max() typeof() wrappers for a switch-style stack of comparison functions which work on the various types, i.e: __u8 minimum = min(one, two) -> __u8 minimum = __u8_min(one, two) (this may be too complex and is probably :P) - make min()/max() inline functions, cast things to void, and use memcmp() (this sounds reasonable, but is probably also :P) - stay with the old-style macros (:P, :P, :P) What do you think, sir? Brad ===== Brad Chapman Permanent e-mail: kakadu_croc@yahoo.com Current e-mail: kakadu@adelphia.net Alternate e-mail: kakadu@netscape.net __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-24 23:21 ` Ben LaHaise 2001-08-24 23:58 ` Brad Chapman 2001-08-24 23:59 ` Brad Chapman @ 2001-08-25 0:07 ` David S. Miller 2001-08-25 0:18 ` Brad Chapman 2001-08-25 0:23 ` David S. Miller 2 siblings, 2 replies; 95+ messages in thread From: David S. Miller @ 2001-08-25 0:07 UTC (permalink / raw) To: kakadu_croc; +Cc: bcrl, linux-kernel From: Brad Chapman <kakadu_croc@yahoo.com> Date: Fri, 24 Aug 2001 16:59:27 -0700 (PDT) - stay with the old-style macros (:P, :P, :P) I've been trying to stay out of this until Linus returns and has his word... but I can say with a level of certainty that this won't sit well with Linus at all. Later, David S. Miller davem@redhat.com ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 0:07 ` David S. Miller @ 2001-08-25 0:18 ` Brad Chapman 2001-08-25 0:23 ` David S. Miller 1 sibling, 0 replies; 95+ messages in thread From: Brad Chapman @ 2001-08-25 0:18 UTC (permalink / raw) To: David S. Miller; +Cc: linux-kernel --- "David S. Miller" <davem@redhat.com> wrote: > From: Brad Chapman <kakadu_croc@yahoo.com> > Date: Fri, 24 Aug 2001 16:59:27 -0700 (PDT) > > - stay with the old-style macros (:P, :P, :P) > > I've been trying to stay out of this until Linus returns > and has his word... but I can say with a level of certainty > that this won't sit well with Linus at all. > > Later, > David S. Miller > davem@redhat.com Mr. Miller, Ack. When Linus returns, I'm sure he'll give us all very good reasons why he thought it needed to be changed. BTW, what is your opinion on the various ways I suggested to satisfy people over the min()/max() issue? Mr. LaHaise nearly threw up when I suggested using #ifdef, so we can safely scratch that one ;-). What do you think, sir? Brad ===== Brad Chapman Permanent e-mail: kakadu_croc@yahoo.com Current e-mail: kakadu@adelphia.net Alternate e-mail: kakadu@netscape.net __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/ ^ permalink raw reply [flat|nested] 95+ messages in thread
* Re: [IDEA+RFC] Possible solution for min()/max() war 2001-08-25 0:07 ` David S. Miller 2001-08-25 0:18 ` Brad Chapman @ 2001-08-25 0:23 ` David S. Miller 1 sibling, 0 replies; 95+ messages in thread From: David S. Miller @ 2001-08-25 0:23 UTC (permalink / raw) To: kakadu_croc; +Cc: linux-kernel From: Brad Chapman <kakadu_croc@yahoo.com> Date: Fri, 24 Aug 2001 17:18:44 -0700 (PDT) What do you think, sir? Like I said, I'd like to defer to Linus until he has his word. I should not have said anything at all... Later, David S. Miller davem@redhat.com ^ permalink raw reply [flat|nested] 95+ messages in thread
end of thread, other threads:[~2001-09-07 18:03 UTC | newest]
Thread overview: 95+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-08-24 22:42 [IDEA+RFC] Possible solution for min()/max() war Brad Chapman
2001-08-24 23:21 ` Ben LaHaise
2001-08-24 23:58 ` Brad Chapman
2001-08-25 0:13 ` Alexander Viro
2001-08-25 0:25 ` Brad Chapman
2001-08-25 0:34 ` Alexander Viro
2001-08-25 0:53 ` Brad Chapman
2001-08-25 1:15 ` Alexander Viro
2001-08-25 11:21 ` Brad Chapman
2001-08-27 0:02 ` Rusty Russell
2001-08-28 4:59 ` Linus Torvalds
2001-08-28 5:20 ` Alexander Viro
2001-08-28 5:51 ` Linus Torvalds
2001-08-28 11:10 ` Alan Cox
2001-08-28 14:15 ` Linus Torvalds
2001-08-28 20:06 ` John Alvord
2001-08-28 12:42 ` Roman Zippel
2001-08-28 13:27 ` Linus Torvalds
2001-08-28 14:19 ` Roman Zippel
2001-08-28 15:14 ` Linus Torvalds
2001-08-28 15:44 ` Henning P. Schmiedehausen
2001-08-28 15:55 ` Russell King
2001-08-28 16:05 ` Alan Cox
2001-08-28 16:53 ` Roman Zippel
2001-08-28 16:39 ` Roman Zippel
2001-08-28 21:51 ` Mike Castle
2001-08-29 0:33 ` Daniel Phillips
2001-08-29 1:13 ` Linus Torvalds
2001-08-29 15:42 ` Daniel Phillips
2001-08-29 16:02 ` David Lang
2001-08-29 23:49 ` Daniel Phillips
2001-08-30 2:05 ` Bill Rugolsky Jr.
2001-08-30 3:28 ` Linus Torvalds
2001-08-30 13:10 ` Ion Badulescu
2001-08-30 13:17 ` David Woodhouse
2001-08-30 13:26 ` Ion Badulescu
2001-08-30 16:09 ` Linus Torvalds
2001-08-30 16:28 ` Ion Badulescu
2001-08-31 12:50 ` Jamie Lokier
2001-08-31 13:45 ` Roman Zippel
2001-08-31 16:27 ` Jamie Lokier
2001-08-30 16:31 ` Ben LaHaise
2001-08-30 16:38 ` Peter T. Breuer
2001-08-30 19:51 ` David Weinehall
2001-08-30 20:16 ` Peter T. Breuer
2001-08-30 20:31 ` Daniel Phillips
[not found] ` <mit.lcs.mail.linux-kernel/200108301638.SAA04923@nbd.it.uc3m.es>
2001-08-30 22:42 ` Patrick J. LoPresti
2001-08-30 23:27 ` Peter T. Breuer
2001-08-31 0:55 ` Linus Torvalds
2001-08-31 1:28 ` Peter T. Breuer
2001-08-31 13:22 ` Peter T. Breuer
2001-08-31 14:02 ` Linus Torvalds
2001-08-31 15:34 ` Peter T. Breuer
2001-08-31 22:25 ` [PATCH] i386 SA_INTERRUPT logic Jonathan Lundell
2001-08-31 12:01 ` [IDEA+RFC] Possible solution for min()/max() war Roman Zippel
2001-08-31 12:13 ` Peter T. Breuer
2001-08-31 12:58 ` Roman Zippel
2001-08-31 13:29 ` Peter T. Breuer
2001-08-31 14:12 ` Roman Zippel
2001-08-31 14:28 ` Peter T. Breuer
2001-08-31 16:30 ` Roman Zippel
2001-09-07 0:52 ` Bill Pringlemeir
2001-09-07 7:26 ` Peter T. Breuer
2001-09-07 12:28 ` Horst von Brand
2001-09-07 18:03 ` Mark H. Wood
2001-09-07 10:58 ` Peter T. Breuer
2001-09-07 14:39 ` Bill Pringlemeir
2001-09-07 15:17 ` Peter T. Breuer
2001-08-30 13:49 ` Roman Zippel
2001-08-30 16:21 ` Linus Torvalds
2001-08-30 16:41 ` Christopher Friesen
2001-08-30 16:50 ` Linus Torvalds
2001-08-30 17:13 ` Roman Zippel
2001-08-31 1:28 ` Ion Badulescu
2001-08-31 5:08 ` Linus Torvalds
2001-08-31 12:37 ` Jamie Lokier
2001-08-31 13:54 ` Linus Torvalds
2001-08-30 17:01 ` Daniel Phillips
2001-08-30 17:03 ` Peter T. Breuer
2001-08-30 17:26 ` Daniel Phillips
2001-08-31 8:04 ` Kai Henningsen
2001-08-30 21:16 ` Graham Murray
2001-08-30 21:47 ` David Weinehall
2001-08-31 10:10 ` Helge Hafting
[not found] ` <mit.lcs.mail.linux-kernel/m266b51c5c.fsf@barnowl.demon.co.uk>
2001-08-30 22:26 ` Patrick J. LoPresti
2001-08-28 16:09 ` Andreas Schwab
2001-08-28 16:47 ` Roman Zippel
2001-08-28 17:12 ` Bill Rugolsky Jr.
2001-08-28 17:28 ` Roman Zippel
2001-08-28 17:29 ` Richard B. Johnson
2001-08-26 17:59 ` Bill Pringlemeir
2001-08-24 23:59 ` Brad Chapman
2001-08-25 0:07 ` David S. Miller
2001-08-25 0:18 ` Brad Chapman
2001-08-25 0:23 ` David S. Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®