Subject: pkg/5446: xmame sound code doesn't protect critical sections
To: None <gnats-bugs@gnats.netbsd.org>
From: None <dave@dtsp.co.nz>
List: netbsd-bugs
Date: 05/12/1998 13:32:27
>Number:         5446
>Category:       pkg
>Synopsis:       xmame sound code doesn't protect critical sections
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue May 12 06:35:00 1998
>Last-Modified:
>Originator:     Dave Sainty
>Organization:
DTSP Ltd.
>Release:        12/5/98
>Environment:
System: NetBSD tequila.dave.dtsp.co.nz 1.3E NetBSD 1.3E (TEQUILA) #2: Tue May 12 16:39:18 NZST 1998 dave@tequila.dave.dtsp.co.nz:/vol/tequila/userC/NetBSD-current/src/sys/arch/i386/compile/TEQUILA i386


>Description:
	xmame sound code doesn't protect critical sections.  The NetBSD sound
	support currently outputs sound on SIGALRM, and eventually the signal
	will occur within a critical section.  It takes on average a few
	minutes on my machine.

>How-To-Repeat:
	Level your sights on an alien, say "I'm taking you doooown!", and get
	annoyed when the application spontaneously exits.

>Fix:
Add this patch to the package.  This stops the immediate problem, but there is
still a free() within the signal handler that definitely shouldn't be there:

--- sound.c.orig	Wed May 13 00:13:36 1998
+++ sound.c	Wed May 13 00:30:11 1998
@@ -12,6 +12,9 @@
 #include <sys/time.h>
 #include <signal.h>
 static int bytes_per_timer_alarm;
+
+/* Set of signals to block during critical sections */
+static sigset_t blockingset;
 #endif
 
 #include "xmame.h"
@@ -33,7 +36,7 @@
  * this is not applicable to data samples ( not fixed size ... )
  **************************************************************************/
  
-/* this should be enought ....*/
+/* this should be enough ....*/
 #define ALLOC_TABLE_SIZE 64
 
 static SAMPLE_T		SampleTTable[ALLOC_TABLE_SIZE];
