fix: own legend label bytes in LegendEntryLabel forwarder (macOS issue #9)#21
Merged
Merged
Conversation
…#9) LegendEntryLabel returned the raw const char* from ImPlot's GetLegendLabel, which points straight into the per-frame Legend.Labels buffer. daslang aliases a const char* return (no copy), so the captured das string pointed into that buffer. The buffer is valid at capture time (post-EndPlot) but the snapshot serializes a frame later, by when the next BeginPlot/SetupFinish has reset and (on macOS) realloc'd it, leaving the string dangling — empty/garbage labels. Win/Linux kept the same allocation and rewrote identical bytes in place, so the alias still read correctly there. Fix in the forwarder (which we own, unlike the generated bindings): thread das::Context*/LineInfoArg* and return context->allocateString(...) so the das string owns its bytes and stays valid regardless of the buffer's later fate. Mirrors the rest of the string-returning API (dasImgui's text_range_string / ImGTB_Slice). Drops the macOS skip in test_multi_axes — the pressure/Y2 legend assertion now runs on all platforms. Full integration suite passes 13/13 headless on macOS. Closes #9 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
355f3d4 to
95d95c6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #9 — on macOS the Y2-routed series' legend label came back empty in the v2 plot snapshot. Root-caused as a dangling internal-pointer alias, not a label-resolution lag.
LegendEntryLabel(src/dasIMPLOT.main.cpp) returned the rawconst char*fromImPlot::...GetLegendLabel(i)=Legend.Labels.Buf.Data + NameOffset, a pointer straight into ImPlot's per-frameLegend.Labelsbuffer. daslang aliases aconst char*return (no copy), andcapture_legendstored the alias. The buffer is valid at capture time (post-EndPlot), but the snapshot is serialized a frame later over the live API — by then the next frame'sBeginPlot/SetupFinish→Legend.Reset()has cleared and (on macOS) realloc'd the buffer, leaving the das string dangling. Windows/Linux kept the same allocation and rewrote identical bytes in place, so the alias still read correctly there; macOS surfaced empty/garbage labels.Diagnosing on a macOS box showed it's worse than "empty": both labels came back as garbage bytes, not just the Y2 one — the test only asserted
pressure, sotemp's corruption went unnoticed. Same root cause.Fix (C++ wrapper, not the das caller)
We own the
LegendEntryLabelforwarder (it's hand-written, unlike the generated bindings), so the right place to own the bytes is the wrapper itself — matching the rest of the string-returning API. Threadeddas::Context*/das::LineInfoArg*and returncontext->allocateString(...), so the returned das string owns a heap copy that stays valid regardless of ImPlot's buffer churn. Same idiom as dasImgui'stext_range_string/ImGTB_Slice.(First pass cloned on the das side with
clone_stringincapture_legend; moved to the wrapper per review — keeps callers from having to remember to clone, consistent with the rest of the API.)Also removed the macOS skip in
test_multi_axes— thepressure/Y2 legend assertion now runs on all platforms.Verification (macOS, headless, CI-equivalent)
Reproduced and fixed in a fresh workspace mirroring
tests.ymlexactly (owndaslang-src+dasImgui+dasImguiImplot, Ninja Release build,daspkg install --globalboth packages):wait_for_series_shown(... "pressure" ...)times out; raw legend dump shows garbage labels for both series.temp/pressure; full integration suite passes 13/13 (--isolated-mode --isolated-mode-threads 4 --headless), including the de-skippedtest_multi_axes..dasfiles lint clean.Audit (same internal-pointer pattern elsewhere)
Swept every native string return that das might store:
LegendEntryLabel— the one live bug. Fixed here.GetColormapName(generated binding) — same internal-ImGuiTextBufferpattern (Text.Buf.Data + TextOffsets[cmap]), but no das caller stores it today → latent only. If it's ever wired to das, give it the sameallocateStringtreatment.GetStyleColorName/GetMarkerName— static string literals → safe.text_range_string/ImGTB_Slice— already usecontext->allocateString(...)→ safe; combo-getter callbacks are transient → safe.🤖 Generated with Claude Code