@@ -118,6 +118,27 @@ int lsx_effect_set_imin(sox_effect_t * effp, size_t imin)
118118 return SOX_SUCCESS ;
119119}
120120
121+ /* Convenience function to avoid having to explicitly free the effect object
122+ (which is not useable after adding it to an effects chain anyway).
123+ This exists because if libsox is dynamically linked on Windows, effects
124+ returned by sox_create_effect() cannot be freed using free() by the
125+ application since they were allocated in the libsox DLL. sox_delete_effect()
126+ cannot be used in the official libsox distribution because it will lead to a
127+ double free. While that is fixed in this fork, the calling code has no way
128+ of knowing that. This is the rationale for this function: the calling
129+ application can check if sox_add_and_delete_effect() exists and use it in
130+ that case, otherwise it can resort to not freeing the sox_effect_t object
131+ and just letting it leak.
132+ */
133+ int sox_add_and_delete_effect (sox_effects_chain_t * chain , sox_effect_t * effp , sox_signalinfo_t * in , sox_signalinfo_t const * out )
134+ {
135+ int result ;
136+ result = sox_add_effect (chain , effp , in , out );
137+ sox_delete_effect (effp );
138+ return result ;
139+ }
140+
141+
121142/* Effects table to be extended in steps of EFF_TABLE_STEP */
122143#define EFF_TABLE_STEP 8
123144
@@ -133,6 +154,8 @@ int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signali
133154 size_t f ;
134155 sox_effect_t eff0 ; /* Copy of effect for flow 0 before calling start */
135156
157+ assert (effp -> priv ); /* Effect instances cannot be reused */
158+
136159 effp -> global_info = & chain -> global_info ;
137160 effp -> in_signal = * in ;
138161 effp -> out_signal = * out ;
@@ -199,14 +222,16 @@ int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signali
199222 chain -> effects [chain -> length ][f ] = eff0 ;
200223 chain -> effects [chain -> length ][f ].flow = f ;
201224 chain -> effects [chain -> length ][f ].priv = lsx_memdup (eff0 .priv , eff0 .handler .priv_size );
202- if ( start ( & chain -> effects [ chain -> length ][ f ]) != SOX_SUCCESS ) {
225+ }
203226 free (eff0 .priv );
227+ effp -> priv = NULL ; /* At this point, effp->priv is "owned" by the chain */
228+
229+ for (f = 1 ; f < effp -> flows ; ++ f ) {
230+ if (start (& chain -> effects [chain -> length ][f ]) != SOX_SUCCESS )
204231 return SOX_EOF ;
205232 }
206- }
207233
208234 ++ chain -> length ;
209- free (eff0 .priv );
210235 return SOX_SUCCESS ;
211236}
212237
@@ -541,6 +566,13 @@ void sox_delete_effect(sox_effect_t *effp)
541566 uint64_t clips ;
542567 size_t f ;
543568
569+ /* If priv is NULL, it means that ownership has been transfered to
570+ the effect chain and we should only free the actual effect struct. */
571+ if (!effp -> priv ) {
572+ free (effp );
573+ return ;
574+ }
575+
544576 if ((clips = sox_stop_effect (effp )) != 0 )
545577 lsx_warn ("%s clipped %" PRIu64 " samples; decrease volume?" ,
546578 effp -> handler .name , clips );
@@ -550,7 +582,11 @@ void sox_delete_effect(sox_effect_t *effp)
550582 /* May or may not indicate a problem; it is normal if the user aborted
551583 processing, or if an effect like "trim" stopped early. */
552584 effp -> handler .kill (effp ); /* N.B. only one kill; not one per flow */
553- for (f = 0 ; f < effp -> flows ; ++ f )
585+
586+ /* There is always at least one element */
587+ free (effp -> priv );
588+ /* More may have been allocated by sox_add_effect */
589+ for (f = 1 ; f < effp -> flows ; ++ f )
554590 free (effp [f ].priv );
555591 free (effp -> obuf );
556592 free (effp );
0 commit comments