Move most large stack using buffers to the heap

This should solve most potential future stack overflows.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
main
Christopher Snowhill 2022-07-24 18:31:08 -07:00
parent eec8bf9f1c
commit ddbc38c7fe
16 changed files with 106 additions and 75 deletions

View File

@ -20,6 +20,7 @@
double srate; double srate;
uint32_t channelCount; uint32_t channelCount;
uint32_t channelConfig; uint32_t channelConfig;
float tempBuffer[4096 * 2];
} }
- (id)initWithSampleRate:(double)srate; - (id)initWithSampleRate:(double)srate;

View File

@ -129,7 +129,6 @@ struct freesurround_params {
freesurround_params *_params = (freesurround_params *)params; freesurround_params *_params = (freesurround_params *)params;
freesurround_decoder *_decoder = (freesurround_decoder *)decoder; freesurround_decoder *_decoder = (freesurround_decoder *)decoder;
float tempInput[4096 * 2];
uint32_t zeroCount = 0; uint32_t zeroCount = 0;
if(count > 4096) { if(count > 4096) {
@ -138,9 +137,9 @@ struct freesurround_params {
} }
if(count < 4096) { if(count < 4096) {
cblas_scopy(count * 2, samplesIn, 1, &tempInput[0], 1); cblas_scopy(count * 2, samplesIn, 1, &tempBuffer[0], 1);
vDSP_vclr(&tempInput[count * 2], 1, (4096 - count) * 2); vDSP_vclr(&tempBuffer[count * 2], 1, (4096 - count) * 2);
samplesIn = &tempInput[0]; samplesIn = &tempBuffer[0];
} }
float *src = _decoder->decode(samplesIn); float *src = _decoder->decode(samplesIn);

View File

@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
double latency; double latency;
float *visAudio; float *visAudio;
int visAudioCursor, visAudioSize; int visAudioCursor, visAudioSize;
float *visAudioTemp;
} }
+ (VisualizationController *)sharedController; + (VisualizationController *)sharedController;

View File

