Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Preserve locals before entering control flow during compilation (#945)
* add some regression tests * rename tests * simplify expression test * add commented out ideal and correct codegen * move checks into sync_local_refs * implement naive local preservation This implements naive local preservation in order to see if this fixes the problems with ffmpeg.wasm. This is not efficient during compilation, introduces new attack surfaces at compilation and produces inefficient code. After asserting that this indeed fixes the issues without major performance loss the following needs to happen: 1. We need a new data structure for locals on the compilation stack to efficiently cope with the fact that all locals on the stack need to be preserved frequently, not just a single local. 2. We need to find a way to reduce dynamic allocations in FuncTranslator::preserve_locals. 3. We need to merge copies whenever possible. Since preservation register indices are contiguous we should be able to encode fused copy instructions instead of many single copy instructions. * adjust new tests to reflect changes Seems like the fixes applied to the tests as expected. * new formatting for conditional preserve tests * add if based local preservation tests * apply rustfmt * apply clippy suggestion * do local preservation after input copy for loops * adjust existing translation tests for new codegen * use local register instead of local index * remove local preservation before loops While coming up with test cases I couldn't find a single one that would have invalid behavior before these changes. This is because with only a loop control flow structure there is no way to skip certain parts without using block or if control flow structures within the loop body. Someone please proof me wrong. Getting rid of as many local preservations is good for performance if not needed. * introduce TranslationBuffers type This is to unify reusable utility buffers of the Wasmi translator. * reuse preserved locals buffer * add clear before buffer usage This is probably not needed but an additional safety guard * make encode_copies return Option<Instr> This is so that the caller can use its encoded root instruction index for notification of preservation in a future commit. * improve debug_assert in notify_preserved_register Relax its allowed copy instructions since this is going to be needed with fused copies of local preservation instructions. * decrease the first preservation slot index by 1 This fixes a bug with RegisterSpanIter going out of bounds when trying to create a register span that starts with the initial preservation register before its index is being defragmented which caused an i16 integer overflow. Note: we could have also altered the implementation of RegisterSpanIter, however, this would have decreased its efficiency eventually which was less desirable. * fuse copies for local preservation upon entering blocks or ifs * make use of slice-group-by no_std support * consider copy-span encodings for local preservation * add more local preservation tests with more locals * shift method up * count locals on the compilation stack This removes a potential attack vector with a malicous Wasm file having lots of values on the compilation stack and a series of blocks or ifs that each have to preserve all locals on the compilation stack. In order to further improve the attack vector resistance we also need to preserve locals on the compilation stack in reverse order of their appearance, e.g. as the compilation stack would have popped from. This commit also contains some needed cleanups. * avoid heap memory allocation in preserve_all_locals_inplace Since this method is only called for small heaps we can get away by using an ArrayVec and linear search instead of using a BTreeMap. * reverse order of local preservation This softens certain non-critical attack vectors on the small stack mode implementation. * add local preservation tests with params * make LocalRefs more resistant to malicious attackers * fix internal doc links * fix bug in new LocalRefs impl * add conditional preserve with 30 stacked locals
- Loading branch information