Fix signed integer overflow detection in f_expand_number() of strings.subr.
Approved by: re (glebius)
This commit is contained in:
parent
64945a9e27
commit
9acbeddc57
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user