From ddbc38c7fecd41c07468bcf6725469454867b30a Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 24 Jul 2022 18:31:08 -0700 Subject: [PATCH] Move most large stack using buffers to the heap This should solve most potential future stack overflows. Signed-off-by: Christopher Snowhill --- Audio/Output/FSurroundFilter.h | 1 + Audio/Output/FSurroundFilter.mm | 7 +- Audio/Visualization/VisualizationController.h | 1 + Audio/Visualization/VisualizationController.m | 7 +- .../File_Extractor/unrar/unpack.cpp | 12 +-- Plugins/GME/GameDecoder.h | 2 + Plugins/GME/GameDecoder.m | 5 +- Plugins/Hively/Hively/HVLDecoder.h | 2 + Plugins/Hively/Hively/HVLDecoder.m | 15 ++-- Plugins/MAD/MADDecoder.m | 89 ++++++++++++------- Plugins/Musepack/MusepackDecoder.h | 3 + Plugins/Musepack/MusepackDecoder.m | 7 +- .../SilenceDecoder/SilenceDecoder.h | 2 + .../SilenceDecoder/SilenceDecoder.m | 20 ++--- SpectrumViewCG.m | 4 +- Visualization/SpectrumViewSK.m | 4 +- 16 files changed, 106 insertions(+), 75 deletions(-) diff --git a/Audio/Output/FSurroundFilter.h b/Audio/Output/FSurroundFilter.h index 19812ba82..0873dae02 100644 --- a/Audio/Output/FSurroundFilter.h +++ b/Audio/Output/FSurroundFilter.h @@ -20,6 +20,7 @@ double srate; uint32_t channelCount; uint32_t channelConfig; + float tempBuffer[4096 * 2]; } - (id)initWithSampleRate:(double)srate; diff --git a/Audio/Output/FSurroundFilter.mm b/Audio/Output/FSurroundFilter.mm index f1f3f1393..9855e2a60 100644 --- a/Audio/Output/FSurroundFilter.mm +++ b/Audio/Output/FSurroundFilter.mm @@ -129,7 +129,6 @@ struct freesurround_params { freesurround_params *_params = (freesurround_params *)params; freesurround_decoder *_decoder = (freesurround_decoder *)decoder; - float tempInput[4096 * 2]; uint32_t zeroCount = 0; if(count > 4096) { @@ -138,9 +137,9 @@ struct freesurround_params { } if(count < 4096) { - cblas_scopy(count * 2, samplesIn, 1, &tempInput[0], 1); - vDSP_vclr(&tempInput[count * 2], 1, (4096 - count) * 2); - samplesIn = &tempInput[0]; + cblas_scopy(count * 2, samplesIn, 1, &tempBuffer[0], 1); + vDSP_vclr(&tempBuffer[count * 2], 1, (4096 - count) * 2); + samplesIn = &tempBuffer[0]; } float *src = _decoder->decode(samplesIn); diff --git a/Audio/Visualization/VisualizationController.h b/Audio/Visualization/VisualizationController.h index 68390ef27..c52e291c3 100644 --- a/Audio/Visualization/VisualizationController.h +++ b/Audio/Visualization/VisualizationController.h @@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN double latency; float *visAudio; int visAudioCursor, visAudioSize; + float *visAudioTemp; } + (VisualizationController *)sharedController; diff --git a/Audio/Visualization/VisualizationController.m b/Audio/Visualization/VisualizationController.m index 3cbe61b43..d25030c3d 100644 --- a/Audio/Visualization/VisualizationController.m +++ b/Audio/Visualization/VisualizationController.m @@ -28,6 +28,10 @@ static VisualizationController *_sharedController = nil; if(self) { visAudio = NULL; latency = 0; + visAudioTemp = (float *) calloc(sizeof(float), 4096); + if(!visAudioTemp) { + return nil; + } } return self; } @@ -89,8 +93,7 @@ static VisualizationController *_sharedController = nil; return; } - float tempPCM[4096]; - if(!outPCM) outPCM = &tempPCM[0]; + if(!outPCM) outPCM = &visAudioTemp[0]; @synchronized(self) { if(!sampleRate) { diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unpack.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unpack.cpp index 4504b1859..a2c4e0171 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unpack.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unpack.cpp @@ -30,17 +30,19 @@ Unpack::Unpack(ComprDataIO *DataIO) void Unpack::init_tables() { - ComprDataIO IOTemp; - Unpack Temp(&IOTemp); + ComprDataIO *IOTemp = new ComprDataIO; + Unpack *Temp = new Unpack(IOTemp); // Perform initialization, which should be done only once for all files. // It prevents crash if first DoUnpack call is later made with wrong // (true) 'Solid' value. - Temp.UnpInitData(false); + Temp->UnpInitData(false); #ifndef SFX_MODULE // RAR 1.5 decompression initialization - Temp.UnpInitData15(false); - Temp.InitHuff(); + Temp->UnpInitData15(false); + Temp->InitHuff(); #endif + delete Temp; + delete IOTemp; } diff --git a/Plugins/GME/GameDecoder.h b/Plugins/GME/GameDecoder.h index 72ae4d69d..cddc3f859 100644 --- a/Plugins/GME/GameDecoder.h +++ b/Plugins/GME/GameDecoder.h @@ -21,6 +21,8 @@ extern gme_err_t readCallback(void* data, void* out, int count); long length; long fade; NSString* codec; + + int16_t sampleBuffer[1024 * 2]; } - (void)setSource:(id)s; diff --git a/Plugins/GME/GameDecoder.m b/Plugins/GME/GameDecoder.m index 528669e23..7477f6d39 100644 --- a/Plugins/GME/GameDecoder.m +++ b/Plugins/GME/GameDecoder.m @@ -176,8 +176,7 @@ gme_err_t readCallback(void *data, void *out, int count) { - (AudioChunk *)readAudio { int frames = 1024; - int16_t buffer[frames * 2]; - void *buf = (void *)buffer; + void *buf = (void *)sampleBuffer; id audioChunkClass = NSClassFromString(@"AudioChunk"); AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; @@ -199,7 +198,7 @@ gme_err_t readCallback(void *data, void *out, int count) { //(From gme.txt) If track length, then use it. If loop length, play for intro + loop * 2. Otherwise, default to 2.5 minutes // GME will always generate samples. There's no real EOS. - [chunk assignSamples:buffer frameCount:numSamples]; + [chunk assignSamples:sampleBuffer frameCount:numSamples]; return chunk; } diff --git a/Plugins/Hively/Hively/HVLDecoder.h b/Plugins/Hively/Hively/HVLDecoder.h index 1ed05141c..4a6c78db1 100644 --- a/Plugins/Hively/Hively/HVLDecoder.h +++ b/Plugins/Hively/Hively/HVLDecoder.h @@ -24,5 +24,7 @@ long framesFade; long framesRead; long framesInBuffer; + + float sampleBuffer[1024 * 2]; } @end diff --git a/Plugins/Hively/Hively/HVLDecoder.m b/Plugins/Hively/Hively/HVLDecoder.m index b56c4ad98..46352b00a 100644 --- a/Plugins/Hively/Hively/HVLDecoder.m +++ b/Plugins/Hively/Hively/HVLDecoder.m @@ -10,6 +10,8 @@ #import "PlaylistController.h" +#import + static void oneTimeInit(void) { static BOOL initialized = NO; if(!initialized) { @@ -109,8 +111,7 @@ static void oneTimeInit(void) { - (AudioChunk *)readAudio { int frames = 1024; - float buffer[frames * 2]; - void *buf = (void *)buffer; + void *buf = (void *)sampleBuffer; BOOL repeatone = IsRepeatOneSet(); @@ -124,11 +125,9 @@ static void oneTimeInit(void) { int framesToCopy = frames - total; if(framesToCopy > framesInBuffer) framesToCopy = (int)framesInBuffer; - for(int i = 0; i < framesToCopy; ++i) { - outbuffer[0] = buffer[i * 2 + 0] * (1.0f / 16777216.0f); - outbuffer[1] = buffer[i * 2 + 1] * (1.0f / 16777216.0f); - outbuffer += 2; - } + vDSP_vflt32(&buffer[0], 1, &outbuffer[0], 1, framesToCopy * 2); + float scale = 16777216.0f; + vDSP_vsdiv(&outbuffer[0], 1, &scale, &outbuffer[0], 1, framesToCopy * 2); framesInBuffer -= framesToCopy; total += framesToCopy; if(framesInBuffer) { @@ -163,7 +162,7 @@ static void oneTimeInit(void) { id audioChunkClass = NSClassFromString(@"AudioChunk"); AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; - [chunk assignSamples:buffer frameCount:total]; + [chunk assignSamples:sampleBuffer frameCount:total]; return chunk; } diff --git a/Plugins/MAD/MADDecoder.m b/Plugins/MAD/MADDecoder.m index 6e5b7e69d..3c1a1071f 100644 --- a/Plugins/MAD/MADDecoder.m +++ b/Plugins/MAD/MADDecoder.m @@ -74,29 +74,36 @@ } - (BOOL)scanFile { - struct mad_stream stream; - struct mad_frame frame; + struct mad_stream *stream; + struct mad_frame *frame; + + stream = (struct mad_stream *) calloc(sizeof(struct mad_stream), 1); + frame = (struct mad_frame *) calloc(sizeof(struct mad_frame), 1); + if(!stream || !frame) { + ALog(@"Out of memory!"); + return NO; + } long framesDecoded = 0; int samplesPerMPEGFrame = 0; int id3_length = 0; - mad_stream_init(&stream); - mad_frame_init(&frame); + mad_stream_init(stream); + mad_frame_init(frame); [_source seek:0 whence:SEEK_END]; _fileSize = [_source tell]; [_source seek:0 whence:SEEK_SET]; for(;;) { - [self bufferRefill:&stream]; + [self bufferRefill:stream]; - if(mad_frame_decode(&frame, &stream) == -1) { - if(MAD_RECOVERABLE(stream.error)) { + if(mad_frame_decode(frame, stream) == -1) { + if(MAD_RECOVERABLE(stream->error)) { // Prevent ID3 tags from reporting recoverable frame errors - const uint8_t *buffer = stream.this_frame; - unsigned long buflen = stream.bufend - stream.this_frame; + const uint8_t *buffer = stream->this_frame; + unsigned long buflen = stream->bufend - stream->this_frame; if(10 <= buflen && 0x49 == buffer[0] && 0x44 == buffer[1] && 0x33 == buffer[2]) { id3_length = (((buffer[6] & 0x7F) << (3 * 7)) | ((buffer[7] & 0x7F) << (2 * 7)) | @@ -108,7 +115,7 @@ id3_length += 10; void *tagBuffer = malloc(id3_length); - if(!tagBuffer) return NO; + if(!tagBuffer) goto error; memcpy(tagBuffer, &buffer[0], MIN(buflen, id3_length)); @@ -116,18 +123,18 @@ long tagRead = MIN(buflen, id3_length); while(bufleft > 0) { - stream.error = MAD_ERROR_BUFLEN; - stream.next_frame = NULL; - [self bufferRefill:&stream]; - buffer = stream.this_frame; - buflen = stream.bufend - stream.this_frame; + stream->error = MAD_ERROR_BUFLEN; + stream->next_frame = NULL; + [self bufferRefill:stream]; + buffer = stream->this_frame; + buflen = stream->bufend - stream->this_frame; memcpy(tagBuffer + tagRead, buffer, MIN(buflen, bufleft)); tagRead += MIN(buflen, bufleft); bufleft -= buflen; } if(bufleft < 0) { - mad_stream_skip(&stream, buflen + bufleft); + mad_stream_skip(stream, buflen + bufleft); } struct id3_tag *tag = id3_tag_parse(tagBuffer, id3_length); @@ -180,14 +187,14 @@ } free(tagBuffer); - } else if(stream.error == MAD_ERROR_BADDATAPTR) { + } else if(stream->error == MAD_ERROR_BADDATAPTR) { goto framedecoded; } continue; - } else if(stream.error == MAD_ERROR_BUFLEN && inputEOF) { + } else if(stream->error == MAD_ERROR_BUFLEN && inputEOF) { break; - } else if(stream.error == MAD_ERROR_BUFLEN) { + } else if(stream->error == MAD_ERROR_BUFLEN) { continue; } else { // DLog(@"Unrecoverable error: %s", mad_stream_errorstr(&stream)); @@ -198,11 +205,11 @@ framesDecoded++; if(framesDecoded == 1) { - sampleRate = frame.header.samplerate; - channels = MAD_NCHANNELS(&frame.header); + sampleRate = frame->header.samplerate; + channels = MAD_NCHANNELS(&frame->header); - if(MAD_FLAG_LSF_EXT & frame.header.flags || MAD_FLAG_MPEG_2_5_EXT & frame.header.flags) { - switch(frame.header.layer) { + if(MAD_FLAG_LSF_EXT & frame->header.flags || MAD_FLAG_MPEG_2_5_EXT & frame->header.flags) { + switch(frame->header.layer) { case MAD_LAYER_I: samplesPerMPEGFrame = 384; layer = 1; @@ -217,7 +224,7 @@ break; } } else { - switch(frame.header.layer) { + switch(frame->header.layer) { case MAD_LAYER_I: samplesPerMPEGFrame = 384; layer = 1; @@ -235,16 +242,16 @@ if(layer != 3) continue; - const size_t ancillaryBitsRemaining = (stream.next_frame - stream.this_frame) * 8; + const size_t ancillaryBitsRemaining = (stream->next_frame - stream->this_frame) * 8; static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; - const int64_t xing_offset = xing_offtbl[!!(MAD_FLAG_LSF_EXT & frame.header.flags || MAD_FLAG_MPEG_2_5_EXT & frame.header.flags)][channels == 1] + 4; // Plus MPEG header + const int64_t xing_offset = xing_offtbl[!!(MAD_FLAG_LSF_EXT & frame->header.flags || MAD_FLAG_MPEG_2_5_EXT & frame->header.flags)][channels == 1] + 4; // Plus MPEG header size_t ancBitsRemainingXing = ancillaryBitsRemaining - xing_offset * 8; if(ancBitsRemainingXing >= 32) { - const uint8_t *ptr = stream.this_frame + xing_offset; + const uint8_t *ptr = stream->this_frame + xing_offset; struct mad_bitptr bitptr; mad_bit_init(&bitptr, ptr); @@ -374,7 +381,7 @@ size_t ancBitsRemainingVBRI = ancillaryBitsRemaining - vbri_offset * 8; if(ancBitsRemainingVBRI >= 32) { - const uint8_t *ptr = stream.this_frame + vbri_offset; + const uint8_t *ptr = stream->this_frame + vbri_offset; struct mad_bitptr bitptr; mad_bit_init(&bitptr, ptr); @@ -407,22 +414,25 @@ } // Don't commit division by zero on bad files - if(stream.next_frame == stream.this_frame) { - return NO; + if(stream->next_frame == stream->this_frame) { + goto error; } if(!_foundiTunSMPB && !_foundXingHeader && !_foundVBRIHeader) { // Now do CBR estimation instead of full file scanning - size_t frameCount = (_fileSize - id3_length) / (stream.next_frame - stream.this_frame); - mad_timer_t duration = frame.header.duration; + size_t frameCount = (_fileSize - id3_length) / (stream->next_frame - stream->this_frame); + mad_timer_t duration = frame->header.duration; mad_timer_multiply(&duration, frameCount); totalFrames = mad_timer_count(duration, sampleRate); } bitrate = ((double)((_fileSize - id3_length) * 8) / 1000.0) * (sampleRate / (double)totalFrames); - mad_frame_finish(&frame); - mad_stream_finish(&stream); + mad_frame_finish(frame); + mad_stream_finish(stream); + + free(frame); + free(stream); [_source seek:0 whence:SEEK_SET]; inputEOF = NO; @@ -430,6 +440,17 @@ DLog(@"Mad properties: %@", [self properties]); return YES; + +error: + if(frame) { + mad_frame_finish(frame); + free(frame); + } + if(stream) { + mad_stream_finish(stream); + free(stream); + } + return NO; } - (BOOL)open:(id)source { diff --git a/Plugins/Musepack/MusepackDecoder.h b/Plugins/Musepack/MusepackDecoder.h index be65c9976..a656c3c80 100644 --- a/Plugins/Musepack/MusepackDecoder.h +++ b/Plugins/Musepack/MusepackDecoder.h @@ -20,6 +20,9 @@ char buffer[MPC_FRAME_LENGTH * 4]; int bufferFrames; + + MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH]; + float floatBuffer[1024 * 2]; int bitrate; float frequency; diff --git a/Plugins/Musepack/MusepackDecoder.m b/Plugins/Musepack/MusepackDecoder.m index 8cdf86fda..11619edf2 100644 --- a/Plugins/Musepack/MusepackDecoder.m +++ b/Plugins/Musepack/MusepackDecoder.m @@ -110,11 +110,8 @@ mpc_bool_t CanSeekProc(mpc_reader *p_reader) { } - (AudioChunk *)readAudio { - MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH]; - int frames = 1024; - float buffer[frames * 2]; - void *buf = (void *)buffer; + void *buf = (void *)floatBuffer; int framesRead = 0; int bytesPerFrame = sizeof(float) * 2; // bitsPerSample == 32, channels == 2 @@ -156,7 +153,7 @@ mpc_bool_t CanSeekProc(mpc_reader *p_reader) { id audioChunkClass = NSClassFromString(@"AudioChunk"); AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; - [chunk assignSamples:buffer frameCount:framesRead]; + [chunk assignSamples:floatBuffer frameCount:framesRead]; return chunk; } diff --git a/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.h b/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.h index 3201d8b41..45b57e07d 100644 --- a/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.h +++ b/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.h @@ -15,6 +15,8 @@ long length; long remain; + + float *buffer; } - (void)setSource:(id)s; diff --git a/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m b/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m index a7a1b4e17..16cb0030c 100644 --- a/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m +++ b/Plugins/SilenceDecoder/SilenceDecoder/SilenceDecoder.m @@ -27,6 +27,12 @@ enum { channels = 2 }; length = seconds * sample_rate; remain = length; + + buffer = (float *) calloc(sizeof(float), 1024 * channels); + if(!buffer) { + ALog(@"Out of memory!"); + return NO; + } [self willChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"]; @@ -52,23 +58,17 @@ enum { channels = 2 }; - (AudioChunk *)readAudio { int frames = 1024; - float buffer[frames * channels]; - void *buf = (void *)buffer; - - int total = frames; if(!IsRepeatOneSet()) { - if(total > remain) - total = (int)remain; + if(frames > remain) + frames = (int)remain; - remain -= total; + remain -= frames; } - memset(buf, 0, sizeof(float) * total * channels); - id audioChunkClass = NSClassFromString(@"AudioChunk"); AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; - [chunk assignSamples:buffer frameCount:total]; + [chunk assignSamples:buffer frameCount:frames]; return chunk; } diff --git a/SpectrumViewCG.m b/SpectrumViewCG.m index 46fc1bd3f..a770b2e73 100644 --- a/SpectrumViewCG.m +++ b/SpectrumViewCG.m @@ -39,6 +39,8 @@ extern NSString *CogPlaybackDidStopNotficiation; NSColor *borderColor; ddb_analyzer_t _analyzer; ddb_analyzer_draw_data_t _draw_data; + + float visAudio[4096], visFFT[2048]; } @end @@ -368,8 +370,6 @@ extern NSString *CogPlaybackDidStopNotficiation; _analyzer.view_width = self.bounds.size.width; } - float visAudio[4096], visFFT[2048]; - [self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0]; ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048); diff --git a/Visualization/SpectrumViewSK.m b/Visualization/SpectrumViewSK.m index c69e60a81..59e3768cd 100644 --- a/Visualization/SpectrumViewSK.m +++ b/Visualization/SpectrumViewSK.m @@ -42,6 +42,8 @@ extern NSString *CogPlaybackDidStopNotficiation; SCNVector3 cameraEulerAngles2d; SCNVector3 cameraPosition3d; SCNVector3 cameraEulerAngles3d; + + float visAudio[4096], visFFT[2048]; } @end @@ -274,8 +276,6 @@ extern NSString *CogPlaybackDidStopNotficiation; return; } - float visAudio[4096], visFFT[2048]; - [self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0]; ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048);