2012-07-25

MSのBig Boobs(デカパイ)コード、修正さる

LKML: Paolo Bonzini: 0xB16B00B5? Really? (was Re: Move hyperv out of the drivers/staging/ directory)

上記の報告によって、Microsoftの提供した、自社の仮想環境Hyper-V上で動作するLinuxカーネルのパフォーマンスを向上させるパッチによってもたらされたコードに、0xB16B00B5という、なんだか面白い16進数整数リテラルが含まれていることが明らかになった。どうも、Big Boobs(デカパイ)と読める。この値は、IDとしての値なので、何か一貫した値を選ぶ必要があった。しかし、よりにもよってこんな面白い値を選択するとは。

この発見によって、Microsoftの文化が男性的でありけしからんなどという批判が巻き起こった。

このたび、Microsoftが正式に謝罪し、コードを修正することになったそうだ。

Linux Kernel Undergoes Breast Reduction Surgery | Wired Enterprise | Wired.com

修正方法は、0xB16B00B5を、同じ値の10進数整数リテラルである2976579765に書き換えるものである。

マイクロソフトのコード上の茶目っ気をうかがい知る例としては、以下のようなものもある。

Why does Windows 95 have functions called BEAR, BUNNY and PIGLET? - The Old New Thing - Site Home - MSDN Blogs
What about BOZOSLIVEHERE and TABTHETEXTOUTFORWIMPS? - The Old New Thing - Site Home - MSDN Blogs

特に二つ目のBOZOSLIVEHEREの例は、下位互換性の問題も絡んでいて、興味深い。

最初期のWindowsでは、ウインドウプロシージャはすべてエクスポートされている必要があった。標準のコントロールのウインドウプロシージャを得るドキュメント化された方法は、GetWindowLongの第二引数にGWL_WNDPROCを渡すものである。しかし、プログラマーというのはえてして怠惰な人間であり、GetWindowLong( hwnd, GWL_WNDPROC )などと書くのを嫌った。「そもそも、ウインドウプロシージャがエクスポートされているならば、直接リンクしてしまえばいいではないか」と考えた。そのため、当時、EDITコントロールのウインドウプロシージャの名前として使われていたBOZOSLIVEHEREに直接リンクして使っていた。おそらくWindows 2.0あたりから、ウインドウプロシージャは、関数のエクスポートを必要としなくなった。そのため、エクスポートをやめてみたのだが、そうすると既存のソフトウェアの多くが動かなくなる。解析した結果、どうもエクスポートされていることをあてにして、直接リンクしている。そのため、エクスポートしたままにしておかなければならなかった。

後に、Windowsが32bitに移行した時、16bitコードで直接リンクしている腐ったプログラムを壊さないために、この手の関数呼び出しを本物の関数呼び出しに変換する関数として、BOZOSLIVEHEREは依然としてエクスポートされた。

他にも似たような例で興味深いのは、この記事だろう。

Why do I have to return this goofy value for WM_DEVICECHANGE? - The Old New Thing - Site Home - MSDN Blogs

プラグアンドプレイにおいて、デバイスの取り外し通知のウインドウメッセージに対して、拒否する場合、BROADCAST_QUERY_DENYを返さなければならない。この値は、なぜか0x424D5144である。これは、最初m単にFALSE(0)を返すように設計されたのだが、そうすると、多くの既存のプログラムが、取り外しを拒否した。調べてみると、これらのソフトウェアは、DefWindowProcを使っていないソフトウェアであった。

Windowsでは、処理しなかったウインドウメッセージは、かならずDefWindowProcに渡して、その結果を返さなければならない。これにより、将来新しいウインドウメッセージが追加された時も、DefWindowProcを呼び出していれば、そのバイナリは互換性を保つことができる。ところが、多くの怠惰なプログラマーが、DefWindowProcを呼び出すなんてめんどくさいとばかりに、単にreturn FALSEと書いているらしい。いくつかのウインドウメッセージは0を返してはならない仕様になっているのだが、この手の怠惰なプログラマーは、そういうウインドウメッセージを自前で処理するほどにはマメだったらしい。結果として、Windows 3.1上では、たまたま問題なく動くプログラムとなっていた。

そのため、単にFALSEを返す設計は使えない。安全のために、TRUE、すなわち1を変えさせる設計も避けた。結果として、まず返し用のない値、0x424D5144が選ばれた。ちなみに、この値は、ASCIIでDQMBである。これは、Broadcast Message Query Denyの頭文字となっている。

No, really, you need to pass all unhandled messages to DefWindowProc - The Old New Thing - Site Home - MSDN Blogs

処理しないウインドウメッセージは、ちゃんとDefWindowProcに渡すべきである。

No, really, you need to pass all unhandled messages to DefWindowProc - The Old New Thing - Site Home - MSDN Blogs

3 comments:

Anonymous said...

「そもそもこんな馬鹿げたことをしなければならないのは、動かなくなった不自由なソフトウェアを修正できないからだ」
って続くのかと思ったのに。

江添亮 said...

残念ながら、下位互換性の維持は、ソフトウェアが自由であっても重要です。

「いずれ誰かによって書かれる」としても、誰かがやる必要があります。今更誰も利用していないようなものは、移植されにくいのです。

さらに、たとえ問題のあるプログラムが修正されたとしても、利用者が手元で使っているプログラムがアップデートされなければなりません。

Anonymous said...

>「いずれ誰かによって書かれる」としても、誰かがやる必要があります。
> さらに、たとえ問題のあるプログラムが修正されたとしても、利用者が手元で使っているプログラムがアップデートされなければなりません。
DebianやUbuntuのパッケージ管理はまさにそれをやっていますよね。だからこそpoolのソフトウェアが自由であることはほとんど必要不可欠だし、LinusはNVIDIAにキレるわけです。