Skip to content

Commit c849d2a

Browse files
tucktuckg00seclaude
andcommitted
v0.9.3: fix text editor use-after-free crash, multi-platform build docs
SafePointer guard in HeaderBar/SliceControlBar text editor callbacks to prevent crash when component is destroyed before async callback fires. Multi-platform build instructions in README (Windows, macOS, Debian, Fedora, Arch). Bump CI actions to v5. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 076b709 commit c849d2a

4 files changed

Lines changed: 136 additions & 51 deletions

File tree

.github/workflows/release.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
run:
1313
shell: bash
1414
steps:
15-
- uses: actions/checkout@v4
15+
- uses: actions/checkout@v5
1616
with:
1717
submodules: recursive
1818

@@ -33,7 +33,7 @@ jobs:
3333
cp build/Intersect_artefacts/Release/Standalone/INTERSECT.exe staging/
3434
cd staging && 7z a ../INTERSECT-${{ github.ref_name }}-Windows-x64.zip *
3535
36-
- uses: actions/upload-artifact@v4
36+
- uses: actions/upload-artifact@v5
3737
with:
3838
name: INTERSECT-Windows-x64
3939
path: INTERSECT-${{ github.ref_name }}-Windows-x64.zip
@@ -46,7 +46,7 @@ jobs:
4646
sudo apt-get update
4747
sudo apt-get install -y libasound2-dev libfreetype-dev libx11-dev libxrandr-dev libxcursor-dev libxinerama-dev libwebkit2gtk-4.1-dev libcurl4-openssl-dev
4848
49-
- uses: actions/checkout@v4
49+
- uses: actions/checkout@v5
5050
with:
5151
submodules: recursive
5252

@@ -67,15 +67,15 @@ jobs:
6767
cp build/Intersect_artefacts/Release/Standalone/INTERSECT staging/
6868
cd staging && zip -r ../INTERSECT-${{ github.ref_name }}-Linux-x64.zip .
6969
70-
- uses: actions/upload-artifact@v4
70+
- uses: actions/upload-artifact@v5
7171
with:
7272
name: INTERSECT-Linux-x64
7373
path: INTERSECT-${{ github.ref_name }}-Linux-x64.zip
7474

7575
build-macos-arm64:
7676
runs-on: macos-latest
7777
steps:
78-
- uses: actions/checkout@v4
78+
- uses: actions/checkout@v5
7979
with:
8080
submodules: recursive
8181

@@ -97,15 +97,15 @@ jobs:
9797
cp -r build/Intersect_artefacts/Release/AU/INTERSECT.component staging/
9898
cd staging && zip -r ../INTERSECT-${{ github.ref_name }}-macOS-arm64.zip .
9999
100-
- uses: actions/upload-artifact@v4
100+
- uses: actions/upload-artifact@v5
101101
with:
102102
name: INTERSECT-macOS-arm64
103103
path: INTERSECT-${{ github.ref_name }}-macOS-arm64.zip
104104

105105
build-macos-x64:
106106
runs-on: macos-15-intel
107107
steps:
108-
- uses: actions/checkout@v4
108+
- uses: actions/checkout@v5
109109
with:
110110
submodules: recursive
111111

@@ -127,7 +127,7 @@ jobs:
127127
cp -r build/Intersect_artefacts/Release/AU/INTERSECT.component staging/
128128
cd staging && zip -r ../INTERSECT-${{ github.ref_name }}-macOS-x64.zip .
129129
130-
- uses: actions/upload-artifact@v4
130+
- uses: actions/upload-artifact@v5
131131
with:
132132
name: INTERSECT-macOS-x64
133133
path: INTERSECT-${{ github.ref_name }}-macOS-x64.zip
@@ -138,7 +138,7 @@ jobs:
138138
permissions:
139139
contents: write
140140
steps:
141-
- uses: actions/download-artifact@v4
141+
- uses: actions/download-artifact@v5
142142
with:
143143
path: artifacts
144144

