From a35ee9894d8a59c302d2fa32f859a76e69ee7410 Mon Sep 17 00:00:00 2001 From: janwas Date: Fri, 5 May 2006 05:54:00 +0000 Subject: [PATCH] # add strict VSrc validation in OpenAL interface to track down bug - required adding C99 insnan() implementation, along with fpclassify This was SVN commit r3850. --- source/lib/res/sound/snd_mgr.cpp | 11 +++++++++++ source/lib/sysdep/ia32.h | 10 ++++++++++ source/lib/sysdep/ia32_asm.asm | 30 ++++++++++++++++++++++++++++-- source/lib/sysdep/sysdep.cpp | 15 +++++++++++++++ source/lib/sysdep/sysdep.h | 16 ++++++++++++++++ 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/source/lib/res/sound/snd_mgr.cpp b/source/lib/res/sound/snd_mgr.cpp index afabeb6485..91a2259da6 100644 --- a/source/lib/res/sound/snd_mgr.cpp +++ b/source/lib/res/sound/snd_mgr.cpp @@ -1827,11 +1827,22 @@ static void vsrc_latch(VSrc* vs) if(!vs->al_src) return; +#ifndef NDEBUG + // paranoid value checking; helps determine which parameter is + // the problem when the below AL_CHECK fails. + debug_assert(!isnan(vs->pos[0]) && !isnan(vs->pos[1]) && !isnan(vs->pos[2])); + debug_assert(vs->relative == AL_TRUE || vs->relative == AL_FALSE); + debug_assert(!isnan(vs->gain)); + debug_assert(!isnan(vs->pitch) && vs->pitch > 0.0f); + debug_assert(vs->loop == AL_TRUE || vs->loop == AL_FALSE); +#endif + alSourcefv(vs->al_src, AL_POSITION, vs->pos); alSourcei (vs->al_src, AL_SOURCE_RELATIVE, vs->relative); alSourcef (vs->al_src, AL_GAIN, vs->gain); alSourcef (vs->al_src, AL_PITCH, vs->pitch); alSourcei (vs->al_src, AL_LOOPING, vs->loop); + AL_CHECK; } diff --git a/source/lib/sysdep/ia32.h b/source/lib/sysdep/ia32.h index 02facc107f..cb118ad466 100644 --- a/source/lib/sysdep/ia32.h +++ b/source/lib/sysdep/ia32.h @@ -54,6 +54,16 @@ extern i32 ia32_i32_from_float(float f); extern i32 ia32_i32_from_double(double d); extern i64 ia32_i64_from_double(double d); +// fpclassify return values +#define IA32_FP_NAN 0x0100 +#define IA32_FP_NORMAL 0x0400 +#define IA32_FP_INFINITE (IA32_FP_NAN | IA32_FP_NORMAL) +#define IA32_FP_ZERO 0x4000 +#define IA32_FP_SUBNORMAL (IA32_FP_NORMAL | IA32_FP_ZERO) + +extern uint ia32_fpclassify(double d); +extern uint ia32_fpclassifyf(float f); + extern void* ia32_memcpy(void* dst, const void* src, size_t nbytes); // asm diff --git a/source/lib/sysdep/ia32_asm.asm b/source/lib/sysdep/ia32_asm.asm index afef8e19d0..a81225b338 100644 --- a/source/lib/sysdep/ia32_asm.asm +++ b/source/lib/sysdep/ia32_asm.asm @@ -503,10 +503,10 @@ db 0xf0 ; LOCK prefix ;------------------------------------------------------------------------------- -; misc +; FPU ;------------------------------------------------------------------------------- -; extern "C" uint __cdecl ia32_control87(uint new_cw, uint mask) +; extern "C" uint __cdecl ia32_control87(uint new_cw, uint mask); global sym(ia32_control87) sym(ia32_control87): push eax @@ -525,6 +525,32 @@ sym(ia32_control87): ret +; possible IA-32 FPU control word flags after FXAM: NAN|NORMAL|ZERO +FP_CLASSIFY_MASK equ 0x4500 + +; extern "C" uint __cdecl ia32_fpclassify(double d); +global sym(ia32_fpclassify) +sym(ia32_fpclassify): + fld qword [esp+4] + fxam + fnstsw ax + and eax, FP_CLASSIFY_MASK + ret + +; extern "C" uint __cdecl ia32_fpclassifyf(float f); +global sym(ia32_fpclassifyf) +sym(ia32_fpclassifyf): + fld dword [esp+4] + fxam + fnstsw ax + and eax, FP_CLASSIFY_MASK + ret + + +;------------------------------------------------------------------------------- +; misc +;------------------------------------------------------------------------------- + ; write the current execution state (e.g. all register values) into ; (Win32::CONTEXT*)pcontext (defined as void* to avoid dependency). ; optimized for size; this must be straight asm because __declspec(naked) diff --git a/source/lib/sysdep/sysdep.cpp b/source/lib/sysdep/sysdep.cpp index da6a323078..27b1bcf0a7 100644 --- a/source/lib/sysdep/sysdep.cpp +++ b/source/lib/sysdep/sysdep.cpp @@ -51,6 +51,21 @@ float fmaxf(float a, float b) return (a > b)? a : b; } +uint fpclassify(double d) +{ + // really sucky stub implementation; doesn't attempt to cover all cases. + + if(d != d) + return IA32_FP_NAN; + else + return IA32_FP_NORMAL; +} + +uint fpclassifyf(float f) +{ + return fpclassify((double)f); +} + #endif #endif // #if !HAVE_C99 diff --git a/source/lib/sysdep/sysdep.h b/source/lib/sysdep/sysdep.h index f0dcc8a6b1..3b2f1a5654 100644 --- a/source/lib/sysdep/sysdep.h +++ b/source/lib/sysdep/sysdep.h @@ -101,13 +101,29 @@ extern void* alloca(size_t size); # define rint ia32_rint # define fminf ia32_fminf # define fmaxf ia32_fmaxf + +# define FP_NAN IA32_FP_NAN +# define FP_NORMAL IA32_FP_NORMAL +# define FP_INFINITE (FP_NAN | FP_NORMAL) +# define FP_ZERO IA32_FP_ZERO +# define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) +# define fpclassify ia32_fpclassify // .. portable C emulation # else extern float rintf(float f); extern double rint(double d); extern float fminf(float a, float b); extern float fmaxf(float a, float b); + +# define FP_NAN 1 +# define FP_NORMAL 2 +# define FP_INFINITE (FP_NAN | FP_NORMAL) +# define FP_ZERO 4 +# define FP_SUBNORMAL (FP_NORMAL | FP_ZERO) + extern uint fpclassify(double d); # endif + +# define isnan(d) (fpclassify(d) == FP_NAN) #endif // finite: return 0 iff the given double is infinite or NaN.