// native_bridge/tests/seh_channel_test.cpp // G3.3: SEH per-channel crash isolation. A plugin whose processAudioBlock // faults (access violation) must be caught by SafeProcessChannel -> renderAll // mutes the channel instead of taking down the whole bridge process. // Assert-based, no framework. Includes the engine .cpp (like shm_selfcheck). #include "../include/NativeInstrumentEngine.h" #include "../src/NativeInstrumentEngine.cpp" #include #include #include class CrashingStub : public INativeInstrument { public: bool init(double, uint32_t) override { return true; } void selectProgram(uint32_t, uint32_t, uint32_t) override {} void noteOn(uint32_t, uint32_t, float, uint32_t) override {} void noteOff(uint32_t, uint32_t, uint32_t) override {} void controlChange(uint32_t, uint32_t, uint32_t) override {} void programChange(uint32_t, uint32_t) override {} void pitchBend(uint32_t, uint32_t) override {} bool openGUI(void*) override { return false; } void closeGUI() override {} void processAudioBlock(float*, float*, uint32_t) override { volatile int* p = nullptr; *p = 42; // deliberate access violation } }; class OkStub : public INativeInstrument { public: bool init(double, uint32_t) override { return true; } void selectProgram(uint32_t, uint32_t, uint32_t) override {} void noteOn(uint32_t, uint32_t, float, uint32_t) override {} void noteOff(uint32_t, uint32_t, uint32_t) override {} void controlChange(uint32_t, uint32_t, uint32_t) override {} void programChange(uint32_t, uint32_t) override {} void pitchBend(uint32_t, uint32_t) override {} bool openGUI(void*) override { return false; } void closeGUI() override {} void processAudioBlock(float* outL, float* outR, uint32_t n) override { for (uint32_t i = 0; i < n; ++i) { outL[i] = 1.0f; outR[i] = 2.0f; } } }; int main() { // 1. Faulting plugin: SEH catches the AV, process survives, returns false. { float L[64] = {}, R[64] = {}; CrashingStub stub; bool ok = SafeProcessChannel(&stub, L, R, 64); assert(!ok); // Block left untouched (renderAll continues without this channel). bool allZero = true; for (float f : L) if (f != 0.0f) allZero = false; assert(allZero); } // 2. Healthy plugin passes through unchanged. { float L[64] = {}, R[64] = {}; OkStub stub; bool ok = SafeProcessChannel(&stub, L, R, 64); assert(ok); assert(L[0] == 1.0f && R[0] == 2.0f); } // 3. Manager crash-mute flags: set, read, and renderAll skips a crashed // channel (no exception escapes into the audio loop). { InstrumentEngineManager mgr; assert(!mgr.isCrashed(3)); mgr.markCrashed(3); assert(mgr.isCrashed(3)); assert(!mgr.isCrashed(4)); // other channels unaffected float L[64] = {}, R[64] = {}; mgr.renderAll(L, R, 64); // crashed + unassigned: no-op, no crash assert(L[0] == 0.0f); } std::printf("SEH_CHANNEL_TEST PASS\n"); return 0; }