aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2016-04-13 16:22:31 +0200
committerBjörn Gustavsson <[email protected]>2016-04-14 10:38:32 +0200
commite72f710ae493cf7ba5da375632b096830df2de5c (patch)
treef539555fc91938e4a5cc96d5d8cc3f3a382f6859 /erts/emulator
parent19f231024d5fc4e0e7084b6b38ca404f3368844a (diff)
downloadotp-e72f710ae493cf7ba5da375632b096830df2de5c.tar.gz
otp-e72f710ae493cf7ba5da375632b096830df2de5c.tar.bz2
otp-e72f710ae493cf7ba5da375632b096830df2de5c.zip
Correct unpacking of 3 operands on 32-bit archictectures
0a4750f91c83 optimized unpacking by removing a mask operation when unpacking three packed operands. Unfortunately, that optimization is only safe on 64-bit architectures. Here is what happens on 32-bit architectures. The operands to be packed are 10-bit register numbers that have been turned into byte offsets: aaaaaaaaaa00 bbbbbbbbbb00 cccccccccc00 They can be packed into a single word like this: 30 20 10 0 | | | | aa aaaaaaaabb bbbbbbbbcc cccccccc00 If we call the packed word P, the original operands can be extracted like this: C = P band 2#111111111100 B = (P bsr 10) band 2#111111111100 A = (P bsr 20) band 2#111111111100 The bug was that A was extracted without the masking: A = P bsr 20 That would give A the value: aaaaaaaaaaaabb That would only be safe if the two most significant bits in B were zeroes.
Diffstat (limited to 'erts/emulator')
-rwxr-xr-xerts/emulator/utils/beam_makeops3
1 files changed, 2 insertions, 1 deletions
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index 31cd072d5a..24eace9fc4 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -48,7 +48,7 @@ $pack_shift[4] = ['0', 'BEAM_LOOSE_SHIFT', # Only for 64 bit wordsize
'(3*BEAM_LOOSE_SHIFT)'];
$pack_mask[2] = ['BEAM_LOOSE_MASK', $WHOLE_WORD];
-$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', $WHOLE_WORD];
+$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK'];
$pack_mask[4] = ['BEAM_LOOSE_MASK', # Only for 64 bit wordsize
'BEAM_LOOSE_MASK',
'BEAM_LOOSE_MASK',
@@ -251,6 +251,7 @@ $args_per_word[5] = 3;
$args_per_word[6] = 3;
if ($wordsize == 64) {
+ $pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', $WHOLE_WORD];
$args_per_word[4] = 4;
}