diff options
author | Mikael Pettersson <[email protected]> | 2015-02-04 20:27:37 +0100 |
---|---|---|
committer | Mikael Pettersson <[email protected]> | 2015-02-04 20:27:37 +0100 |
commit | 7e147a05683c709128b6777d0c360fcde067f567 (patch) | |
tree | 370b8fd2856d4e4b1fd88697ea4e7bee0658b59a /erts/emulator/beam/erl_bits.c | |
parent | 42d6afe554e11813385dbf175fce58f995c2f9e5 (diff) | |
download | otp-7e147a05683c709128b6777d0c360fcde067f567.tar.gz otp-7e147a05683c709128b6777d0c360fcde067f567.tar.bz2 otp-7e147a05683c709128b6777d0c360fcde067f567.zip |
don't create oversize bignums in binary matching
Bignums are artifically restricted in size. Arithmetic and logical
operations check the sizes of resulting bignums, and turn oversize
results into system_limit exceptions.
However, this check is not performed when bignums are constructed by
binary matching. The consequence is that such matchings can construct
oversize bignums that satisfy is_integer/1 yet don't work. Performing
arithmetic such as Term - 0 fails with a system_limit exception. Worse,
performing a logical operation such as Term band Term results in [].
The latter occurs because the size checking (e.g. in erts_band()) is
a simple ASSERT(is_not_nil(...)) on the result of the bignum operation,
which internally is [] (NIL) in the case of oversize results. However,
ASSERT is a no-op in release builds, so the error goes unnoticed and []
is returned as the result of the band/2.
This patch addresses this by preventing oversize bignums from entering
the VM via binary matching:
- the internal bytes_to_big() procedure is augmented to return NIL for
oversize results, just like big_norm()
- callers of bytes_to_big() are augmented to check for NIL returns and
signal errors in those cases
- erts_bs_get_integer_2() can only fail with badmatch, so that is the
Erlang-level result of oversize bignums from binary matches
- big_SUITE.erl is extended with a test case that fails without this
fix (no error signalled) and passes with it (badmatch occurs)
Credit goes to Nico Kruber for the initial bug report.
Diffstat (limited to 'erts/emulator/beam/erl_bits.c')
-rw-r--r-- | erts/emulator/beam/erl_bits.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c index 73765772c8..642f56a15e 100644 --- a/erts/emulator/beam/erl_bits.c +++ b/erts/emulator/beam/erl_bits.c @@ -403,7 +403,9 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff words_needed = 1+WSIZE(bytes); hp = HeapOnlyAlloc(p, words_needed); res = bytes_to_big(LSB, bytes, sgn, hp); - if (is_small(res)) { + if (is_nil(res)) { + res = THE_NON_VALUE; + } else if (is_small(res)) { p->htop = hp; } else if ((actual = bignum_header_arity(*hp)+1) < words_needed) { p->htop = hp + actual; |