From 039087a2dde402039312092f7e498f9997aadcd5 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Wed, 17 Mar 2021 23:56:50 +0300
Subject: [PATCH] timidity: handle malloc() failures. revise library init.
---
src/codecs/timidity/common.c | 10 ++-
src/codecs/timidity/common.h | 2 +-
src/codecs/timidity/instrum.c | 92 ++++++++++++++-----------
src/codecs/timidity/readmidi.c | 16 +++++
src/codecs/timidity/resample.c | 4 +-
src/codecs/timidity/timidity.c | 121 +++++++++++++++++++++++++--------
src/codecs/timidity/timidity.h | 1 +
7 files changed, 169 insertions(+), 77 deletions(-)
diff --git a/src/codecs/timidity/common.c b/src/codecs/timidity/common.c
index 527787f..2798284 100644
--- a/src/codecs/timidity/common.c
+++ b/src/codecs/timidity/common.c
@@ -81,22 +81,20 @@ SDL_RWops *open_file(const char *name)
}
/* This adds a directory to the path list */
-void add_to_pathlist(const char *s, size_t l)
+int add_to_pathlist(const char *s, size_t l)
{
PathList *plp = SDL_malloc(sizeof(PathList));
-
- if (plp == NULL)
- return;
-
+ if (plp == NULL) return -2;
plp->path = SDL_malloc(l + 1);
if (plp->path == NULL) {
SDL_free (plp);
- return;
+ return -2;
}
SDL_memcpy(plp->path, s, l);
plp->path[l] = 0;
plp->next = pathlist;
pathlist = plp;
+ return 0;
}
void free_pathlist(void)
diff --git a/src/codecs/timidity/common.h b/src/codecs/timidity/common.h
index f6faa9f..46e68db 100644
--- a/src/codecs/timidity/common.h
+++ b/src/codecs/timidity/common.h
@@ -9,5 +9,5 @@
*/
extern SDL_RWops *open_file(const char *name);
-extern void add_to_pathlist(const char *s, size_t len);
+extern int add_to_pathlist(const char *s, size_t len);
extern void free_pathlist(void);
diff --git a/src/codecs/timidity/instrum.c b/src/codecs/timidity/instrum.c
index 36da50a..0400199 100644
--- a/src/codecs/timidity/instrum.c
+++ b/src/codecs/timidity/instrum.c
@@ -26,12 +26,13 @@ static void free_instrument(Instrument *ip)
Sample *sp;
int i;
if (!ip) return;
- for (i=0; i<ip->samples; i++)
- {
+ if (ip->sample) {
+ for (i=0; i<ip->samples; i++) {
sp=&(ip->sample[i]);
SDL_free(sp->data);
}
- SDL_free(ip->sample);
+ SDL_free(ip->sample);
+ }
SDL_free(ip);
}
@@ -42,7 +43,6 @@ static void free_bank(MidiSong *song, int dr, int b)
for (i=0; i<MAXBANK; i++)
if (bank->instrument[i])
{
- /* Not that this could ever happen, of course */
if (bank->instrument[i] != MAGIC_LOAD_INSTRUMENT)
free_instrument(bank->instrument[i]);
bank->instrument[i]=0;
@@ -141,7 +141,8 @@ static void reverse_data(Sint16 *sp, Sint32 ls, Sint32 le)
undefined.
TODO: do reverse loops right */
-static Instrument *load_instrument(MidiSong *song, const char *name,
+static void load_instrument(MidiSong *song, const char *name,
+ Instrument **out,
int percussion, int panning,
int amp, int note_to_use,
int strip_loop, int strip_envelope,
@@ -155,7 +156,8 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
static char *patch_ext[] = PATCH_EXT_LIST;
(void)percussion; /* unused */
- if (!name) return 0;
+ *out = NULL;
+ if (!name) return;
/* Open patch file */
if ((rw=open_file(name)) == NULL)
@@ -172,7 +174,7 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
if (rw == NULL)
{
SNDDBG(("Instrument `%s' can't be found.\n", name));
- return 0;
+ return;
}
SNDDBG(("Loading instrument %s\n", tmp));
@@ -186,28 +188,30 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
differences are */
{
SNDDBG(("%s: not an instrument\n", name));
- SDL_RWclose(rw);
- return 0;
+ goto badpat;
}
if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers,
0 means 1 */
{
SNDDBG(("Can't handle patches with %d instruments\n", tmp[82]));
- SDL_RWclose(rw);
- return 0;
+ goto badpat;
}
if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
{
SNDDBG(("Can't handle instruments with %d layers\n", tmp[151]));
- SDL_RWclose(rw);
- return 0;
+ goto badpat;
}
- ip=SDL_malloc(sizeof(Instrument));
+ *out=SDL_malloc(sizeof(Instrument));
+ ip = *out;
+ if (!ip) goto nomem;
+
ip->samples = tmp[198];
ip->sample = SDL_malloc(sizeof(Sample) * ip->samples);
+ if (!ip->sample) goto nomem;
+
for (i=0; i<ip->samples; i++)
{
Uint8 fractions;
@@ -216,28 +220,19 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
Uint8 tmpchar;
#define READ_CHAR(thing) \
- if (1 != SDL_RWread(rw, &tmpchar, 1, 1)) goto fail; \
+ if (1 != SDL_RWread(rw, &tmpchar, 1, 1)) goto badread; \
thing = tmpchar;
#define READ_SHORT(thing) \
- if (1 != SDL_RWread(rw, &tmpshort, 2, 1)) goto fail; \
+ if (1 != SDL_RWread(rw, &tmpshort, 2, 1)) goto badread; \
thing = SDL_SwapLE16(tmpshort);
#define READ_LONG(thing) \
- if (1 != SDL_RWread(rw, &tmplong, 4, 1)) g oto fail; \
+ if (1 != SDL_RWread(rw, &tmplong, 4, 1)) goto badread; \
thing = (Sint32)SDL_SwapLE32((Uint32)tmplong);
SDL_RWseek(rw, 7, RW_SEEK_CUR); /* Skip the wave name */
if (1 != SDL_RWread(rw, &fractions, 1, 1))
- {
- fail:
- SNDDBG(("Error reading sample %d\n", i));
- for (j=0; j<i; j++)
- SDL_free(ip->sample[j].data);
- SDL_free(ip->sample);
- SDL_free(ip);
- SDL_RWclose(rw);
- return 0;
- }
+ goto badread;
sp=&(ip->sample[i]);
@@ -259,7 +254,8 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
sp->panning=(Uint8)(panning & 0x7F);
/* envelope, tremolo, and vibrato */
- if (18 != SDL_RWread(rw, tmp, 1, 18)) goto fail;
+ if (18 != SDL_RWread(rw, tmp, 1, 18))
+ goto badread;
if (!tmp[13] || !tmp[14])
{
@@ -369,8 +365,10 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
/* Then read the sample data */
sp->data = (sample_t *) SDL_malloc(sp->data_length+4);
+ if (!sp->data) goto nomem;
+
if (1 != SDL_RWread(rw, sp->data, sp->data_length, 1))
- goto fail;
+ goto badread;
if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */
{
@@ -381,6 +379,7 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
sp->loop_start *= 2;
sp->loop_end *= 2;
tmp16 = new16 = (Uint16 *) SDL_malloc(sp->data_length+4);
+ if (!new16) goto nomem;
while (k--)
*tmp16++ = (Uint16)(*cp++) << 8;
SDL_free(sp->data);
@@ -476,8 +475,10 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
/* If this instrument will always be played on the same note,
and it's not looped, we can resample it now. */
- if (sp->note_to_use && !(sp->modes & MODES_LOOPING))
+ if (sp->note_to_use && !(sp->modes & MODES_LOOPING)) {
pre_resample(song, sp);
+ if (song->oom) goto fail;
+ }
if (strip_tail==1)
{
@@ -488,7 +489,18 @@ static Instrument *load_instrument(MidiSong *song, const char *name,
}
SDL_RWclose(rw);
- return ip;
+ return;
+
+nomem:
+ song->oom=1;
+ goto fail;
+badread:
+ SNDDBG(("Error reading sample %d\n", i));
+fail:
+ free_instrument (ip);
+badpat:
+ SDL_RWclose(rw);
+ *out = NULL;
}
static int fill_bank(MidiSong *song, int dr, int b)
@@ -530,9 +542,11 @@ static int fill_bank(MidiSong *song, int dr, int b)
bank->instrument[i] = 0;
errors++;
}
- else if (!(bank->instrument[i] =
- load_instrument(song,
+ else
+ {
+ load_instrument(song,
bank->tone[i].name,
+ &bank->instrument[i],
(dr) ? 1 : 0,
bank->tone[i].pan,
bank->tone[i].amp,
@@ -545,13 +559,14 @@ static int fill_bank(MidiSong *song, int dr, int b)
(bank->tone[i].strip_envelope != -1) ?
bank->tone[i].strip_envelope :
((dr) ? 1 : -1),
- bank->tone[i].strip_tail )))
- {
- SNDDBG(("Couldn't load instrument %s (%s %d, program %d)\n",
+ bank->tone[i].strip_tail);
+ if (!bank->instrument[i]) {
+ SNDDBG(("Couldn't load instrument %s (%s %d, program %d)\n",
bank->tone[i].name,
(dr)? "drum set" : "tone bank", b, i));
errors++;
}
+ }
}
}
return errors;
@@ -584,10 +599,9 @@ void free_instruments(MidiSong *song)
int set_default_instrument(MidiSong *song, const char *name)
{
- Instrument *ip;
- if (!(ip=load_instrument(song, name, 0, -1, -1, -1, 0, 0, 0)))
+ load_instrument(song, name, &song->default_instrument, 0, -1, -1, -1, 0, 0, 0);
+ if (!song->default_instrument)
return -1;
- song->default_instrument = ip;
song->default_program = SPECIAL_PROGRAM;
return 0;
}
diff --git a/src/codecs/timidity/readmidi.c b/src/codecs/timidity/readmidi.c
index 237e60b..03d6e12 100644
--- a/src/codecs/timidity/readmidi.c
+++ b/src/codecs/timidity/readmidi.c
@@ -53,11 +53,17 @@ static int dumpstring(SDL_RWops *rw, Sint32 len, Uint8 type)
"Text event: ", "Text: ", "Copyright: ", "Track name: ",
"Instrument: ", "Lyric: ", "Marker: ", "Cue point: " };
signed char *s = SDL_malloc(len+1);
+ if (!s)
+ {
+ SDL_RWseek(song->rw, len, RW_SEEK_CUR);/* should I ? */
+ return -1;
+ }
if (len != (Sint32) SDL_RWread(rw, s, 1, len))
{
SDL_free(s);
return -1;
}
+
s[len]='\0';
while (len--)
{
@@ -72,6 +78,7 @@ static int dumpstring(SDL_RWops *rw, Sint32 len, Uint8 type)
#define MIDIEVENT(at,t,ch,pa,pb) \
newlist = (MidiEventList *) SDL_malloc(sizeof(MidiEventList));\
+ if (!newlist) {song->oom = 1; return NULL;} \
newlist->event.time = at; \
newlist->event.type = t; \
newlist->event.channel = ch; \
@@ -364,6 +371,11 @@ static MidiEvent *groom_list(MidiSong *song, Sint32 divisions,Sint32 *eventsp,
/* This may allocate a bit more than we need */
groomed_list=lp=SDL_malloc(sizeof(MidiEvent) * (song->event_count+1));
+ if (!groomed_list) {
+ song->oom=1;
+ free_midi_list(song);
+ return NULL;
+ }
meep=song->evlist;
our_event_count=0;
@@ -579,6 +591,10 @@ MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp)
/* Put a do-nothing event first in the list for easier processing */
song->evlist=SDL_calloc(1, sizeof(MidiEventList));
+ if (!song->evlist) {
+ song->oom=1;
+ return NULL;
+ }
song->event_count++;
switch(format)
diff --git a/src/codecs/timidity/resample.c b/src/codecs/timidity/resample.c
index 7fd9ac3..4372ca6 100644
--- a/src/codecs/timidity/resample.c
+++ b/src/codecs/timidity/resample.c
@@ -552,8 +552,10 @@ void pre_resample(MidiSong *song, Sample *sp)
}
dest = newdata = (Sint16 *) SDL_malloc((newlen >> (FRACTION_BITS - 1)) + 2);
- if (!dest)
+ if (!dest) {
+ song->oom = 1;
return;
+ }
if (--count)
*dest++ = src[0];
diff --git a/src/codecs/timidity/timidity.c b/src/codecs/timidity/timidity.c
index cddeabc..fe16e9c 100644
--- a/src/codecs/timidity/timidity.c
+++ b/src/codecs/timidity/timidity.c
@@ -189,7 +189,8 @@ static int read_config_file(const char *name, int rcf_count)
goto fail;
}
for (i=1; i<words; i++) {
- add_to_pathlist(w[i], SDL_strlen(w[i]));
+ if (add_to_pathlist(w[i], SDL_strlen(w[i])) < 0)
+ goto fail;
}
}
else if (!SDL_strcmp(w[0], "source"))
@@ -234,7 +235,9 @@ static int read_config_file(const char *name, int rcf_count)
if (!master_drumset[i])
{
master_drumset[i] = SDL_calloc(1, sizeof(ToneBank));
+ if (!master_drumset[i]) goto fail;
master_drumset[i]->tone = SDL_calloc(128, sizeof(ToneBankElement));
+ if (!master_drumset[i]->tone) goto fail;
}
bank=master_drumset[i];
}
@@ -255,7 +258,9 @@ static int read_config_file(const char *name, int rcf_count)
if (!master_tonebank[i])
{
master_tonebank[i] = SDL_calloc(1, sizeof(ToneBank));
+ if (!master_tonebank[i]) goto fail;
master_tonebank[i]->tone = SDL_calloc(128, sizeof(ToneBankElement));
+ if (!master_tonebank[i]->tone) goto fail;
}
bank=master_tonebank[i];
}
@@ -283,6 +288,7 @@ static int read_config_file(const char *name, int rcf_count)
SDL_free(bank->tone[i].name);
sz = SDL_strlen(w[1])+1;
bank->tone[i].name = SDL_malloc(sz);
+ if (!bank->tone[i].name) goto fail;
SDL_memcpy(bank->tone[i].name,w[1],sz);
bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
@@ -378,62 +384,106 @@ static int read_config_file(const char *name, int rcf_count)
return r;
}
-int Timidity_Init_NoConfig(void)
+#if defined(_WIN32)||defined(__CYGWIN__)||defined(__OS2__)
+/* FIXME: What about C:FOO ? */
+static SDL_INLINE char *get_last_dirsep (const char *p) {
+ char *p1 = SDL_strrchr(p, '/');
+ char *p2 = SDL_strrchr(p, '\\');
+ if (!p1) return p2;
+ if (!p2) return p1;
+ return (p1 > p2)? p1 : p2;
+}
+#else /* assumed UNIX-ish : */
+static SDL_INLINE char *get_last_dirsep (const char *p) {
+ return SDL_strrchr(p, '/');
+}
+#endif
+
+static int init_alloc_banks(void)
{
/* Allocate memory for the standard tonebank and drumset */
master_tonebank[0] = SDL_calloc(1, sizeof(ToneBank));
+ if (!master_tonebank[0]) goto _nomem;
master_tonebank[0]->tone = SDL_calloc(128, sizeof(ToneBankElement));
+ if (!master_tonebank[0]->tone) goto _nomem;
master_drumset[0] = SDL_calloc(1, sizeof(ToneBank));
+ if (!master_drumset[0]) goto _nomem;
master_drumset[0]->tone = SDL_calloc(128, sizeof(ToneBankElement));
+ if (!master_drumset[0]->tone) goto _nomem;
return 0;
+_nomem:
+ SNDDBG(("Out of memory\n"));
+ Timidity_Exit ();
+ return -2;
}
-int Timidity_Init(const char *config_file)
+static int init_begin_config(const char *cf)
{
- const char *p;
-
- Timidity_Init_NoConfig();
+ const char *p = get_last_dirsep(cf);
+ if (p != NULL)
+ return add_to_pathlist(cf, p - cf + 1); /* including DIRSEP */
+ return 0;
+}
- if (config_file == NULL || *config_file == '\0')
- config_file = TIMIDITY_CFG;
+static int init_with_config(const char *cf)
+{
+ int rc = init_begin_config(cf);
+ if (rc != 0) {
+ Timidity_Exit ();
+ return rc;
+ }
+ rc = read_config_file(cf, 0);
+ if (rc != 0) {
+ Timidity_Exit ();
+ }
+ return rc;
+}
- p = SDL_strrchr(config_file, '/');
-#if defined(__WIN32__)||defined(__OS2__)
- if (!p) p = SDL_strrchr(config_file, '\\');
-#endif
- if (p != NULL)
- add_to_pathlist(config_file, p - config_file + 1);
+int Timidity_Init_NoConfig(void)
+{
+ master_tonebank[0] = NULL;
+ master_drumset[0] = NULL;
+ return init_alloc_banks();
+}
- if (read_config_file(config_file, 0) < 0) {
- Timidity_Exit();
- return -1;
+int Timidity_Init(const char *config_file)
+{
+ int rc = Timidity_Init_NoConfig();
+ if (rc != 0) {
+ return rc;
}
- return 0;
+ if (config_file == NULL || *config_file == '\0') {
+ return init_with_config(TIMIDITY_CFG);
+ }
+ return init_with_config(config_file);
}
-MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
+static void do_song_load(SDL_RWops *rw, SDL_AudioSpec *audio, MidiSong **out)
{
MidiSong *song;
int i;
+ *out = NULL;
if (rw == NULL)
- return NULL;
+ return;
/* Allocate memory for the song */
song = (MidiSong *)SDL_calloc(1, sizeof(*song));
if (song == NULL)
- return NULL;
+ return;
for (i = 0; i < MAXBANK; i++)
{
if (master_tonebank[i]) {
song->tonebank[i] = SDL_calloc(1, sizeof(ToneBank));
+ if (!song->tonebank[i]) goto fail;
song->tonebank[i]->tone = master_tonebank[i]->tone;
}
if (master_drumset[i]) {
song->drumset[i] = SDL_calloc(1, sizeof(ToneBank));
+ if (!song->drumset[i]) goto fail;
song->drumset[i]->tone = master_drumset[i]->tone;
}
}
@@ -456,8 +506,7 @@ MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
song->encoding |= PE_MONO;
else if (audio->channels > 2) {
SDL_SetError("Surround sound not supported");
- SDL_free(song);
- return NULL;
+ goto fail;
}
switch (audio->format) {
case AUDIO_S8:
@@ -489,13 +538,14 @@ MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
break;
default:
SDL_SetError("Unsupported audio format");
- SDL_free(song);
- return NULL;
+ goto fail;
}
song->buffer_size = audio->samples;
song->resample_buffer = SDL_malloc(audio->samples * sizeof(sample_t));
+ if (!song->resample_buffer) goto fail;
song->common_buffer = SDL_malloc(audio->samples * 2 * sizeof(Sint32));
+ if (!song->common_buffer) goto fail;
song->control_ratio = audio->freq / CONTROLS_PER_SECOND;
if (song->control_ratio < 1)
@@ -510,10 +560,8 @@ MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
&song->samples);
/* Make sure everything is okay */
- if (!song->events) {
- SDL_free(song);
- return(NULL);
- }
+ if (!song->events)
+ goto fail;
song->default_instrument = NULL;
song->default_program = DEFAULT_PROGRAM;
@@ -523,13 +571,26 @@ MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
load_missing_instruments(song);
- return(song);
+ if (! song->oom)
+ *out = song;
+ else {
+fail: Timidity_FreeSong(song);
+ }
+}
+
+MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
+{
+ MidiSong *song;
+ do_song_load(rw, audio, &song);
+ return song;
}
void Timidity_FreeSong(MidiSong *song)
{
int i;
+ if (!song) return;
+
free_instruments(song);
for (i = 0; i < 128; i++) {
diff --git a/src/codecs/timidity/timidity.h b/src/codecs/timidity/timidity.h
index 9fb0f20..a3d94c9 100644
--- a/src/codecs/timidity/timidity.h
+++ b/src/codecs/timidity/timidity.h
@@ -106,6 +106,7 @@ typedef struct _MidiEventList {
} MidiEventList;
typedef struct {
+ int oom; /* malloc() failed */
int playing;
SDL_RWops *rw;
Sint32 rate;