Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hygiene transform leaks memory #9126

Closed
nathanwhit opened this issue Jul 3, 2024 · 1 comment · Fixed by #9136
Closed

Hygiene transform leaks memory #9126

nathanwhit opened this issue Jul 3, 2024 · 1 comment · Fixed by #9136
Assignees
Labels
Milestone

Comments

@nathanwhit
Copy link

nathanwhit commented Jul 3, 2024

Describe the bug

The hygiene transform has a memory leak where some hstr::Entrys are never freed. A reproducer can be found here: https://github.com/nathanwhit/swc-memory-leak-repro. It just parses a simple program and then runs the hygiene transform over it. Running with miri (as suggested in the readme of the repro) points out a memory leak.

Input code

No response

Config

No response

Playground link (or link to the minimal reproduction)

https://github.com/nathanwhit/swc-memory-leak-repro

SWC Info output

No response

Expected behavior

The transform runs and frees all memory allocated once it is complete.

Actual behavior

No response

Version

swc_ecma_transforms_base = "0.140.1"

Additional context

Running the linked reproducer with miri points out the memory leak:
error: memory leaked: alloc6124 (Rust heap, size: 48, align: 8), allocated here:
   --> /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/alloc.rs:100:9
    |
100 |         __rust_alloc(layout.size(), layout.align())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: BACKTRACE:
    = note: inside `std::alloc::alloc` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/alloc.rs:243:9: 243:39
    = note: inside `alloc::alloc::exchange_malloc` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/alloc.rs:332:11: 332:34
    = note: inside `std::boxed::Box::<triomphe::arc::ArcInner<hstr::dynamic::Entry>>::new` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/boxed.rs:260:9: 260:20
    = note: inside `triomphe::arc::Arc::<hstr::dynamic::Entry>::new` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/triomphe-0.1.13/src/arc.rs:81:33: 84:11
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:169:21: 174:23
    = note: inside `hashbrown::map::RawEntryMut::<'_, triomphe::arc::Arc<hstr::dynamic::Entry>, (), std::hash::BuildHasherDefault<hstr::dynamic::EntryHasher>>::or_insert_with::<{closure@<&mut hstr::dynamic::AtomStore as hstr::dynamic::Storage>::insert_entry::{closure#1}}>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hashbrown-0.14.5/src/map.rs:3430:30: 3430:39
    = note: inside `<&mut hstr::dynamic::AtomStore as hstr::dynamic::Storage>::insert_entry` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:163:26: 177:15
    = note: inside `hstr::dynamic::new_atom::<&mut hstr::dynamic::AtomStore>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:142:17: 142:49
    = note: inside `hstr::dynamic::AtomStore::atom::<'_, std::borrow::Cow<'_, str>>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:119:9: 119:36
    = note: inside `swc_atoms::AtomStore::atom::<'_, std::borrow::Cow<'_, str>>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.7/src/lib.rs:230:14: 230:28
    = note: inside `swc_atoms::AtomStoreCell::atom::<'_, &str>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.7/src/lib.rs:247:18: 247:41
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:769:42: 769:57
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:897:17: 897:58
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::with_buf::<{closure@swc_ecma_parser::lexer::Lexer<'_>::read_word_as_str_with<{closure@swc_ecma_parser::lexer::Lexer<'_>::read_word_with::{closure#0}}, swc_ecma_parser::token::Word>::{closure#0}}, (swc_ecma_parser::token::Word, bool)>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:175:9: 175:27
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::read_word_as_str_with::<{closure@swc_ecma_parser::lexer::Lexer<'_>::read_word_with::{closure#0}}, swc_ecma_parser::token::Word>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:799:9: 910:11
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::read_word_with` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:762:34: 770:11
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/table.rs:89:5: 96:7
    = note: inside `<{closure@swc_ecma_parser::lexer::table::L_C::{closure#0}} as std::ops::FnOnce<(&mut swc_ecma_parser::lexer::Lexer<'_>,)>>::call_once - shim` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5: 250:71
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::read_token` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:188:30: 188:43
    = note: inside `swc_ecma_parser::lexer::state::<impl swc_ecma_parser::lexer::Lexer<'_>>::next_token` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/state.rs:337:9: 337:26
    = note: inside `swc_ecma_parser::lexer::state::<impl std::iter::Iterator for swc_ecma_parser::lexer::Lexer<'_>>::next` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/state.rs:347:19: 347:46
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/input.rs:377:52: 377:68
    = note: inside `std::option::Option::<swc_ecma_parser::token::TokenAndSpan>::or_else::<{closure@swc_ecma_parser::input::Buffer<swc_ecma_parser::lexer::Lexer<'_>>::cur::{closure#0}}>` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:1543:21: 1543:24
    = note: inside `swc_ecma_parser::input::Buffer::<swc_ecma_parser::lexer::Lexer<'_>>::cur` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/input.rs:377:24: 377:69
    = note: inside `swc_ecma_parser::input::Buffer::<swc_ecma_parser::lexer::Lexer<'_>>::cur_pos` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/input.rs:419:17: 419:27
    = note: inside `swc_ecma_parser::Parser::<swc_ecma_parser::lexer::Lexer<'_>>::parse_program` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/macros.rs:300:9: 300:27
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lib.rs:515:47: 515:64
    = note: inside `swc_ecma_parser::with_file_parser::<swc_ecma_ast::Program, {closure@swc_ecma_parser::parse_file_as_program::{closure#0}}>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lib.rs:479:15: 479:25
    = note: inside `swc_ecma_parser::parse_file_as_program` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lib.rs:503:13: 503:85
note: inside `main`
   --> src/main.rs:17:19
    |
17  |       let program = swc_ecma_parser::parse_file_as_program(
    |  ___________________^
18  | |         &src,
19  | |         swc_ecma_parser::Syntax::Es(Default::default()),
20  | |         swc_ecma_ast::EsVersion::EsNext,
21  | |         None,
22  | |         &mut errs,
23  | |     )
    | |_____^

error: memory leaked: alloc5944 (Rust heap, size: 7, align: 1), allocated here:
   --> /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/alloc.rs:100:9
    |
100 |         __rust_alloc(layout.size(), layout.align())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: BACKTRACE:
    = note: inside `std::alloc::alloc` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/alloc.rs:100:9: 100:52
    = note: inside `std::alloc::Global::alloc_impl` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/alloc.rs:183:73: 183:86
    = note: inside `<std::alloc::Global as std::alloc::Allocator>::allocate` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/alloc.rs:243:9: 243:39
    = note: inside `alloc::raw_vec::RawVec::<u8>::try_allocate_in` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:230:45: 230:67
    = note: inside `alloc::raw_vec::RawVec::<u8>::with_capacity_in` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:158:15: 158:79
    = note: inside `std::vec::Vec::<u8>::with_capacity_in` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:699:20: 699:61
    = note: inside `<u8 as std::slice::hack::ConvertVec>::to_vec::<std::alloc::Global>` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/slice.rs:162:25: 162:62
    = note: inside `std::slice::hack::to_vec::<u8, std::alloc::Global>` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/slice.rs:111:9: 111:28
    = note: inside `std::slice::<impl [u8]>::to_vec_in::<std::alloc::Global>` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/slice.rs:462:9: 462:34
    = note: inside `std::slice::<impl [u8]>::to_vec` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/slice.rs:437:9: 437:31
    = note: inside `std::slice::<impl std::borrow::ToOwned for [u8]>::to_owned` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/slice.rs:844:9: 844:22
    = note: inside `std::str::<impl std::borrow::ToOwned for str>::to_owned` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/str.rs:212:46: 212:72
    = note: inside `std::borrow::Cow::<'_, str>::into_owned` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/borrow.rs:325:35: 325:54
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:170:33: 170:50
    = note: inside `hashbrown::map::RawEntryMut::<'_, triomphe::arc::Arc<hstr::dynamic::Entry>, (), std::hash::BuildHasherDefault<hstr::dynamic::EntryHasher>>::or_insert_with::<{closure@<&mut hstr::dynamic::AtomStore as hstr::dynamic::Storage>::insert_entry::{closure#1}}>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hashbrown-0.14.5/src/map.rs:3430:30: 3430:39
    = note: inside `<&mut hstr::dynamic::AtomStore as hstr::dynamic::Storage>::insert_entry` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:163:26: 177:15
    = note: inside `hstr::dynamic::new_atom::<&mut hstr::dynamic::AtomStore>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:142:17: 142:49
    = note: inside `hstr::dynamic::AtomStore::atom::<'_, std::borrow::Cow<'_, str>>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/hstr-0.2.10/src/dynamic.rs:119:9: 119:36
    = note: inside `swc_atoms::AtomStore::atom::<'_, std::borrow::Cow<'_, str>>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.7/src/lib.rs:230:14: 230:28
    = note: inside `swc_atoms::AtomStoreCell::atom::<'_, &str>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_atoms-0.6.7/src/lib.rs:247:18: 247:41
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:769:42: 769:57
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:897:17: 897:58
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::with_buf::<{closure@swc_ecma_parser::lexer::Lexer<'_>::read_word_as_str_with<{closure@swc_ecma_parser::lexer::Lexer<'_>::read_word_with::{closure#0}}, swc_ecma_parser::token::Word>::{closure#0}}, (swc_ecma_parser::token::Word, bool)>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:175:9: 175:27
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::read_word_as_str_with::<{closure@swc_ecma_parser::lexer::Lexer<'_>::read_word_with::{closure#0}}, swc_ecma_parser::token::Word>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:799:9: 910:11
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::read_word_with` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:762:34: 770:11
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/table.rs:89:5: 96:7
    = note: inside `<{closure@swc_ecma_parser::lexer::table::L_C::{closure#0}} as std::ops::FnOnce<(&mut swc_ecma_parser::lexer::Lexer<'_>,)>>::call_once - shim` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5: 250:71
    = note: inside `swc_ecma_parser::lexer::Lexer::<'_>::read_token` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/mod.rs:188:30: 188:43
    = note: inside `swc_ecma_parser::lexer::state::<impl swc_ecma_parser::lexer::Lexer<'_>>::next_token` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/state.rs:337:9: 337:26
    = note: inside `swc_ecma_parser::lexer::state::<impl std::iter::Iterator for swc_ecma_parser::lexer::Lexer<'_>>::next` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lexer/state.rs:347:19: 347:46
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/input.rs:377:52: 377:68
    = note: inside `std::option::Option::<swc_ecma_parser::token::TokenAndSpan>::or_else::<{closure@swc_ecma_parser::input::Buffer<swc_ecma_parser::lexer::Lexer<'_>>::cur::{closure#0}}>` at /home/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:1543:21: 1543:24
    = note: inside `swc_ecma_parser::input::Buffer::<swc_ecma_parser::lexer::Lexer<'_>>::cur` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/input.rs:377:24: 377:69
    = note: inside `swc_ecma_parser::input::Buffer::<swc_ecma_parser::lexer::Lexer<'_>>::cur_pos` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/input.rs:419:17: 419:27
    = note: inside `swc_ecma_parser::Parser::<swc_ecma_parser::lexer::Lexer<'_>>::parse_program` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/parser/macros.rs:300:9: 300:27
    = note: inside closure at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lib.rs:515:47: 515:64
    = note: inside `swc_ecma_parser::with_file_parser::<swc_ecma_ast::Program, {closure@swc_ecma_parser::parse_file_as_program::{closure#0}}>` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lib.rs:479:15: 479:25
    = note: inside `swc_ecma_parser::parse_file_as_program` at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc_ecma_parser-0.146.8/src/lib.rs:503:13: 503:85
