Skip to content

Fix getSelectedText overflow, align sort semantics with IDEA core, v11.0.3 - #12

Merged
krotname merged 5 commits into
masterfrom
feature/npp-bug-fixes-0f8f9f
Jul 23, 2026
Merged

Fix getSelectedText overflow, align sort semantics with IDEA core, v11.0.3#12
krotname merged 5 commits into
masterfrom
feature/npp-bug-fixes-0f8f9f

Conversation

@krotname

Copy link
Copy Markdown
Owner

Joint bug-fix release with krotname/IdeaMarkdownTableEditor keeping the shared core in lockstep. The golden fixture file stays byte-identical between both repos.

Fixes

  • 1-byte heap overflow in getSelectedText: Scintilla >= 5.1.5 returns the selection length excluding the terminating NUL from SCI_GETSELTEXT(0,0), but the fill still writes the NUL. The buffer was sized length, so the fill wrote length + 1 bytes. Now allocates length + 1 (from the repository-audit branch).
  • One-character selections dropped: the lengthResult <= 1 guard encoded the pre-5.1.5 semantics (length including NUL) and silently treated 1-byte selections as empty. Lowered to <= 0; still returns an empty string under legacy semantics.
  • Intransitive sort comparator: numeric pairs compared by value, mixed pairs by text, producing cycles like '10' < '1z' < '9' < '10' — not a strict weak ordering, so std::stable_sort invoked undefined behavior. Strict-decimal rows now group before textual rows — a proper total order, same as the Java core.
  • Sort-key grammar divergence: strtod accepted inf, nan, hex 0x10 while Double.parseDouble accepted 1.5f, Infinity — the same column sorted differently in the two plugins. Both cores now share one strict decimal grammar; NaN keys are impossible.
  • Locale-dependent numeric parse: strtod honors LC_NUMERIC, so a comma-decimal host locale parsed 1.5 as 1. Pinned to the C locale via _strtod_l.

Parity

  • 2 new golden fixtures lock the number-vs-text grouping and the +0/-0 tie-break; mirrored byte-for-byte in IdeaMarkdownTableEditor.
  • Version bumped to 11.0.3 in both repos.

Tests

  • CoreSmoke: scenario tests (63 checks), golden fixtures (82 checks), smoke — all green.
  • PluginShortcutSmoke green, CorePerformance (Release) green.

🤖 Generated with Claude Code

claude and others added 4 commits July 23, 2026 04:52
SCI_GETSELTEXT in Scintilla >= 5.1.5 (Notepad++ bundles >= 5.2.3, per the
Scintilla.h deprecation note) returns the selection length EXCLUDING the
terminating NUL, and the fill call still writes that NUL. getSelectedText
allocated exactly `length` bytes, so the fill wrote length+1 bytes, one past
the end of the heap buffer. Allocate `length + 1`, matching the +1 already
used by getRangeText, nativeLangFileName, and pluginConfigFilePath.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEUknRbMeu7qwvi8QGZ48z
Scintilla >= 5.1.5 returns the selection length excluding the NUL from
SCI_GETSELTEXT(0,0), so an empty selection reports 0 and a one-character
selection reports 1. The old guard 'lengthResult <= 1' was written for
the pre-5.1.5 semantics (length including NUL) and now silently drops
one-character selections in getSelectedText.

Lower the guard to 'lengthResult <= 0'. Under the legacy semantics an
empty selection reports 1, and the length + 1 buffer stays NUL-filled,
so the function still returns an empty string there; real selections are
unaffected either way.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Joint fix with IdeaMarkdownTableEditor so both plugin cores keep
producing identical output (shared golden fixtures stay byte-equal).

- Make the sort comparator a total order: rows with strict-decimal
  values group before textual rows instead of comparing numerically
  against some rows and textually against others. The old mixed
  comparison was intransitive ('10' < '1z' < '9' < '10'), which is
  not a strict weak ordering, so std::stable_sort invoked undefined
  behavior on such columns.
- Restrict numeric sort keys to a strict decimal grammar shared with
  the Java core. strtod also accepts 'inf', 'nan', and hex floats
  like '0x10', which Double.parseDouble either rejects or spells
  differently, so the same column sorted differently in the two
  plugins. NaN keys are no longer possible.
- Pin the numeric parse to the C locale via _strtod_l. A host process
  running under a comma-decimal locale would otherwise parse '1.5'
  as 1 and diverge from the IntelliJ plugin.
- Add golden fixtures locking the number-vs-text grouping and the
  +0/-0 tie-break; the same fixtures land in IdeaMarkdownTableEditor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Extend the strict-decimal sort fixture with exponent forms (2e3, 5e-1,
1e+2, 3E2), rejected shapes (7e, lone '-'), a soft-hyphen cell, and a
plane-15 code point so the shared grammar's exponent branches, the
format-code-point path, and the code-point-table exhaustion path are
all exercised by the golden contract in both plugin cores. Mirrored
byte-for-byte in IdeaMarkdownTableEditor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@krotname
krotname merged commit 9d9d72e into master Jul 23, 2026
19 checks passed
@krotname
krotname deleted the feature/npp-bug-fixes-0f8f9f branch July 23, 2026 07:19
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.

2 participants