@ -28,6 +28,10 @@ static VisualizationController *_sharedController = nil;
if(self) { if(self) {
visAudio = NULL; visAudio = NULL;
latency = 0; latency = 0;
visAudioTemp = (float *) calloc(sizeof(float), 4096);
if(!visAudioTemp) {
return nil;
}
} }
return self; return self;
} }
@ -89,8 +93,7 @@ static VisualizationController *_sharedController = nil;
return; return;
} }
float tempPCM[4096]; if(!outPCM) outPCM = &visAudioTemp[0];
if(!outPCM) outPCM = &tempPCM[0];
@synchronized(self) { @synchronized(self) {
if(!sampleRate) { if(!sampleRate) {

View File

@ -30,17 +30,19 @@ Unpack::Unpack(ComprDataIO *DataIO)
void Unpack::init_tables() void Unpack::init_tables()
{ {
ComprDataIO IOTemp; ComprDataIO *IOTemp = new ComprDataIO;
Unpack Temp(&IOTemp); Unpack *Temp = new Unpack(IOTemp);
// Perform initialization, which should be done only once for all files. // Perform initialization, which should be done only once for all files.
// It prevents crash if first DoUnpack call is later made with wrong // It prevents crash if first DoUnpack call is later made with wrong
// (true) 'Solid' value. // (true) 'Solid' value.
Temp.UnpInitData(false); Temp->UnpInitData(false);
#ifndef SFX_MODULE #ifndef SFX_MODULE
// RAR 1.5 decompression initialization // RAR 1.5 decompression initialization
Temp.UnpInitData15(false); Temp->UnpInitData15(false);
Temp.InitHuff(); Temp->InitHuff();
#endif #endif
delete Temp;
delete IOTemp;
} }

View File

@ -21,6 +21,8 @@ extern gme_err_t readCallback(void* data, void* out, int count);
long length; long length;
long fade; long fade;
NSString* codec; NSString* codec;
int16_t sampleBuffer[1024 * 2];
} }
- (void)setSource:(id<CogSource>)s; - (void)setSource:(id<CogSource>)s;

View File

@ -176,8 +176,7 @@ gme_err_t readCallback(void *data, void *out, int count) {
- (AudioChunk *)readAudio { - (AudioChunk *)readAudio {
int frames = 1024; int frames = 1024;
int16_t buffer[frames * 2]; void *buf = (void *)sampleBuffer;
void *buf = (void *)buffer;
id audioChunkClass = NSClassFromString(@"AudioChunk"); id audioChunkClass = NSClassFromString(@"AudioChunk");
AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; 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 //(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. // GME will always generate samples. There's no real EOS.
[chunk assignSamples:buffer frameCount:numSamples]; [chunk assignSamples:sampleBuffer frameCount:numSamples];
return chunk; return chunk;
} }

View File

@ -24,5 +24,7 @@
long framesFade; long framesFade;
long framesRead; long framesRead;
long framesInBuffer; long framesInBuffer;
float sampleBuffer[1024 * 2];
} }
@end @end

View File

@ -10,6 +10,8 @@
#import "PlaylistController.h" #import "PlaylistController.h"
#import <Accelerate/Accelerate.h>
static void oneTimeInit(void) { static void oneTimeInit(void) {
static BOOL initialized = NO; static BOOL initialized = NO;
if(!initialized) { if(!initialized) {
@ -109,8 +111,7 @@ static void oneTimeInit(void) {
- (AudioChunk *)readAudio { - (AudioChunk *)readAudio {
int frames = 1024; int frames = 1024;
float buffer[frames * 2]; void *buf = (void *)sampleBuffer;
void *buf = (void *)buffer;
BOOL repeatone = IsRepeatOneSet(); BOOL repeatone = IsRepeatOneSet();
@ -124,11 +125,9 @@ static void oneTimeInit(void) {
int framesToCopy = frames - total; int framesToCopy = frames - total;
if(framesToCopy > framesInBuffer) if(framesToCopy > framesInBuffer)
framesToCopy = (int)framesInBuffer; framesToCopy = (int)framesInBuffer;
for(int i = 0; i < framesToCopy; ++i) { vDSP_vflt32(&buffer[0], 1, &outbuffer[0], 1, framesToCopy * 2);
outbuffer[0] = buffer[i * 2 + 0] * (1.0f / 16777216.0f); float scale = 16777216.0f;
outbuffer[1] = buffer[i * 2 + 1] * (1.0f / 16777216.0f); vDSP_vsdiv(&outbuffer[0], 1, &scale, &outbuffer[0], 1, framesToCopy * 2);
outbuffer += 2;
}
framesInBuffer -= framesToCopy; framesInBuffer -= framesToCopy;
total += framesToCopy; total += framesToCopy;
if(framesInBuffer) { if(framesInBuffer) {
@ -163,7 +162,7 @@ static void oneTimeInit(void) {
id audioChunkClass = NSClassFromString(@"AudioChunk"); id audioChunkClass = NSClassFromString(@"AudioChunk");
AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]];
[chunk assignSamples:buffer frameCount:total]; [chunk assignSamples:sampleBuffer frameCount:total];
return chunk; return chunk;
} }

View File

@ -74,29 +74,36 @@
} }
- (BOOL)scanFile { - (BOOL)scanFile {
struct mad_stream stream; struct mad_stream *stream;
struct mad_frame frame; 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; long framesDecoded = 0;
int samplesPerMPEGFrame = 0; int samplesPerMPEGFrame = 0;
int id3_length = 0; int id3_length = 0;
mad_stream_init(&stream); mad_stream_init(stream);
mad_frame_init(&frame); mad_frame_init(frame);
[_source seek:0 whence:SEEK_END]; [_source seek:0 whence:SEEK_END];
_fileSize = [_source tell]; _fileSize = [_source tell];
[_source seek:0 whence:SEEK_SET]; [_source seek:0 whence:SEEK_SET];
for(;;) { for(;;) {
[self bufferRefill:&stream]; [self bufferRefill:stream];
if(mad_frame_decode(&frame, &stream) == -1) { if(mad_frame_decode(frame, stream) == -1) {
if(MAD_RECOVERABLE(stream.error)) { if(MAD_RECOVERABLE(stream->error)) {
// Prevent ID3 tags from reporting recoverable frame errors // Prevent ID3 tags from reporting recoverable frame errors
const uint8_t *buffer = stream.this_frame; const uint8_t *buffer = stream->this_frame;
unsigned long buflen = stream.bufend - stream.this_frame; unsigned long buflen = stream->bufend - stream->this_frame;
if(10 <= buflen && 0x49 == buffer[0] && 0x44 == buffer[1] && 0x33 == buffer[2]) { if(10 <= buflen && 0x49 == buffer[0] && 0x44 == buffer[1] && 0x33 == buffer[2]) {
id3_length = (((buffer[6] & 0x7F) << (3 * 7)) | ((buffer[7] & 0x7F) << (2 * 7)) | id3_length = (((buffer[6] & 0x7F) << (3 * 7)) | ((buffer[7] & 0x7F) << (2 * 7)) |
@ -108,7 +115,7 @@
id3_length += 10; id3_length += 10;
void *tagBuffer = malloc(id3_length); void *tagBuffer = malloc(id3_length);
if(!tagBuffer) return NO; if(!tagBuffer) goto error;
memcpy(tagBuffer, &buffer[0], MIN(buflen, id3_length)); memcpy(tagBuffer, &buffer[0], MIN(buflen, id3_length));
@ -116,18 +123,18 @@
long tagRead = MIN(buflen, id3_length); long tagRead = MIN(buflen, id3_length);
while(bufleft > 0) { while(bufleft > 0) {
stream.error = MAD_ERROR_BUFLEN; stream->error = MAD_ERROR_BUFLEN;
stream.next_frame = NULL; stream->next_frame = NULL;
[self bufferRefill:&stream]; [self bufferRefill:stream];
buffer = stream.this_frame; buffer = stream->this_frame;
buflen = stream.bufend - stream.this_frame; buflen = stream->bufend - stream->this_frame;
memcpy(tagBuffer + tagRead, buffer, MIN(buflen, bufleft)); memcpy(tagBuffer + tagRead, buffer, MIN(buflen, bufleft));
tagRead += MIN(buflen, bufleft); tagRead += MIN(buflen, bufleft);
bufleft -= buflen; bufleft -= buflen;
} }
if(bufleft < 0) { 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); struct id3_tag *tag = id3_tag_parse(tagBuffer, id3_length);
@ -180,14 +187,14 @@
} }
free(tagBuffer); free(tagBuffer);
} else if(stream.error == MAD_ERROR_BADDATAPTR) { } else if(stream->error == MAD_ERROR_BADDATAPTR) {
goto framedecoded; goto framedecoded;
} }
continue; continue;
} else if(stream.error == MAD_ERROR_BUFLEN && inputEOF) { } else if(stream->error == MAD_ERROR_BUFLEN && inputEOF) {
break; break;
} else if(stream.error == MAD_ERROR_BUFLEN) { } else if(stream->error == MAD_ERROR_BUFLEN) {
continue; continue;
} else { } else {
// DLog(@"Unrecoverable error: %s", mad_stream_errorstr(&stream)); // DLog(@"Unrecoverable error: %s", mad_stream_errorstr(&stream));
@ -198,11 +205,11 @@
framesDecoded++; framesDecoded++;
if(framesDecoded == 1) { if(framesDecoded == 1) {
sampleRate = frame.header.samplerate; sampleRate = frame->header.samplerate;
channels = MAD_NCHANNELS(&frame.header); channels = MAD_NCHANNELS(&frame->header);
if(MAD_FLAG_LSF_EXT & frame.header.flags || MAD_FLAG_MPEG_2_5_EXT & frame.header.flags) { if(MAD_FLAG_LSF_EXT & frame->header.flags || MAD_FLAG_MPEG_2_5_EXT & frame->header.flags) {
switch(frame.header.layer) { switch(frame->header.layer) {
case MAD_LAYER_I: case MAD_LAYER_I:
samplesPerMPEGFrame = 384; samplesPerMPEGFrame = 384;
layer = 1; layer = 1;
@ -217,7 +224,7 @@
break; break;
} }
} else { } else {
switch(frame.header.layer) { switch(frame->header.layer) {
case MAD_LAYER_I: case MAD_LAYER_I:
samplesPerMPEGFrame = 384; samplesPerMPEGFrame = 384;
layer = 1; layer = 1;
@ -235,16 +242,16 @@
if(layer != 3) continue; 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}}; 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; size_t ancBitsRemainingXing = ancillaryBitsRemaining - xing_offset * 8;
if(ancBitsRemainingXing >= 32) { 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; struct mad_bitptr bitptr;
mad_bit_init(&bitptr, ptr); mad_bit_init(&bitptr, ptr);
@ -374,7 +381,7 @@
size_t ancBitsRemainingVBRI = ancillaryBitsRemaining - vbri_offset * 8; size_t ancBitsRemainingVBRI = ancillaryBitsRemaining - vbri_offset * 8;
if(ancBitsRemainingVBRI >= 32) { 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; struct mad_bitptr bitptr;
mad_bit_init(&bitptr, ptr); mad_bit_init(&bitptr, ptr);
@ -407,22 +414,25 @@
} }
// Don't commit division by zero on bad files // Don't commit division by zero on bad files
if(stream.next_frame == stream.this_frame) { if(stream->next_frame == stream->this_frame) {
return NO; goto error;
} }
if(!_foundiTunSMPB && !_foundXingHeader && !_foundVBRIHeader) { if(!_foundiTunSMPB && !_foundXingHeader && !_foundVBRIHeader) {
// Now do CBR estimation instead of full file scanning // Now do CBR estimation instead of full file scanning
size_t frameCount = (_fileSize - id3_length) / (stream.next_frame - stream.this_frame); size_t frameCount = (_fileSize - id3_length) / (stream->next_frame - stream->this_frame);
mad_timer_t duration = frame.header.duration; mad_timer_t duration = frame->header.duration;
mad_timer_multiply(&duration, frameCount); mad_timer_multiply(&duration, frameCount);
totalFrames = mad_timer_count(duration, sampleRate); totalFrames = mad_timer_count(duration, sampleRate);
} }
bitrate = ((double)((_fileSize - id3_length) * 8) / 1000.0) * (sampleRate / (double)totalFrames); bitrate = ((double)((_fileSize - id3_length) * 8) / 1000.0) * (sampleRate / (double)totalFrames);
mad_frame_finish(&frame); mad_frame_finish(frame);
mad_stream_finish(&stream); mad_stream_finish(stream);
free(frame);
free(stream);
[_source seek:0 whence:SEEK_SET]; [_source seek:0 whence:SEEK_SET];
inputEOF = NO; inputEOF = NO;
@ -430,6 +440,17 @@
DLog(@"Mad properties: %@", [self properties]); DLog(@"Mad properties: %@", [self properties]);
return YES; return YES;
error:
if(frame) {
mad_frame_finish(frame);
free(frame);
}
if(stream) {
mad_stream_finish(stream);
free(stream);
}
return NO;
} }
- (BOOL)open:(id<CogSource>)source { - (BOOL)open:(id<CogSource>)source {

View File

@ -20,6 +20,9 @@
char buffer[MPC_FRAME_LENGTH * 4]; char buffer[MPC_FRAME_LENGTH * 4];
int bufferFrames; int bufferFrames;
MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH];
float floatBuffer[1024 * 2];
int bitrate; int bitrate;
float frequency; float frequency;

View File

@ -110,11 +110,8 @@ mpc_bool_t CanSeekProc(mpc_reader *p_reader) {
} }
- (AudioChunk *)readAudio { - (AudioChunk *)readAudio {
MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH];
int frames = 1024; int frames = 1024;
float buffer[frames * 2]; void *buf = (void *)floatBuffer;
void *buf = (void *)buffer;
int framesRead = 0; int framesRead = 0;
int bytesPerFrame = sizeof(float) * 2; // bitsPerSample == 32, channels == 2 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"); id audioChunkClass = NSClassFromString(@"AudioChunk");
AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]];
[chunk assignSamples:buffer frameCount:framesRead]; [chunk assignSamples:floatBuffer frameCount:framesRead];
return chunk; return chunk;
} }

View File

@ -15,6 +15,8 @@
long length; long length;
long remain; long remain;
float *buffer;
} }
- (void)setSource:(id<CogSource>)s; - (void)setSource:(id<CogSource>)s;

View File

@ -27,6 +27,12 @@ enum { channels = 2 };
length = seconds * sample_rate; length = seconds * sample_rate;
remain = length; remain = length;
buffer = (float *) calloc(sizeof(float), 1024 * channels);
if(!buffer) {
ALog(@"Out of memory!");
return NO;
}
[self willChangeValueForKey:@"properties"]; [self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"];
@ -52,23 +58,17 @@ enum { channels = 2 };
- (AudioChunk *)readAudio { - (AudioChunk *)readAudio {
int frames = 1024; int frames = 1024;
float buffer[frames * channels];
void *buf = (void *)buffer;
int total = frames;
if(!IsRepeatOneSet()) { if(!IsRepeatOneSet()) {
if(total > remain) if(frames > remain)
total = (int)remain; frames = (int)remain;
remain -= total; remain -= frames;
} }
memset(buf, 0, sizeof(float) * total * channels);
id audioChunkClass = NSClassFromString(@"AudioChunk"); id audioChunkClass = NSClassFromString(@"AudioChunk");
AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]]; AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]];
[chunk assignSamples:buffer frameCount:total]; [chunk assignSamples:buffer frameCount:frames];
return chunk; return chunk;
} }

View File

@ -39,6 +39,8 @@ extern NSString *CogPlaybackDidStopNotficiation;
NSColor *borderColor; NSColor *borderColor;
ddb_analyzer_t _analyzer; ddb_analyzer_t _analyzer;
ddb_analyzer_draw_data_t _draw_data; ddb_analyzer_draw_data_t _draw_data;
float visAudio[4096], visFFT[2048];
} }
@end @end
@ -368,8 +370,6 @@ extern NSString *CogPlaybackDidStopNotficiation;
_analyzer.view_width = self.bounds.size.width; _analyzer.view_width = self.bounds.size.width;
} }
float visAudio[4096], visFFT[2048];
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0]; [self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0];
ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048); ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048);

View File

@ -42,6 +42,8 @@ extern NSString *CogPlaybackDidStopNotficiation;
SCNVector3 cameraEulerAngles2d; SCNVector3 cameraEulerAngles2d;
SCNVector3 cameraPosition3d; SCNVector3 cameraPosition3d;
SCNVector3 cameraEulerAngles3d; SCNVector3 cameraEulerAngles3d;
float visAudio[4096], visFFT[2048];
} }
@end @end
@ -274,8 +276,6 @@ extern NSString *CogPlaybackDidStopNotficiation;
return; return;
} }
float visAudio[4096], visFFT[2048];
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0]; [self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0];
ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048); ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048);