[PATCH] improve checks on usernames V3.

Matthias Andree mandree at FreeBSD.org
Wed Aug 10 11:58:44 UTC 2011


Am 10.08.2011 13:24, schrieb Harald Becker:
>  Hallo Denys!
> 
>> On Tue, Aug 9, 2011 at 7:33 PM, Rich Felker <dalias at aerifal.cx> wrote:
>>> On Tue, Aug 09, 2011 at 09:37:58AM +0200, Denys Vlasenko wrote:
>>>> #define isalnum(a) bb_ascii_isalnum(a)
>>>> static ALWAYS_INLINE int bb_ascii_isalnum(unsigned char a)
>>>> {
>>>>         unsigned char b = a - '0';
>>>>         if (b <= 9)
>>>>                 return (b <= 9);
>>>>         b = (a|0x20) - 'a';
>>>>         return b <= 'z' - 'a';
>>>> }
>>> I'm scared to ask why this is written in such an obfuscated way rather
>>> than just
>>>
>>> return a-'0'<10U || (a|32)-'a'<26U;
>> Tried it. Bloatcheck:
>> [...]
> 
> FYI: I tried it too ... test this version:
> 
> return (unsigned char)(a-'0')<10U || (unsigned char)((a|32)-'a')<26U;
> 
> ... may look obscure, but influences the way gcc produces code! May be
> you need to fiddle with type casting the other arguments in the
> expression :-(

Nothing in that is obscure, the answer is in the "integral promotion"
rules of C which is what required the extension from unsigned char to
unsigned int, hence the movz* commands in Denys's sample.

It pays to read the C and Unix standard, and you'll figure that the
simpler version causes implicit promotion to "unsigned int" - and note
that the C standard ctype.h signature demands "int interpreted as
unsigned char, or EOF". This sidesteps lots of the problems observed
here because no conversion happens inside the forcibly inlined
bb_ascii_alnum...


More information about the busybox mailing list