From c83dee07b73f8c23e7054d27e86f7172e6fb3569 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Dec 2020 07:57:47 -0800 Subject: [PATCH] Fix a memory reservation bug in `reserve_modules` This method attempted to reserve space in the `results` list of final modules. Unfortunately `results.reserve(nmodules)` isn't enough here because this can be called many times before a module is actually finished and pushed onto the vector. The attempted logic to work around this was buggy, however, and would simply trigger geometric growth on every single reservation because it erroneously assumed that a reservation would be exactly met. This is fixed by avoiding looking at the vector's capacity and instead keeping track of modules-to-be in a side field. This is the incremented and passed to `reserve` as it represents the number of modules that will eventually make their way into the result vector. --- crates/environ/src/module_environ.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 6d36b4e7a9..7b2cca6110 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -31,6 +31,10 @@ pub struct ModuleEnvironment<'data> { /// the module linking proposal. results: Vec>, + /// How many modules that have not yet made their way into `results` which + /// are coming at some point. + modules_to_be: usize, + /// Intern'd types for this entire translation, shared by all modules. types: TypeTables, @@ -138,6 +142,7 @@ impl<'data> ModuleEnvironment<'data> { Self { result: ModuleTranslation::default(), results: Vec::with_capacity(1), + modules_to_be: 1, cur: 0, types: Default::default(), target_config, @@ -741,8 +746,8 @@ and for re-adding support for interface types you can see this issue: fn reserve_modules(&mut self, amount: u32) { // Go ahead and reserve space in the final `results` array for `amount` // more modules. - let extra = self.results.capacity() + (amount as usize) - self.results.len(); - self.results.reserve(extra); + self.modules_to_be += amount as usize; + self.results.reserve(self.modules_to_be); // Then also reserve space in our own local module's metadata fields // we'll be adding to. @@ -796,6 +801,7 @@ and for re-adding support for interface types you can see this issue: self.cur = index; assert_eq!(index, self.results.len()); self.results.push(prev); + self.modules_to_be -= 1; } fn module_end(&mut self, index: usize) {