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:
parent
576d3e3013
commit
6525bb18cf
@ -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;
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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),
|
||||
|
Loading…
x
Reference in New Issue
Block a user