README.md

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -242,24 +242,73 @@ The **SET** button popup also controls interface scale (`0.5x` to `3.0x` in `0.2
242242
### Prerequisites
243243

244244
- CMake `3.22+`
245-
- C++20 compiler/toolchain
246-
- Git submodules initialized
247-
- Platform SDK requirements for JUCE (Visual Studio on Windows, Xcode/CLT on macOS, required dev packages on Linux)
245+
- C++20 compiler
246+
- Git
248247

249-
### Build commands
248+
### Platform setup
250249

251-
Linux users may need JUCE/system libraries first. On Debian/Ubuntu:
250+
Pick your platform below to install the required toolchain and libraries, then follow the shared **Clone and build** steps.
251+
252+
<details>
253+
<summary><strong>Windows</strong></summary>
254+
255+
1. Install [Visual Studio 2022](https://visualstudio.microsoft.com/vs/community/) (Community edition is free).
256+
During installation, select the **"Desktop development with C++"** workload.
257+
2. Install [CMake](https://cmake.org/download/) (add to PATH during install) and [Git](https://git-scm.com/download/win).
258+
259+
</details>
260+
261+
<details>
262+
<summary><strong>macOS</strong></summary>
263+
264+
1. Install Xcode Command Line Tools:
265+
```bash
266+
xcode-select --install
267+
```
268+
2. Install CMake via [Homebrew](https://brew.sh/):
269+
```bash
270+
brew install cmake
271+
```
272+
273+
</details>
274+
275+
<details>
276+
<summary><strong>Linux — Debian / Ubuntu</strong></summary>
277+
278+
```bash
279+
sudo apt update
280+
sudo apt install -y build-essential cmake git libasound2-dev libfreetype-dev \
281+
libx11-dev libxrandr-dev libxcursor-dev libxinerama-dev \
282+
libwebkit2gtk-4.1-dev libcurl4-openssl-dev
283+
```
284+
285+
</details>
286+
287+
<details>
288+
<summary><strong>Linux — Fedora</strong></summary>
252289

253290
```bash
254-
sudo apt-get update
255-
sudo apt-get install -y libasound2-dev libfreetype-dev libx11-dev libxrandr-dev \
256-
libxcursor-dev libxinerama-dev libwebkit2gtk-4.1-dev libcurl4-openssl-dev
291+
sudo dnf install -y gcc-c++ cmake git alsa-lib-devel freetype-devel \
292+
libX11-devel libXrandr-devel libXcursor-devel libXinerama-devel \
293+
webkit2gtk4.1-devel libcurl-devel
257294
```
258295

259-
Then build:
296+
</details>
297+
298+
<details>
299+
<summary><strong>Linux — Arch</strong></summary>
300+
301+
```bash
302+
sudo pacman -S --needed base-devel cmake git alsa-lib freetype2 \
303+
libx11 libxrandr libxcursor libxinerama webkit2gtk-4.1 curl
304+
```
305+
306+
</details>
307+
308+
### Clone and build
260309

261310
```bash
262-
git clone --recursive git@github.com:tucktuckg00se/INTERSECT.git
311+
git clone --recursive https://github.com/tucktuckg00se/INTERSECT.git
263312
cd INTERSECT
264313
cmake -B build
265314
cmake --build build --config Release

src/ui/HeaderBar.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -608,26 +608,37 @@ void HeaderBar::showTextEditor (const HeaderCell& cell)
608608
float minV = cell.minVal;
609609
float maxV = cell.maxVal;
610610

611-
textEditor->onReturnKey = [this, paramId, minV, maxV] {
612-
if (textEditor == nullptr) return;
613-
float val = textEditor->getText().getFloatValue();
611+
juce::Component::SafePointer<HeaderBar> safeThis (this);
612+
613+
textEditor->onReturnKey = [safeThis, paramId, minV, maxV] {
614+
if (safeThis == nullptr) return;
615+
auto& self = *safeThis;
616+
if (self.textEditor == nullptr) return;
617+
float val = self.textEditor->getText().getFloatValue();
614618
val = juce::jlimit (minV, maxV, val);
615619

616-
if (auto* p = processor.apvts.getParameter (paramId))
620+
if (auto* p = self.processor.apvts.getParameter (paramId))
617621
p->setValueNotifyingHost (p->convertTo0to1 (val));
618622

619-
textEditor.reset();
620-
repaint();
623+
self.textEditor->onFocusLost = nullptr;
624+
self.textEditor.reset();
625+
self.repaint();
621626
};
622627

623-
textEditor->onEscapeKey = [this] {
624-
textEditor.reset();
625-
repaint();
628+
textEditor->onEscapeKey = [safeThis] {
629+
if (safeThis == nullptr) return;
630+
auto& self = *safeThis;
631+
self.textEditor->onFocusLost = nullptr;
632+
self.textEditor.reset();
633+
self.repaint();
626634
};
627635

628-
textEditor->onFocusLost = [this] {
629-
textEditor.reset();
630-
repaint();
636+
textEditor->onFocusLost = [safeThis] {
637+
if (safeThis == nullptr) return;
638+
auto& self = *safeThis;
639+
self.textEditor->onFocusLost = nullptr;
640+
self.textEditor.reset();
641+
self.repaint();
631642
};
632643
}
633644

src/ui/SliceControlBar.cpp

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -678,18 +678,32 @@ void SliceControlBar::mouseDoubleClick (const juce::MouseEvent& e)
678678
textEditor->selectAll();
679679
textEditor->grabKeyboardFocus();
680680

681-
textEditor->onReturnKey = [this] {
682-
if (textEditor == nullptr) return;
683-
int val = juce::jlimit (0, 127, textEditor->getText().getIntValue());
681+
juce::Component::SafePointer<SliceControlBar> safeThis (this);
682+
textEditor->onReturnKey = [safeThis] {
683+
if (safeThis == nullptr) return;
684+
auto& self = *safeThis;
685+
if (self.textEditor == nullptr) return;
686+
int val = juce::jlimit (0, 127, self.textEditor->getText().getIntValue());
684687
IntersectProcessor::Command cmd;
685688
cmd.type = IntersectProcessor::CmdSetRootNote;
686689
cmd.intParam1 = val;
687-
processor.pushCommand (cmd);
688-
textEditor.reset();
689-
repaint();
690+
self.processor.pushCommand (cmd);
691+
self.textEditor->onFocusLost = nullptr;
692+
self.textEditor.reset();
693+
self.repaint();
694+
};
695+
textEditor->onEscapeKey = [safeThis] {
696+
if (safeThis == nullptr) return;
697+
safeThis->textEditor->onFocusLost = nullptr;
698+
safeThis->textEditor.reset();
699+
safeThis->repaint();
700+
};
701+
textEditor->onFocusLost = [safeThis] {
702+
if (safeThis == nullptr) return;
703+
safeThis->textEditor->onFocusLost = nullptr;
704+
safeThis->textEditor.reset();
705+
safeThis->repaint();
690706
};
691-
textEditor->onEscapeKey = [this] { textEditor.reset(); repaint(); };
692-
textEditor->onFocusLost = [this] { textEditor.reset(); repaint(); };
693707
return;
694708
}
695709

@@ -806,9 +820,13 @@ void SliceControlBar::showTextEditor (const ParamCell& cell, float currentValue)
806820
float minV = cell.minVal;
807821
float maxV = cell.maxVal;
808822

809-
textEditor->onReturnKey = [this, fieldId, minV, maxV] {
810-
if (textEditor == nullptr) return;
811-
float val = textEditor->getText().getFloatValue();
823+
juce::Component::SafePointer<SliceControlBar> safeThis (this);
824+
825+
textEditor->onReturnKey = [safeThis, fieldId, minV, maxV] {
826+
if (safeThis == nullptr) return;
827+
auto& self = *safeThis;
828+
if (self.textEditor == nullptr) return;
829+
float val = self.textEditor->getText().getFloatValue();
812830

813831
// Convert ms to seconds for ATK/DEC/REL, percent to fraction for SUS
814832
if (fieldId == IntersectProcessor::FieldAttack ||
@@ -825,19 +843,26 @@ void SliceControlBar::showTextEditor (const ParamCell& cell, float currentValue)
825843
cmd.type = IntersectProcessor::CmdSetSliceParam;
826844
cmd.intParam1 = fieldId;
827845
cmd.floatParam1 = val;
828-
processor.pushCommand (cmd);
829-
textEditor.reset();
830-
repaint();
846+
self.processor.pushCommand (cmd);
847+
self.textEditor->onFocusLost = nullptr;
848+
self.textEditor.reset();
849+
self.repaint();
831850
};
832851

833-
textEditor->onEscapeKey = [this] {
834-
textEditor.reset();
835-
repaint();
852+
textEditor->onEscapeKey = [safeThis] {
853+
if (safeThis == nullptr) return;
854+
auto& self = *safeThis;
855+
self.textEditor->onFocusLost = nullptr;
856+
self.textEditor.reset();
857+
self.repaint();
836858
};
837859

838-
textEditor->onFocusLost = [this] {
839-
textEditor.reset();
840-
repaint();
860+
textEditor->onFocusLost = [safeThis] {
861+
if (safeThis == nullptr) return;
862+
auto& self = *safeThis;
863+
self.textEditor->onFocusLost = nullptr;
864+
self.textEditor.reset();
865+
self.repaint();
841866
};
842867
}
843868

0 commit comments

Comments
 (0)