note: inside `main`
   --> src/main.rs:17:19
    |
17  |       let program = swc_ecma_parser::parse_file_as_program(
    |  ___________________^
18  | |         &src,
19  | |         swc_ecma_parser::Syntax::Es(Default::default()),
20  | |         swc_ecma_ast::EsVersion::EsNext,
21  | |         None,
22  | |         &mut errs,
23  | |     )
    | |_____^

(for some extra context, this was minimized from denoland/deno#24380)


I took a bit of a look at this, and I think the issue may stem from this set of FastIds. From what I can tell, the JsWords in that set are not guaranteed to be dropped (they're wrapped in ManuallyDrop), and so the reference counts of the underlying Atoms never hit 0.

I would expect that all FastJsWords that are added to the set would eventually be converted back to JsWords at the end of the transform so that their reference counts are decreased properly. (In other words, I think each FastJsWord::new should be paired with a FastJsWord::into_inner call so the JsWord gets dropped).

I've tested a local patch that calls into_inner on each FastJsWord in that set when the ScopeData is dropped, and confirmed that resolves the memory leak.

@swc-bot
Copy link
Collaborator

swc-bot commented Aug 5, 2024

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@swc-project swc-project locked as resolved and limited conversation to collaborators Aug 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

Successfully merging a pull request may close this issue.

3 participants