Skip to content

Fix issue #105: linear_extrude scale= heap corruption on non-finite values - #107

Merged
particlesector merged 2 commits into
mainfrom
claude/issue-105-fyk59e
Aug 12, 2026
Merged

particlesector merged 2 commits into
mainfrom
claude/issue-105-fyk59e

Conversation

@particlesector

Copy link
Copy Markdown
Owner

Summary

Fixes #105 — linear_extrude-parameter-tests.scad crashed with heap corruption (free(): invalid next size (fast)).

Root cause: CsgEvaluator::evalExtrusion() special-cases scale= to accept either a scalar or a 2-vector. Every other extrusion param (height, twist, slices, convexity, ...) routes through Interpreter::evalNumber(), which folds non-finite doubles (1/0, -1/0, 0/0) down to 0.0. angle= (for rotate_extrude) gets its own explicit std::isfinite() fallback. But the scale= branch assigned sv.asNumber() straight into scale_x/scale_y with no such guard — and 1/0/-1/0/0/0 are real IEEE-754 Number values per the interpreter's arithmetic propagation, so they sailed right past the isNumber() type check unclamped.

Those non-finite values then flowed into MeshEvaluator::evalExtrusion() → manifold::Manifold::Extrude(..., {scaleX, scaleY}), which lerps every extruded vertex toward the given scale across the profile's height — with an inf/nan scale, this corrupts the heap.

Fix: reject non-finite scale values (scalar or per-component in the 2-vector form), leaving scale_x/scale_y unset so MeshEvaluator falls back to its existing default of 1.0 (no scaling) — the same "malformed scale is ignored" behavior already used for e.g. a stray 3-element scale vector.

Verification

  • Reproduced the exact reported crash locally: built chiselcad_cli against the pre-fix code and ran a linear_extrude(scale=1/0) square(10); file — free(): invalid next size (fast) / Aborted (core dumped), matching the issue.
  • Rebuilt with the fix — same file now renders and exports cleanly (exit 0), including a full repro of all eight of the corpus file's odd param values (undef, 1/0, -1/0, 0/0, "", true, [1:3], 3) fed through scale=.
  • Added CsgEval:linear_extrude non-finite scale is rejected, not passed through to tests/test_csg_evaluator.cpp, verifying the resolved IR params (the half of the pipeline that's unit-testable without linking Manifold — see the file's existing header comment on this).
  • Full suite: ./chiselcad_tests → all 3699 assertions in 665 test cases pass.

Test plan

  • ./chiselcad_tests (full suite) passes
  • New regression test covers non-finite scalar scale (1/0, -1/0, 0/0) and non-finite 2-vector component
  • Manually reproduced and confirmed-fixed the original crash via chiselcad_cli on both pre-fix and post-fix builds

Generated by Claude Code

…alues

CsgEvaluator::evalExtrusion() special-cases "scale" to support both a
scalar and a 2-vector, but unlike every other extrusion param (which
routes through evalNumber(), folding non-finite doubles to 0.0) and
unlike "angle" (which explicitly resolves non-finite to a fallback),
the scale branch assigned sv.asNumber() straight into scale_x/scale_y.
1/0, -1/0, and 0/0 are real IEEE-754 Numbers per the interpreter's
arithmetic propagation, so they sailed through the isNumber() check
unclamped. MeshEvaluator/Manifold::Extrude then lerped every extruded
vertex toward that inf/nan scale, corrupting the heap ("free(): invalid
next size (fast)") — reproduced with linear_extrude(scale=1/0), matching
OpenSCAD's own linear_extrude-parameter-tests.scad corpus file.

Now a non-finite scalar or vector component is rejected, leaving
scale_x/scale_y unset so MeshEvaluator falls back to its default 1.0
(no scaling) — the same "malformed scale is ignored" behavior already
used for a stray 3-element vector.

@particlesector particlesector left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Reviewed. Fix is correct and narrowly scoped: scale= now goes through the same std::isfinite() guard already used for angle= (<cmath> was already included), and leaving scale_x/scale_y unset correctly falls back to MeshEvaluator's default of 1.0 (verified at src/csg/MeshEvaluator.cpp:426-427). Test case covers 1/0, -1/0, 0/0, the 2-vector form, and a finite-value regression check.

One nit: scale=[1/0, 2] is tested, but not the symmetric scale=[2, 1/0] (non-finite in the second component only) — probably not worth a separate case given the shared guard, just flagging.

No blocking issues.


Generated by Claude Code


Generated by Claude Code

Mirrors the existing scale=[1/0, 2] case to also cover a non-finite
value in the vector's second component only.

Copy link
Copy Markdown
Owner Author

Good catch — added the symmetric scale=[2, 1/0] case in 81e8c7c. Full suite still green (3703 assertions, 665 test cases).


Generated by Claude Code

@particlesector particlesector left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Symmetric scale=[2, 1/0] case added, addressing the earlier nit. Fix logic unchanged and still correct. LGTM.


Generated by Claude Code


Generated by Claude Code

@particlesector
particlesector merged commit 517329b into main Aug 12, 2026
6 checks passed
@particlesector
particlesector deleted the claude/issue-105-fyk59e branch August 12, 2026 14:20
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.

linear_extrude-parameter-tests.scad crashes with heap corruption ("free(): invalid next size (fast)")

2 participants