Skip to content

fix(wasm): correct several bugs in realloc#5261

Merged
WillLillis merged 2 commits intotree-sitter:masterfrom
WillLillis:wasm_realloc_size
Jan 27, 2026
Merged

fix(wasm): correct several bugs in realloc#5261
WillLillis merged 2 commits intotree-sitter:masterfrom
WillLillis:wasm_realloc_size

Conversation

@WillLillis
Copy link
Member

@WillLillis WillLillis commented Jan 26, 2026

  • free memory if 0 size is passed in

  • Don't memcpy contents if new pointer is NULL

  • Copy old region's contents only up to size of new region

  • free old region

  • also exit early from calloc if call to malloc fails

Supersedes #5234 with more minimal changes and test coverage for the bug.

CC @trim21 I wasn't able to get beancount-format to build locally to give this change a try on your original repro from #5205. If you get a chance to try it out let me know!

@trim21
Copy link
Contributor

trim21 commented Jan 26, 2026

what's the error when you try to build it?

there is a cargo registry patch in master branch, you can replace it and remove the rust malloc workaround and try.

https://github.com/trim21/beancount-format/tree/master/patches/tree-sitter-language-0.1.6

also I guess there are some bug when region_end == next is true, I forget what I found and why I change it in the original PR.

@trim21
Copy link
Contributor

trim21 commented Jan 26, 2026

since you create a new PR I'll close my #5234 .

@trim21
Copy link
Contributor

trim21 commented Jan 26, 2026

also while we are fixing malloc, there is also a bug in calloc, if doesn't handle NULL from malloc:

void *calloc(size_t count, size_t size) {
void *result = malloc(count * size);
memset(result, 0, count * size);
return result;
}

@WillLillis
Copy link
Member Author

what's the error when you try to build it?

❯ cargo build -p dprint-plugin-beancount --target wasm32-unknown-unknown --features wasm --release
    Updating crates.io index
error: failed to select a version for `tree-sitter`.
    ... required by package `tree-sitter-beancount v2.4.2 (https://github.com/trim21/tree-sitter-beancount?branch=wasm#110e43d6)`
    ... which satisfies git dependency `tree-sitter-beancount` (locked to 2.4.2) of package `beancount-formatter v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter)`
    ... which satisfies path dependency `beancount-formatter` (locked to 0.1.0) of package `beancount-formatter-cli v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter-cli)`
versions that meet the requirements `~0.26.3` are: 0.26.3

package `tree-sitter` links to the native library `tree-sitter`, but it conflicts with a previous package which links to `tree-sitter` as well:
package `tree-sitter v0.27.0 (/home/lillis/projects/tree-sitter/lib)`
    ... which satisfies path dependency `tree-sitter` of package `beancount-formatter v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter)`
    ... which satisfies path dependency `beancount-formatter` (locked to 0.1.0) of package `beancount-formatter-cli v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter-cli)`
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = "tree-sitter"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.

failed to select a version for `tree-sitter` which could resolve this conflict

This is with the following changes to the broken-malloc branch to point to my local checkout of tree-sitter with these changes:

diff --git a/crates/beancount-formatter/Cargo.toml b/crates/beancount-formatter/Cargo.toml
index 17113f6..8e2f654 100644
--- a/crates/beancount-formatter/Cargo.toml
+++ b/crates/beancount-formatter/Cargo.toml
@@ -16,7 +16,8 @@ wasm = ["tree-sitter-beancount/wasm"]
 [dependencies]
 tree-sitter-beancount = { git = "https://github.com/trim21/tree-sitter-beancount", branch = "wasm", default-features = false }
 # tree-sitter-beancount = { path = "C:/Users/trim21/projects/tree-sitter-beancount/", default-features = false }
-tree-sitter = { version = "0.26.3" }
+# tree-sitter = { version = "0.26.3" }
+tree-sitter = { path = "../../../tree-sitter/lib" }
 anyhow.workspace = true
 serde.workspace = true
 ropey = '1.6.1'

@trim21
Copy link
Contributor

trim21 commented Jan 26, 2026

what's the error when you try to build it?

❯ cargo build -p dprint-plugin-beancount --target wasm32-unknown-unknown --features wasm --release
    Updating crates.io index
error: failed to select a version for `tree-sitter`.
    ... required by package `tree-sitter-beancount v2.4.2 (https://github.com/trim21/tree-sitter-beancount?branch=wasm#110e43d6)`
    ... which satisfies git dependency `tree-sitter-beancount` (locked to 2.4.2) of package `beancount-formatter v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter)`
    ... which satisfies path dependency `beancount-formatter` (locked to 0.1.0) of package `beancount-formatter-cli v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter-cli)`
