9

MacOSXにVorbisOggファイルをロードする際に不思議なバグがありました。最初のファイルは正しくロードされ、2番目のファイルはファイルが破損していることを示すコードでクラッシュします。同じ正確なファイルを2回ロードしても、同じことが起こります。

Vorbis内での長時間の詳細なデバッグの結果、バグの原因は、システム関数 "pow"(の2倍)が完全に有効な入力に対して(nan)を返すことであり、これは(ov_readの2回目の呼び出しでのみ発生する)ことがわかりました。 )、最初の呼び出しで、「pow」に渡された同じ正確な値が有効な結果を返します。

8時間後、Intelx87のドキュメントをたくさん読んで問題が見つかりました。簡単に言うと、このアセンブリコードを使用する関数「vorbis_ftoi」がvorbisの奥深くにあります。

__asm__("fistl %0": "=m"(i) : "t"(f));

これは、IntelFPUスタックをプッシュしてポップする必要があります。ただし、LLVMでは次のコードが生成されます。

fld    QWORD PTR [ebp-0x20]
fist   DWORD PTR [ebp-0x14]

これはスタックをプッシュしますが、FPUスタックオーバーフローを引き起こすことはありません。そしてそれは明らかにLLVMのバグです

GCCによって生成される適切なコードは次のようになります。

fld    QWORD PTR [ebp-0x20]
fist   DWORD PTR [ebp-0xc]
fstp   st(0)        // pops off the stack

私はこれについていくつかのゴミ(x87命令セットとレジスター)を学ぶ私のブライアンの1日半と数バイトを無駄にしたので、私はそれを共有したいと思います。

オーデイ

4

2 に答える 2

3

単純なパッチで、llvm でコンパイルする場合にのみ影響します:

--- Xiph\vorbis\os.h    Mon Mar 28 08:42:43 2011
+++ Xiph\vorbis\os.h    Thu Feb 02 14:20:27 2012
@@ -81,7 +81,7 @@


 /* Special i386 GCC implementation */
-#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__)
+#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__) && !defined(__llvm__)
 #  define VORBIS_FPU_CONTROL
 /* both GCC and MSVC are kinda stupid about rounding/casting to int.
    Because of encapsulation constraints (GCC can't see inside the asm

残念ながら、OP に投票するほどの評判はありませんが、あなたの発見に感謝しています。ありがとうございました。

于 2012-02-02T14:22:06.057 に答える
2

優秀な!ありがとうございました。別の解決策は、単純に asm を完全に削除することです。ここにパッチがあります:

--- lib/os.h 2011-11-13 20:36:24.000000000 -0500
+++ lib/os.h        2011-11-15 18:45:00.000000000 -0500
@@ -93,27 +93,16 @@
 typedef ogg_int16_t vorbis_fpu_control;

 static inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){
-  ogg_int16_t ret;
-  ogg_int16_t temp;
-  __asm__ __volatile__("fnstcw %0\n\t"
-          "movw %0,%%dx\n\t"
-          "andw $62463,%%dx\n\t"
-          "movw %%dx,%1\n\t"
-          "fldcw %1\n\t":"=m"(ret):"m"(temp): "dx");
-  *fpu=ret;
 }

 static inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
-  __asm__ __volatile__("fldcw %0":: "m"(fpu));
 }

 /* assumes the FPU is in round mode! */
 static inline int vorbis_ftoi(double f){  /* yes, double!  Otherwise,
                                              we get extra fst/fld to
                                              truncate precision */
-  int i;
-  __asm__("fistl %0": "=m"(i) : "t"(f));
-  return(i);
+    return (int)floor(f+.5);
 }
 #endif /* Special i386 GCC implementation */
于 2011-11-15T23:55:03.527 に答える