Undo-block review fixes: exception-safe depth, corrected docs, real test teeth
Fixes ctor exception safety, a ValidatePtr2 guard, false SDK-citation and enforcement claims, the span-depth invariant, and vacuous fx_reclaim tests.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#define REAPERAPI_MINIMAL
|
||||
#define REAPERAPI_WANT_Undo_BeginBlock2
|
||||
#define REAPERAPI_WANT_Undo_EndBlock2
|
||||
#define REAPERAPI_WANT_ValidatePtr2
|
||||
#include "reaper_plugin_functions.h"
|
||||
|
||||
namespace reasampler {
|
||||
@@ -31,15 +32,36 @@ UndoBlock::UndoBlock(ReaProject* proj) : project_(proj) {
|
||||
// enclosing UndoBlock already did it, and a close from here would land at depth
|
||||
// 2->1 — minting nothing and hijacking the enclosing block's label instead. That is
|
||||
// the same criterion applyMode's reapply is gated on.
|
||||
if (g_depth++ == 0) fxReclaimEndUndoSpan();
|
||||
Undo_BeginBlock2(proj);
|
||||
//
|
||||
// The whole body is one try: fxReclaimEndUndoSpan's closeSpan copies a std::string
|
||||
// and can throw. A throwing constructor runs no destructor, so an uncompensated
|
||||
// ++g_depth would stick forever — undoBlockOpen() reads true for the rest of the
|
||||
// session, fxReclaimTick refuses every tick, and no later UndoBlock is ever
|
||||
// outermost. Roll the depth back on any throw so the type degrades to "this one
|
||||
// block failed to open," not "every block after it is now poisoned."
|
||||
try {
|
||||
if (g_depth++ == 0) fxReclaimEndUndoSpan();
|
||||
Undo_BeginBlock2(proj);
|
||||
} catch (...) {
|
||||
--g_depth;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
UndoBlock::~UndoBlock() {
|
||||
// Depth drops AFTER the SDK call, not before: the close that reaches depth 0 mints a
|
||||
// point, and anything re-entered through that must still read a block as open rather
|
||||
// than let the drain open a span underneath it.
|
||||
Undo_EndBlock2(project_, label_.c_str(), mask_);
|
||||
//
|
||||
// Guarded the same way fx_reclaim.cpp's closeSpan guards its own Undo_EndBlock2, but
|
||||
// only for a REAL pinned pointer: `project_ == nullptr` means "the active project",
|
||||
// the same convention Undo_BeginBlock2 was handed, and ValidatePtr2 does not accept
|
||||
// nullptr as a valid object of any type — guarding it unconditionally would silently
|
||||
// stop every `UndoBlock undo(nullptr)` site (most of them) from ever closing. A real
|
||||
// pointer, by contrast, can go stale: several call sites allocate freely between open
|
||||
// and close, and the project it named may have closed underneath by now.
|
||||
if (!project_ || ValidatePtr2(nullptr, project_, "ReaProject*"))
|
||||
Undo_EndBlock2(project_, label_.c_str(), mask_);
|
||||
--g_depth;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user