@@ -64,7 +67,7 @@
 SAMPLE_T  *AllocSampleT(void) {
 #if 1
     SAMPLE_T *pt;
-    if (SampleTPointer<0) return (SAMPLE_T *) NULL; /* no items availables */
+    if (SampleTPointer<0) return (SAMPLE_T *) NULL; /* no items available */
     pt = &SampleTTable[SampleTIndex[SampleTPointer--]];
     return pt;
 #else
@@ -238,6 +241,10 @@
 	audio_timer_freq  = AUDIO_TIMER_FREQ;
 #ifdef USE_TIMER
 	bytes_per_timer_alarm=audio_sample_freq/audio_timer_freq;
+ 
+ 	/* Initialise the signal set to block during critical sections */
+ 	sigemptyset(&blockingset);
+ 	sigaddset(&blockingset, SIGALRM);
 #endif
 	InitSampleTTable();
         for (i = 0; i < AUDIO_NUM_VOICES; i++) {
@@ -250,6 +257,9 @@
 
 void osd_set_mastervolume(int volume)
 {
+#ifdef USE_TIMER
+	sigset_t oset;
+#endif
 	int channel;
 	float old_master_volume_divider;
 	
@@ -258,15 +268,29 @@
         old_master_volume_divider=master_volume_divider;
         master_volume_divider=(float)256 * 100 / volume;
         
+#ifdef USE_TIMER
+	sigprocmask(SIG_BLOCK, &blockingset, &oset);
+#endif
+
 	for (channel=0; channel < AUDIO_NUM_VOICES; channel++) {
 	   SAMPLE_T *pt=voices[channel].sample;
 	   for(;pt;pt=pt->next_sample) 
 	      pt->vol *= old_master_volume_divider/master_volume_divider;
 	}
+
+#ifdef USE_TIMER
+	if (!sigismember(&oset, SIGALRM))
+	  sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
 }
 
 void osd_play_sample(int channel,signed char *data,int len,int freq,int volume,int loop)
 {
+#ifdef USE_TIMER
+	sigset_t oset;
+#endif
+	SAMPLE_T *new_samp;
+	
         if ((play_sound == 0) || (channel >= AUDIO_NUM_VOICES)) return;
 	if ((freq<10) || (freq> 100000)) 
 	{ 
@@ -275,36 +299,60 @@
 #endif
 	   return;
 	}
-        sound_active=1;
+
+#ifdef USE_TIMER
+ 	sigprocmask(SIG_BLOCK, &blockingset, &oset);
+#endif
 
 	osd_stop_sample(channel);
-	if ( !(voices[channel].sample=AllocSampleT()) ) return;
-	if ( !(voices[channel].sample->data=(signed char *)malloc(len+1)) ) {
-		FreeSampleT(voices[channel].sample);
-		voices[channel].sample=(SAMPLE_T *)NULL;
+
+	if (!(new_samp = AllocSampleT()) ||
+	    !(new_samp->data = (signed char *)malloc(len+1))) {
+	  if (new_samp)
+	    FreeSampleT(new_samp);
+	  
+#ifdef USE_TIMER
+	  if (!sigismember(&oset, SIGALRM))
+	    sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
 		return;
 	}
+
+        sound_active=1;	
+
+	voices[channel].sample = new_samp;
+
 #ifdef FANCY_SOUND
         /* calculate one sample more as the actual length for interpolation */
-	if (loop) voices[channel].sample->data[len]=data[0];
-	 else voices[channel].sample->data[len]=0;
+ 	if (loop) new_samp->data[len]=data[0];
+	 else new_samp->data[len]=0;
 #endif	 
-	voices[channel].current_data_pt = voices[channel].sample->data;
-	voices[channel].sample->end_data_pt = voices[channel].sample->data + len - 1;
+	voices[channel].current_data_pt = new_samp->data;
+	new_samp->end_data_pt = new_samp->data + len - 1;
 	voices[channel].pos_frac = 0;
-	voices[channel].sample->next_sample = (SAMPLE_T *) NULL;
-	voices[channel].sample->loop_stream = loop;
- 	voices[channel].sample->vol = (float)volume / master_volume_divider;
-	voices[channel].sample->freq_fac = (float)freq / audio_sample_freq;
-        memcpy(voices[channel].sample->data,data,len);
+	new_samp->next_sample = (SAMPLE_T *) NULL;
+	new_samp->loop_stream = loop;
+ 	new_samp->vol = (float)volume / master_volume_divider;
+	new_samp->freq_fac = (float)freq / audio_sample_freq;
+        memcpy(new_samp->data,data,len);
 #ifdef SOUND_DEBUG
         fprintf(stderr,"play() chan:%d len:%d frec:%d vol:%d loop:%d\n",channel,len,freq,volume,loop); 
 #endif
+
+#ifdef USE_TIMER
+	if (!sigismember(&oset, SIGALRM))
+	  sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
+	
 	return;
 }
 
 void osd_play_streamed_sample(int channel,signed char *data,int len,int freq,int volume)
 {
+#ifdef USE_TIMER
+	sigset_t oset;
+#endif
+
 	SAMPLE_T *new_samp, *last_samp=NULL;
 
         if ((play_sound == 0) || (channel >= AUDIO_NUM_VOICES)) return;
@@ -315,25 +363,32 @@
 #endif
 	   return;
 	}
+
+#ifdef USE_TIMER
+	sigprocmask(SIG_BLOCK, &blockingset, &oset);
+#endif
+
+	if (!(new_samp = AllocSampleT()) ||
+	    !(new_samp->data = (signed char *)malloc(len+1))) {
+	  if (new_samp)
+	    FreeSampleT(new_samp);
+	  
+#ifdef USE_TIMER
+	  if (!sigismember(&oset, SIGALRM))
+	    sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
+	  
+	  return;
+	}
+	
         sound_active=1;
 
 	if(voices[channel].sample == NULL) {
-	    voices[channel].sample = AllocSampleT();
-	    new_samp= voices[channel].sample;
+	  voices[channel].sample = new_samp;
 	} else {
 	    last_samp = voices[channel].sample;
 	    while (last_samp->next_sample) last_samp=last_samp->next_sample;
-	    last_samp->next_sample = AllocSampleT();
-	    new_samp = last_samp->next_sample;
-	}
-	if (!new_samp) return; /* no resources availables */	
-	new_samp->data = (signed char *)malloc(len+1);
-	if (! new_samp->data) {
-	    if ( new_samp == voices[channel].sample ) 
-		 voices[channel].sample = NULL;
-	    else last_samp->next_sample = NULL;
-	    FreeSampleT(new_samp);
-	    return; /* cannot malloc data space: free sampleT and return */
+	  last_samp->next_sample = new_samp;
 	}
 #ifdef FANCY_SOUND
         /* calculate one sample more as the actual length for interpolation */
@@ -351,10 +406,19 @@
 	new_samp->vol = (float)volume / master_volume_divider;
 	new_samp->freq_fac = (float)freq / audio_sample_freq;
         memcpy(new_samp->data,data,len);
+	
+#ifdef USE_TIMER
+	if (!sigismember(&oset, SIGALRM))
+	  sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
 }
 
 void osd_adjust_sample(int channel,int freq,int volume)
 {
+#ifdef USE_TIMER
+	sigset_t oset;
+#endif
+
 	SAMPLE_T *next_samp;
         if (play_sound == 0 || channel >= AUDIO_NUM_VOICES) return;
 	if ((freq<10) || (freq> 100000)) 
@@ -364,6 +428,11 @@
 #endif
 	   return;
 	}
+
+#ifdef USE_TIMER
+	sigprocmask(SIG_BLOCK, &blockingset, &oset);
+#endif
+	
 	if(voices[channel].sample != NULL) {
 	    next_samp = voices[channel].sample;
 	    while(next_samp != NULL) {
@@ -372,14 +441,27 @@
 	    	next_samp = next_samp->next_sample;
 	    }
 	}
+
+#ifdef USE_TIMER
+	if (!sigismember(&oset, SIGALRM))
+	  sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
 }
 
 void osd_stop_sample(int channel)
 {
+#ifdef USE_TIMER
+	sigset_t oset;
+#endif
+  
 	SAMPLE_T *next_samp;
 	SAMPLE_T *curr_samp;
         if (play_sound == 0 || channel >= AUDIO_NUM_VOICES) return;
 
+#ifdef USE_TIMER
+	sigprocmask(SIG_BLOCK, &blockingset, &oset);
+#endif
+	
 	if(voices[channel].sample != NULL) {
 	    next_samp = voices[channel].sample;
 	    voices[channel].sample = NULL;
@@ -392,12 +474,31 @@
 	    	FreeSampleT(curr_samp);
 	    }
 	}
+  
+#ifdef USE_TIMER
+	if (!sigismember(&oset, SIGALRM))
+	  sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
 }
 
 void osd_restart_sample(int channel)
 {
+#ifdef USE_TIMER
+	sigset_t oset;
+#endif
+
 	if (play_sound == 0 || channel >= AUDIO_NUM_VOICES) return;
+
+#ifdef USE_TIMER
+	sigprocmask(SIG_BLOCK, &blockingset, &oset);
+#endif
+  
 	voices[channel].current_data_pt = voices[channel].sample->data;
+  
+#ifdef USE_TIMER
+	if (!sigismember(&oset, SIGALRM))
+	  sigprocmask(SIG_UNBLOCK, &blockingset, NULL);
+#endif
 }
 
 int osd_get_sample_status(int channel)

>Audit-Trail:
>Unformatted: