Skip to content

bug(#4584): resize on writing to malloc#4994

Merged
yegor256 merged 1 commit into
objectionary:masterfrom
maxonfjvipon:bug/#4584/resize-on-write
Apr 17, 2026
Merged

bug(#4584): resize on writing to malloc#4994
yegor256 merged 1 commit into
objectionary:masterfrom
maxonfjvipon:bug/#4584/resize-on-write

Conversation

@maxonfjvipon

@maxonfjvipon maxonfjvipon commented Apr 17, 2026

Copy link
Copy Markdown
Member

Closes: #4584

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Memory allocation now automatically resizes to accommodate write operations that exceed the initially allocated capacity, replacing the previous error behavior.

@coderabbitai

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This pull request modifies malloc memory management to support automatic block resizing instead of throwing errors on out-of-bounds writes. Test cases in EO and Java are updated to verify successful resizing behavior, and the core Heaps.write() method is refactored to expand allocated memory when writes exceed current block capacity.

Changes

Cohort / File(s) Summary
EO Test Cases
eo-runtime/src/main/eo/io/malloc-as-output.eo, eo-runtime/src/main/eo/malloc.eo
Removed test cases expecting runtime failures on oversized writes. Replaced with tests verifying automatic resizing: writes-larger-data-than-provided-block and writes-beyond-offset-and-resizes now assert successful writes with expanded block sizes instead of exceptions.
Java Implementation
eo-runtime/src/main/java/org/eolang/Heaps.java
Modified write(identifier, offset, data) to automatically resize heap blocks when write operations exceed current allocated length. Eliminates exception-throwing behavior; simplifies buffer logic by unconditionally copying existing contents and applying new writes with resizing as needed.
Java Unit Tests
eo-runtime/src/test/java/org/eolang/HeapsTest.java
Replaced exception-assertion tests (failsOnWriteMoreThanAllocated, failsToWriteMoreThanAllocatedWithOffset) with tests that perform oversized writes and verify correct byte sequences in the heap via Heaps.INSTANCE.read. Updated assertion messaging for partial-overwrite scenario.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A malloc that grows with each beat,
No crashes when writes overflow,
Blocks expand so neat,
Data flows, no more foe,
Puzzle solved—success complete! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly references issue #4584 and accurately describes the main change: automatic resizing behavior when writing to malloc blocks.
Linked Issues check ✅ Passed The PR addresses issue #4584 by implementing automatic resizing of malloc blocks on write operations, allowing tests to pass without throwing errors on out-of-bounds writes, effectively resolving the puzzle.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing automatic resize behavior for malloc writes across test files and the Heaps.java implementation, with no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Performance Analysis

All benchmarks are within the acceptable range. No critical degradation detected (threshold is 100%). Please refer to the detailed report for more information.

Click to see the detailed report
Test Base Score PR Score Change % Change Unit Mode
benchmarks.XmirBench.xmirToEO 213.704 209.289 -4.415 -2.07% ms/op Average Time

✅ Performance gain: benchmarks.XmirBench.xmirToEO is faster by 4.415 ms/op (2.07%)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
eo-runtime/src/main/eo/malloc.eo (1)

293-300: Naming: use the tests- prefix for positive tests.

All other success-path tests in this file are named tests-…, and throws-on-… is reserved for tests that expect a failure. Since these two are now success-path assertions (replacing former throws-on-… tests), renaming to tests-writes-beyond-offset-and-resizes and tests-copies-and-resizes-to-target would keep the convention consistent and make their intent obvious at a glance.

Also applies to: 385-392

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eo-runtime/src/main/eo/malloc.eo` around lines 293 - 300, Rename the positive
test identifiers to follow the project convention: change the test name
writes-beyond-offset-and-resizes to tests-writes-beyond-offset-and-resizes (in
the malloc.of test that contains m.write and m.size.eq) and likewise change the
other positive test (the one around the copy-and-resize behavior referenced at
lines 385-392) from its current non-prefixed name to
tests-copies-and-resizes-to-target so that all success-path tests use the
tests-… prefix and failure tests keep throws-on-…; update only the test names
(identifiers) where they are declared.
eo-runtime/src/test/java/org/eolang/HeapsTest.java (1)

126-135: Consider strengthening this test to cover leading bytes and final size.

The assertion only reads back the three bytes that were just written; a regression that clobbered the leading byte at offset 0 or grew the block past offset + data.length would not be caught. Reading from offset 0 for 4 bytes (expecting {0, 1, 2, 3}) or asserting Heaps.INSTANCE.size(idx) == 4 would close that gap.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eo-runtime/src/test/java/org/eolang/HeapsTest.java` around lines 126 - 135,
Update the test resizesOnWriteMoreThanAllocatedWithOffset to also verify leading
byte and final block size: after calling Heaps.INSTANCE.write(idx, 1, new byte[]
{1,2,3}), read from offset 0 for 4 bytes via Heaps.INSTANCE.read(idx, 0, 4) and
assert the result equals {0,1,2,3}, and also assert Heaps.INSTANCE.size(idx) ==
4 to ensure the block resized exactly to offset+data.length; keep the existing
free(idx) cleanup.
eo-runtime/src/main/eo/io/malloc-as-output.eo (1)

63-72: Consider prefixing the test name with tests- for consistency.

Other positive tests in this file and in malloc.eo use the tests- prefix (tests-makes-an-output-from-malloc-and-writes right above), while throws-on- is reserved for negative expectations. Since this is now a success-path assertion, tests-writes-larger-data-than-provided-block would align with the existing convention.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eo-runtime/src/main/eo/io/malloc-as-output.eo` around lines 63 - 72, Rename
the test label "writes-larger-data-than-provided-block" to follow the project's
positive-test convention by prefixing it with "tests-"; update the test
declaration in the malloc-as-output.eo diff so the label becomes
"tests-writes-larger-data-than-provided-block" (the test that calls malloc.of
and (malloc-as-output mem).write 01-02-03 should be the one renamed) to match
other positive tests like "tests-makes-an-output-from-malloc-and-writes".
eo-runtime/src/main/java/org/eolang/Heaps.java (1)

180-188: Redundant allocation and copy when the block is resized.

When the resize branch is taken, this.resize(...) already allocates a new array of size offset + data.length and copies the old contents into it. Immediately after, lines 183–186 allocate yet another array of the same length and copy the same contents again, so you pay for two full-size allocations plus copies on every resizing write. The non-resize path also unnecessarily clones the existing buffer — since read() already returns Arrays.copyOfRange(...), readers never observe the stored array, so an in-place write under the lock is safe.

Consider inlining the growth and writing directly into the stored buffer:

♻️ Proposed refactor
-            if (this.blocks.get(identifier).length < offset + data.length) {
-                this.resize(identifier, offset + data.length);
-            }
-            final byte[] source = this.blocks.get(identifier);
-            final int length = source.length;
-            final byte[] result = new byte[length];
-            System.arraycopy(source, 0, result, 0, length);
-            System.arraycopy(data, 0, result, offset, data.length);
-            this.blocks.put(identifier, result);
+            byte[] bytes = this.blocks.get(identifier);
+            if (bytes.length < offset + data.length) {
+                final byte[] resized = new byte[offset + data.length];
+                System.arraycopy(bytes, 0, resized, 0, bytes.length);
+                bytes = resized;
+                this.blocks.put(identifier, bytes);
+            }
+            System.arraycopy(data, 0, bytes, offset, data.length);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@eo-runtime/src/main/java/org/eolang/Heaps.java` around lines 180 - 188, The
current write logic performs an extra allocation+copy: after calling
this.resize(identifier, ...) you immediately clone the buffer again and copy
data into the clone; also the non-resize path clones the buffer unnecessarily.
Fix by obtaining the stored byte[] once (this.blocks.get(identifier)) after any
resize and writing data directly into that array at offset
(System.arraycopy(data, 0, buf, offset, data.length)); do the same in the
non-resize path—avoid creating the intermediate result array. Keep using the
lock and note that read() already returns a copy, so in-place writes to
this.blocks are safe; update code around Heaps.resize, this.blocks, identifier,
data, and offset accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@eo-runtime/src/main/eo/io/malloc-as-output.eo`:
- Around line 63-72: Rename the test label
"writes-larger-data-than-provided-block" to follow the project's positive-test
convention by prefixing it with "tests-"; update the test declaration in the
malloc-as-output.eo diff so the label becomes
"tests-writes-larger-data-than-provided-block" (the test that calls malloc.of
and (malloc-as-output mem).write 01-02-03 should be the one renamed) to match
other positive tests like "tests-makes-an-output-from-malloc-and-writes".

In `@eo-runtime/src/main/eo/malloc.eo`:
- Around line 293-300: Rename the positive test identifiers to follow the
project convention: change the test name writes-beyond-offset-and-resizes to
tests-writes-beyond-offset-and-resizes (in the malloc.of test that contains
m.write and m.size.eq) and likewise change the other positive test (the one
around the copy-and-resize behavior referenced at lines 385-392) from its
current non-prefixed name to tests-copies-and-resizes-to-target so that all
success-path tests use the tests-… prefix and failure tests keep throws-on-…;
update only the test names (identifiers) where they are declared.

In `@eo-runtime/src/main/java/org/eolang/Heaps.java`:
- Around line 180-188: The current write logic performs an extra
allocation+copy: after calling this.resize(identifier, ...) you immediately
clone the buffer again and copy data into the clone; also the non-resize path
clones the buffer unnecessarily. Fix by obtaining the stored byte[] once
(this.blocks.get(identifier)) after any resize and writing data directly into
that array at offset (System.arraycopy(data, 0, buf, offset, data.length)); do
the same in the non-resize path—avoid creating the intermediate result array.
Keep using the lock and note that read() already returns a copy, so in-place
writes to this.blocks are safe; update code around Heaps.resize, this.blocks,
identifier, data, and offset accordingly.

In `@eo-runtime/src/test/java/org/eolang/HeapsTest.java`:
- Around line 126-135: Update the test resizesOnWriteMoreThanAllocatedWithOffset
to also verify leading byte and final block size: after calling
Heaps.INSTANCE.write(idx, 1, new byte[] {1,2,3}), read from offset 0 for 4 bytes
via Heaps.INSTANCE.read(idx, 0, 4) and assert the result equals {0,1,2,3}, and
also assert Heaps.INSTANCE.size(idx) == 4 to ensure the block resized exactly to
offset+data.length; keep the existing free(idx) cleanup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 75b232fb-672a-4a28-a9ce-d360c884bd98

📥 Commits

Reviewing files that changed from the base of the PR and between 58196b2 and f632633.

📒 Files selected for processing (4)
  • eo-runtime/src/main/eo/io/malloc-as-output.eo
  • eo-runtime/src/main/eo/malloc.eo
  • eo-runtime/src/main/java/org/eolang/Heaps.java
  • eo-runtime/src/test/java/org/eolang/HeapsTest.java

@maxonfjvipon

Copy link
Copy Markdown
Member Author

@yegor256 please check

@yegor256 yegor256 merged commit 34a673f into objectionary:master Apr 17, 2026
25 checks passed
@0crat

0crat commented Apr 18, 2026

Copy link
Copy Markdown

@maxonfjvipon Great work on your contribution! 🎉 You've earned +16 points and your total score is now +76. Keep up the excellent pace and don't forget to check your Zerocracy account for updates!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Malloc-as-output.eo: Failure to Resolve Puzzle 4475-c4f74bf0

3 participants