This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
handy.h: Make inRANGE more robust
authorKarl Williamson <khw@cpan.org>
Sat, 20 Apr 2019 06:17:42 +0000 (00:17 -0600)
committerKarl Williamson <khw@cpan.org>
Sat, 20 Apr 2019 06:33:19 +0000 (00:33 -0600)
commit94250c4fc8bd70e90985c18c6eeb4257b56420e9
treef09ee39c25fa9f26a9624a4d179885f2d75822a4
parentb9893ba58d9656b9b5f2a5a6998b77dc16542ef7
handy.h: Make inRANGE more robust

It turns out that in order to make this work or assert if it won't, it
needs to be more complicated.  The problem has to do with signed and
unsigned operands.  It now special cases where the item being checked to
be in the range is a char, and casts that to a U8.  Otherwise, there is
a problem when that is a negative signed type and the range is above the
int_max for that type.  An assert is added to detect this rare event
(not rare for chars, hence the special case).  The use of sizeof() for
this case means that it will be resolved at compile time and not
generate extra code.  I did an experiment, and gcc even under -O0
compiled away the sizeof() clause.

As an example of why this is needed, suppose we have a signed char,
-127, and we want to see if it is in the range 128-130, expressed as
ints.  Without casting that -127 to an unsigned char, it would subtract
128 from -127, yield -255, which when cast to an unsigned int would be
wrong.  But casting the -127 to U8 first yields 129, and gives the
correct result.  The same issue could happen wih ints if the range is
above INT_MAX, but that is a much rarer case, and this macro asserts
against it.
handy.h