1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-16 08:34:10 +02:00

Translate exceptions to error codes in callback functions...

... That is what the library protocols allow, and libraries may be written
in C and might corrupt their state if C++ exceptions pass through them.
This commit is contained in:
Paul Licameli 2016-11-21 16:32:16 -05:00
parent 576d3e3013
commit 6525bb18cf
6 changed files with 173 additions and 139 deletions

View File

@ -91,6 +91,7 @@ scroll information. It also has some status flags.
#endif
#endif
#include "AudacityException.h"
#include "FreqWindow.h"
#include "effects/Contrast.h"
#include "AutoRecovery.h"
@ -446,19 +447,25 @@ public:
bool OnDropFiles(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxArrayString& filenames) override
{
//sort by OD non OD. load Non OD first so user can start editing asap.
wxArrayString sortednames(filenames);
// Experiment shows that this function can be reached while there is no
// catch block above in wxWidgets. So stop all exceptions here.
return GuardedCall< bool > ( [&] {
//sort by OD non OD. load Non OD first so user can start editing asap.
wxArrayString sortednames(filenames);
ODManager::Pauser pauser;
ODManager::Pauser pauser;
sortednames.Sort(CompareNoCaseFileName);
for (unsigned int i = 0; i < sortednames.GetCount(); i++) {
sortednames.Sort(CompareNoCaseFileName);
mProject->Import(sortednames[i]);
}
mProject->HandleResize(); // Adjust scrollers for NEW track sizes.
for (unsigned int i = 0; i < sortednames.GetCount(); i++) {
return true;
mProject->Import(sortednames[i]);
}
mProject->HandleResize(); // Adjust scrollers for NEW track sizes.
return true;
} );
}
private:
@ -487,7 +494,14 @@ bool ImportXMLTagHandler::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
}
WaveTrackArray trackArray;
mProject->Import(strAttr, &trackArray);
// Guard this call so that C++ exceptions don't propagate through
// the expat library
GuardedCall< void >(
[&] { mProject->Import(strAttr, &trackArray); },
[&] (AudacityException*) { trackArray.clear(); }
);
if (trackArray.empty())
return false;

View File

@ -86,6 +86,7 @@ CommandManager. It holds the callback for one command.
#include <wx/msgdlg.h>
#include <wx/tokenzr.h>
#include "../AudacityException.h"
#include "../Prefs.h"
#include "../Project.h"
@ -190,47 +191,51 @@ public:
int FilterEvent(wxEvent& event) override
{
// Quickly bail if this isn't something we want.
wxEventType type = event.GetEventType();
if (type != wxEVT_CHAR_HOOK && type != wxEVT_KEY_UP)
{
// Unguarded exception propagation may crash the program, at least
// on Mac while in the objective-C closure above
return GuardedCall< int > ( [&] {
// Quickly bail if this isn't something we want.
wxEventType type = event.GetEventType();
if (type != wxEVT_CHAR_HOOK && type != wxEVT_KEY_UP)
{
return Event_Skip;
}
// We must have a project since we will be working with the Command Manager
// and capture handler, both of which are (currently) tied to individual projects.
//
// Shouldn't they be tied to the application instead???
AudacityProject *project = GetActiveProject();
if (!project || !project->IsEnabled())
{
return Event_Skip;
}
// Make a copy of the event and (possibly) make it look like a key down
// event.
wxKeyEvent key = (wxKeyEvent &) event;
if (type == wxEVT_CHAR_HOOK)
{
key.SetEventType(wxEVT_KEY_DOWN);
}
// Give the capture handler first dibs at the event.
wxWindow *handler = project->GetKeyboardCaptureHandler();
if (handler && HandleCapture(handler, key))
{
return Event_Processed;
}
// Capture handler didn't want it, so ask the Command Manager.
CommandManager *manager = project->GetCommandManager();
if (manager && manager->FilterKeyEvent(project, key))
{
return Event_Processed;
}
// Give it back to WX for normal processing.
return Event_Skip;
}
// We must have a project since we will be working with the Command Manager
// and capture handler, both of which are (currently) tied to individual projects.
//
// Shouldn't they be tied to the application instead???
AudacityProject *project = GetActiveProject();
if (!project || !project->IsEnabled())
{
return Event_Skip;
}
// Make a copy of the event and (possibly) make it look like a key down
// event.
wxKeyEvent key = (wxKeyEvent &) event;
if (type == wxEVT_CHAR_HOOK)
{
key.SetEventType(wxEVT_KEY_DOWN);
}
// Give the capture handler first dibs at the event.
wxWindow *handler = project->GetKeyboardCaptureHandler();
if (handler && HandleCapture(handler, key))
{
return Event_Processed;
}
// Capture handler didn't want it, so ask the Command Manager.
CommandManager *manager = project->GetCommandManager();
if (manager && manager->FilterKeyEvent(project, key))
{
return Event_Processed;
}
// Give it back to WX for normal processing.
return Event_Skip;
}, MakeSimpleGuard( Event_Skip ) );
}
private:

View File

@ -45,6 +45,7 @@ effects from this one class.
#include <wx/numformatter.h>
#include "../../AudacityApp.h"
#include "../../AudacityException.h"
#include "../../FileNames.h"
#include "../../Internat.h"
#include "../../LabelTrack.h"
@ -1832,23 +1833,26 @@ int NyquistEffect::StaticPutCallback(float *buffer, int channel,
int NyquistEffect::PutCallback(float *buffer, int channel,
long start, long len, long totlen)
{
if (channel == 0) {
double progress = mScale*((float)(start+len)/totlen);
// Don't let C++ exceptions propagate through the Nyquist library
return GuardedCall<int>( [&] {
if (channel == 0) {
double progress = mScale*((float)(start+len)/totlen);
if (progress > mProgressOut) {
mProgressOut = progress;
if (progress > mProgressOut) {
mProgressOut = progress;
}
if (TotalProgress(mProgressIn+mProgressOut+mProgressTot)) {
return -1;
}
}
if (TotalProgress(mProgressIn+mProgressOut+mProgressTot)) {
return -1;
if (mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len)) {
return 0; // success
}
}
if (mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len)) {
return 0; // success
}
return -1; // failure
return -1; // failure
}, MakeSimpleGuard( -1 ) ); // translate all exceptions into failure
}
void NyquistEffect::StaticOutputCallback(int c, void *This)

View File

@ -37,6 +37,7 @@
#include <wx/intl.h> // needed for _("translated stings") even if we
// don't have libflac available
#include "../AudacityException.h"
#include "Import.h"
#include "ImportPlugin.h"
@ -252,35 +253,38 @@ void MyFLACFile::error_callback(FLAC__StreamDecoderErrorStatus WXUNUSED(status))
FLAC__StreamDecoderWriteStatus MyFLACFile::write_callback(const FLAC__Frame *frame,
const FLAC__int32 * const buffer[])
{
ArrayOf<short> tmp{ frame->header.blocksize };
// Don't let C++ exceptions propagate through libflac
return GuardedCall< FLAC__StreamDecoderWriteStatus > ( [&] {
auto tmp = ArrayOf< short >{ frame->header.blocksize };
auto iter = mFile->mChannels.begin();
for (unsigned int chn=0; chn<mFile->mNumChannels; ++iter, ++chn) {
if (frame->header.bits_per_sample == 16) {
for (unsigned int s=0; s<frame->header.blocksize; s++) {
tmp[s]=buffer[chn][s];
auto iter = mFile->mChannels.begin();
for (unsigned int chn=0; chn<mFile->mNumChannels; ++iter, ++chn) {
if (frame->header.bits_per_sample == 16) {
for (unsigned int s=0; s<frame->header.blocksize; s++) {
tmp[s]=buffer[chn][s];
}
iter->get()->Append((samplePtr)tmp.get(),
int16Sample,
frame->header.blocksize);
}
else {
iter->get()->Append((samplePtr)buffer[chn],
int24Sample,
frame->header.blocksize);
}
iter->get()->Append((samplePtr)tmp.get(),
int16Sample,
frame->header.blocksize);
}
else {
iter->get()->Append((samplePtr)buffer[chn],
int24Sample,
frame->header.blocksize);
mFile->mSamplesDone += frame->header.blocksize;
mFile->mUpdateResult = mFile->mProgress->Update((wxULongLong_t) mFile->mSamplesDone, mFile->mNumSamples != 0 ? (wxULongLong_t)mFile->mNumSamples : 1);
if (mFile->mUpdateResult != ProgressResult::Success)
{
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
}
mFile->mSamplesDone += frame->header.blocksize;
mFile->mUpdateResult = mFile->mProgress->Update((wxULongLong_t) mFile->mSamplesDone, mFile->mNumSamples != 0 ? (wxULongLong_t)mFile->mNumSamples : 1);
if (mFile->mUpdateResult != ProgressResult::Success)
{
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}, MakeSimpleGuard(FLAC__STREAM_DECODER_WRITE_STATUS_ABORT) );
}

View File

@ -46,6 +46,7 @@ Licensed under the GNU General Public License v2 or later
#endif
// all the includes live here by default
#include "../AudacityException.h"
#include "../SampleFormat.h"
#include "../Tags.h"
#include "../Internat.h"
@ -489,20 +490,23 @@ inline void GstSampleUnref(GstSample *p) { gst_sample_unref(p); } // I can't use
static GstFlowReturn
GStreamerNewSample(GstAppSink *appsink, gpointer data)
{
GStreamerImportFileHandle *handle = (GStreamerImportFileHandle *)data;
static GMutex mutex;
// Don't let C++ exceptions propagate through GStreamer
return GuardedCall< GstFlowReturn > ( [&] {
GStreamerImportFileHandle *handle = (GStreamerImportFileHandle *)data;
static GMutex mutex;
// Get the sample
std::unique_ptr < GstSample, Deleter< GstSample, GstSampleUnref> >
sample{ gst_app_sink_pull_sample(appsink) };
// Get the sample
std::unique_ptr < GstSample, Deleter< GstSample, GstSampleUnref> >
sample{ gst_app_sink_pull_sample(appsink) };
// We must single thread here to prevent concurrent use of the
// Audacity track functions.
g_mutex_locker locker{ mutex };
// We must single thread here to prevent concurrent use of the
// Audacity track functions.
g_mutex_locker locker{ mutex };
handle->OnNewSample(GETCTX(appsink), sample.get());
handle->OnNewSample(GETCTX(appsink), sample.get());
return GST_FLOW_OK;
return GST_FLOW_OK;
}, MakeSimpleGuard(GST_FLOW_ERROR) );
}
// ----------------------------------------------------------------------------

View File

@ -39,6 +39,7 @@
#include <wx/defs.h>
#include <wx/intl.h>
#include "../AudacityException.h"
#include "../Prefs.h"
#include "Import.h"
#include "ImportPlugin.h"
@ -480,59 +481,61 @@ enum mad_flow output_cb(void *_data,
struct mad_header const * WXUNUSED(header),
struct mad_pcm *pcm)
{
int samplerate;
struct private_data *data = (struct private_data *)_data;
// Don't C++ exceptions propagate through mad
return GuardedCall< mad_flow > ( [&] {
int samplerate;
struct private_data *data = (struct private_data *)_data;
samplerate= pcm->samplerate;
auto channels = pcm->channels;
const auto samples = pcm->length;
samplerate= pcm->samplerate;
auto channels = pcm->channels;
const auto samples = pcm->length;
/* If this is the first run, we need to create the WaveTracks that
* will hold the data. We do this now because now is the first
* moment when we know how many channels there are. */
/* If this is the first run, we need to create the WaveTracks that
* will hold the data. We do this now because now is the first
* moment when we know how many channels there are. */
if(data->channels.empty()) {
data->channels.resize(channels);
if(data->channels.empty()) {
data->channels.resize(channels);
sampleFormat format = (sampleFormat) gPrefs->
Read(wxT("/SamplingRate/DefaultProjectSampleFormat"), floatSample);
sampleFormat format = (sampleFormat) gPrefs->
Read(wxT("/SamplingRate/DefaultProjectSampleFormat"), floatSample);
for(auto &channel: data->channels) {
channel = data->trackFactory->NewWaveTrack(format, samplerate);
channel->SetChannel(Track::MonoChannel);
for(auto &channel: data->channels) {
channel = data->trackFactory->NewWaveTrack(format, samplerate);
channel->SetChannel(Track::MonoChannel);
}
/* special case: 2 channels is understood to be stereo */
if(channels == 2) {
data->channels.begin()->get()->SetChannel(Track::LeftChannel);
data->channels.rbegin()->get()->SetChannel(Track::RightChannel);
data->channels.begin()->get()->SetLinked(true);
}
data->numChannels = channels;
}
else {
// This is not the first run, protect us from libmad glitching
// on the number of channels
channels = data->numChannels;
}
/* special case: 2 channels is understood to be stereo */
if(channels == 2) {
data->channels.begin()->get()->SetChannel(Track::LeftChannel);
data->channels.rbegin()->get()->SetChannel(Track::RightChannel);
data->channels.begin()->get()->SetLinked(true);
}
data->numChannels = channels;
}
else {
// This is not the first run, protect us from libmad glitching
// on the number of channels
channels = data->numChannels;
}
/* TODO: get rid of this by adding fixed-point support to SampleFormat.
* For now, we allocate temporary float buffers to convert the fixed
* point samples into something we can feed to the WaveTrack. Allocating
* big blocks of data like this isn't a great idea, but it's temporary.
*/
FloatBuffers channelBuffers{ channels, samples };
for(size_t smpl = 0; smpl < samples; smpl++)
for(int chn = 0; chn < channels; chn++)
channelBuffers[chn][smpl] = scale(pcm->samples[chn][smpl]);
/* TODO: get rid of this by adding fixed-point support to SampleFormat.
* For now, we allocate temporary float buffers to convert the fixed
* point samples into something we can feed to the WaveTrack. Allocating
* big blocks of data like this isn't a great idea, but it's temporary.
*/
FloatBuffers channelBuffers{ channels, samples };
for (size_t smpl = 0; smpl < samples; smpl++)
for(int chn = 0; chn < channels; chn++)
channelBuffers[chn][smpl] = scale(pcm->samples[chn][smpl]);
data->channels[chn]->Append((samplePtr)channelBuffers[chn].get(),
floatSample,
samples);
for (int chn = 0; chn < channels; chn++)
data->channels[chn]->Append((samplePtr)channelBuffers[chn].get(),
floatSample,
samples);
return MAD_FLOW_CONTINUE;
return MAD_FLOW_CONTINUE;
}, MakeSimpleGuard(MAD_FLOW_BREAK) );
}
enum mad_flow error_cb(void * WXUNUSED(_data), struct mad_stream * WXUNUSED(stream),