Fix signed integer overflow detection in f_expand_number() of strings.subr.

Approved by:	re (glebius)
This commit is contained in:
Devin Teske 2013-10-12 19:52:27 +00:00
parent 64945a9e27
commit 9acbeddc57

View File

@ -341,17 +341,19 @@ f_shell_unescape()
#
# NOTE: Prefixes are case-insensitive.
#
# Upon successful completion, the value 0 is returned (or stored to
# $var_to_set); otherwise -1. Reasons for a -1 return include:
# Upon successful completion, success status is returned; otherwise the number
# -1 is produced ($var_to_set set to -1 or if $var_to_set is NULL or missing)
# on standard output. In the case of failure, the error status will be one of:
#
# Given $string contains no digits.
# An unrecognized prefix was given.
# Result too large to calculate.
# Status Reason
# 1 Given $string contains no digits
# 2 An unrecognized prefix was given
# 3 Result too large to calculate
#
f_expand_number()
{
local __string="$1" __var_to_set="$2"
local __cp __num
local __cp __num __bshift __maxinput
# Remove any leading non-digits
while :; do
@ -360,14 +362,14 @@ f_expand_number()
[ "$__string" = "$__cp" ] && break
done
# Return `-1' if string didn't contain any digits
# Produce `-1' if string didn't contain any digits
if [ ! "$__string" ]; then
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" -1
else
echo -1
fi
return $FAILURE
return 1 # 1 = "Given $string contains no digits"
fi
# Store the numbers
@ -390,9 +392,23 @@ f_expand_number()
[ "$__string" = "$__cp" ] && break
done
# Test for invalid prefix
#
# Test for invalid prefix (and determine bitshift length)
#
case "$__string" in
""|[KkMmGgTtPpEe]*) : known prefix ;;
""|[[:space:]]*) # Shortcut
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" $__num
else
echo $__num
fi
return $SUCCESS ;;
[Kk]*) __bshift=10 ;;
[Mm]*) __bshift=20 ;;
[Gg]*) __bshift=30 ;;
[Tt]*) __bshift=40 ;;
[Pp]*) __bshift=50 ;;
[Ee]*) __bshift=60 ;;
*)
# Unknown prefix
if [ "$__var_to_set" ]; then
@ -400,29 +416,23 @@ f_expand_number()
else
echo -1
fi
return $FAILURE
return 2 # 2 = "An unrecognized prefix was given"
esac
# Multiply the number out
case "$__string" in
[Kk]) __num=$(( $__num * 1024 )) ;;
[Mm]) __num=$(( $__num * 1048576 )) ;;
[Gg]) __num=$(( $__num * 1073741824 )) ;;
[Tt]) __num=$(( $__num * 1099511627776 )) ;;
[Pp]) __num=$(( $__num * 1125899906842624 )) ;;
[Ee]) __num=$(( $__num * 1152921504606846976 )) ;;
esac
if [ $__num -le 0 ]; then
# Arithmetic overflow
# Determine if the wheels fall off
__maxinput=$(( 0x7fffffffffffffff >> $__bshift ))
if [ $__num -gt $__maxinput ]; then
# Input (before expanding) would exceed 64-bit signed int
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" -1
else
echo -1
fi
return $FAILURE
return 3 # 3 = "Result too large to calculate"
fi
# Return the number
# Shift the number out and produce it
__num=$(( $__num << $__bshift ))
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" $__num
else