[Speex-dev] Possible fixed point overflow/div 0 preprocess.c

Jean-Marc Valin jean-marc.valin at usherbrooke.ca
Mon Sep 17 21:45:57 PDT 2007


Hi Peter,

Thanks a lot for posting this bug report. There's indeed a problem with 
the fixed-point code, though not in the floating point (it turns out 
that "floating-point exception" is very misleading as it only occurs on 
*integer* divisions, not float). Anyway, so the fix should be fairly 
simple. I'll fix that in the next few days -- flame me if I forget.

Cheers,

	Jean-Marc

Peter Rowling wrote:
> Hi,
> 
> I'll try to keep this as brief, yet descriptive enough to save everyone
> some time. 
> If I'm off with this one please forgive me, but it has fixed my issues.
> I am not
> sure whether it is just my compiler (gcc 3.3.5) doing the wrong thing
> with the cast.
> 
> File: preprocess.c
> Arch affected: x86, (others?)
> svn revision: 12778
> 
> Description:
> 
> The SpeexPreprocessState_ member 'nb_adapt' is a signed integer.
> nb_adapt is only
> modified during 'speex_preprocess_run' when an unbounded increment is
> performed. When
> calculating 'beta' within 'speex_preprocess_run', I received a floating
> point exception
> even when compiled with -DFIXED_POINT.  The reason is as follows:
> 
> <original beta calculation within speex_preprocess_run>
> ...
>    st->nb_adapt++;
>    st->min_count++;
>    
>    beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt));
>    beta_1 = Q15_ONE-beta;
> ...
> </>
> 
> On my architecture(x86) at least the DIV32_16 is defined as follows.
> 
> typedef short spx_int16_t;
> typedef spx_int16_t spx_word16_t;
> #define DIV32_16(a,b)
> ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b))))
> 
> The nb_adapt overflow occurred when its value reached 0x00010000 when
> the cast is
> performed to a short the value 0x0000 is given and hence the divide by
> zero exception.
> 
> Proposed resolution:
> 
> The SpeexPreprocessState_ member 'nb_adapt' is only checked in a couple
> of places and
> mostly for initial conditions such as within update_noise_prob below:
> 
> <preprocess.c update_noise_prob>
> ...
>    if (st->nb_adapt==1)
>    {
>       for (i=0;i<N;i++)
>          st->Smin[i] = st->Stmp[i] = 0;
>    }
> 
>    if (st->nb_adapt < 100)
>       min_range = 15;
>    else if (st->nb_adapt < 1000)
>       min_range = 50;
>    else if (st->nb_adapt < 10000)
>       min_range = 150;
>    else
>       min_range = 300;
> ...
> </>
> 
> Maybe something like this is required within speex_preprocess_run to
> prevent the observed overflow.
> 
> <preprocess.c speex_preprocess_run>
> ...
>    if ( st->nb_adapt < 0x7FFF /* or 32767 as elsewhere in the code */ )
>        st->nb_adapt++;
> ...
> </>
> 
> Thanks.
> 
> Peter Rowling
> 
> _______________________________________________
> Speex-dev mailing list
> Speex-dev at xiph.org
> http://lists.xiph.org/mailman/listinfo/speex-dev
> 


More information about the Speex-dev mailing list