versions that meet the requirements `~0.26.3` are: 0.26.3

package `tree-sitter` links to the native library `tree-sitter`, but it conflicts with a previous package which links to `tree-sitter` as well:
package `tree-sitter v0.27.0 (/home/lillis/projects/tree-sitter/lib)`
    ... which satisfies path dependency `tree-sitter` of package `beancount-formatter v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter)`
    ... which satisfies path dependency `beancount-formatter` (locked to 0.1.0) of package `beancount-formatter-cli v0.1.0 (/home/lillis/projects/beancount-format/crates/beancount-formatter-cli)`
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = "tree-sitter"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.

failed to select a version for `tree-sitter` which could resolve this conflict

This is with the following changes to the broken-malloc branch to point to my local checkout of tree-sitter with these changes:

diff --git a/crates/beancount-formatter/Cargo.toml b/crates/beancount-formatter/Cargo.toml
index 17113f6..8e2f654 100644
--- a/crates/beancount-formatter/Cargo.toml
+++ b/crates/beancount-formatter/Cargo.toml
@@ -16,7 +16,8 @@ wasm = ["tree-sitter-beancount/wasm"]
 [dependencies]
 tree-sitter-beancount = { git = "https://github.com/trim21/tree-sitter-beancount", branch = "wasm", default-features = false }
 # tree-sitter-beancount = { path = "C:/Users/trim21/projects/tree-sitter-beancount/", default-features = false }
-tree-sitter = { version = "0.26.3" }
+# tree-sitter = { version = "0.26.3" }
+tree-sitter = { path = "../../../tree-sitter/lib" }
 anyhow.workspace = true
 serde.workspace = true
 ropey = '1.6.1'

there is a version spec that ~0.26.3 on tree-sitter on the beancount-parser (which is a dependency doesn't exists in this repo) so you can't use master branch of tree-sitter to build it, it's 0.27.0 doesn't match ~0.26.3.

@WillLillis
Copy link
Member Author

WillLillis commented Jan 26, 2026

there is a version spec that ~0.26.3 on tree-sitter on the beancount-parser (which is a dependency doesn't exists in this repo) so you can't use master branch of tree-sitter to build it, it's 0.27.0 doesn't match ~0.26.3.

How were you testing your changes then?

Edit: I see, nevermind.

@trim21
Copy link
Contributor

trim21 commented Jan 26, 2026

there is a patch.crates-io on tree-sitter-language so the tree-sitter-language resolve a vendor version inside the project

https://github.com/trim21/beancount-format/blob/0669ac8bd7a99867c73af1168f45d5cb43953567/Cargo.toml#L19-L20

It's a small enough change so I think you can only change content of https://github.com/trim21/beancount-format/blob/master/patches/tree-sitter-language-0.1.6/wasm/src/stdlib.c

and also remove these workaround

https://github.com/trim21/beancount-format/blob/0669ac8bd7a99867c73af1168f45d5cb43953567/crates/dprint-plugin-beancount/src/lib.rs#L164-L165

WillLillis and others added 2 commits January 26, 2026 02:13
- free memory if 0 size is passed in
- Don't `memcpy` contents if new pointer is `NULL`
- Copy old region's contents only up to size of new region
- free old region

Co-authored-by: trim21 <i@trim21.me>
Co-authored-by: trim21 <i@trim21.me>
@WillLillis
Copy link
Member Author

Replaced the contents of stdlib.c with the file from this PR, and removed the rust global allocator workaround. Everything seems to be working for beancount-format, so this should be good to land.

@WillLillis WillLillis merged commit 7ad63a8 into tree-sitter:master Jan 27, 2026
24 of 26 checks passed
@WillLillis WillLillis deleted the wasm_realloc_size branch January 27, 2026 02:14
@tree-sitter-ci-bot
Copy link

Backport failed for release-0.26, because it was unable to cherry-pick the commit(s).

Please cherry-pick the changes locally and resolve any conflicts.

git fetch origin release-0.26
git worktree add -d .worktree/backport-5261-to-release-0.26 origin/release-0.26
cd .worktree/backport-5261-to-release-0.26
git switch --create backport-5261-to-release-0.26
git cherry-pick -x f9d64425dbea3e286e9092e6f5ccd599e728cbc0 b714e2a7c01e8d5abab526f23e40b77c33babcb4

@trim21
Copy link
Contributor

trim21 commented Jan 30, 2026

there is indeed some bug in these code

Region *region_end = region_after(region, region->size);
// When reallocating the last allocated region, return
// the same pointer, and skip copying the data.
if (region_end == next) {
next = region;
return malloc(new_size);
}

image

haven't findout why...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

malloc for rust wasm32 target is buggy

3 participants