Skip to content

v4.0.0-rc1: measureText("") / fillText("") / strokeText("") abort the process (SIGTRAP in SBAlgorithmCreateParagraph) #2604

Description

@lvcabral

In canvas@4.0.0-rc1 ( PR #2602 ), passing an empty string to any of the text APIs, ctx.measureText(""), ctx.fillText("", x, y), or ctx.strokeText("", x, y), crashes the entire Node.js process with SIGTRAP (exit code 133). It's a native abort, not a JS exception, so it cannot be caught with try/catch and takes down the whole application.

In v3.x (and in browsers), these calls are valid no-ops: measureText("") returns metrics with width: 0, and fillText("")/strokeText("") draw nothing. This is a common real-world input — any UI code rendering a text field/label whose content happens to be empty hits it.

Steps to reproduce

const { createCanvas } = require("canvas");
const ctx = createCanvas(10, 10).getContext("2d");
ctx.measureText(""); // process dies here, exit code 133 (SIGTRAP)

Same result with ctx.fillText("", 5, 5) and ctx.strokeText("", 5, 5). Non-empty strings (including " ", "\n", emoji, accented chars) all work fine. No font registration is required to reproduce.

Native backtrace

The trap is a brk instruction inside SheenBidi's paragraph creation — presumably an assertion on a zero-length paragraph:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x1176079f4)
    frame #0: canvas.node`SBAlgorithmCreateParagraph + 1512
canvas.node`SBAlgorithmCreateParagraph:
->  0x1176079f4 <+1512>: brk    #0x5516

Suggests the new text layout path calls into SheenBidi without first checking for zero-length input; per SheenBidi's API docs, SBAlgorithmCreateParagraph expects a paragraph length ≥ 1.

Environment

  • canvas: 4.0.0-rc1 (prebuilt binary from npm, canvas-darwin-arm64)
  • Node.js: v22.22.2
  • OS: macOS 15.7.7 (Darwin 24.6.0), Apple Silicon (arm64)

Expected behavior

Match v3.x / browser behavior: measureText("") returns a TextMetrics with all-zero extents; fillText/strokeText with empty text are no-ops. An early return for zero-length input before entering bidi/layout would presumably fix all three entry points at once.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions