From: masaya tarui Date: 2010-05-15T01:24:56+09:00 Subject: [ruby-dev:41317] [Bug #3296] windows で iconv.dll の使用する MSVC runtime DLL のバージョンが、ruby 本体が使用するものと一致していない場合に[BUG]が出る。 Bug #3296: windows で iconv.dll の使用する MSVC runtime DLL のバージョンが、ruby 本体が使用するものと一致していない場合に[BUG]が出る。 http://redmine.ruby-lang.org/issues/show/3296 起票者: masaya tarui ステータス: Open, 優先度: Low Target version: 1.9.2 ruby -v: ruby 1.9.2dev (2010-05-14 revision 27797) [i386-mswin32_90] 樽家です。 ランタイムが一致していないiconv.dllをロードする環境で、以下のソース require 'iconv' Iconv.iconv("utf-8", "SJIS", "heh") Iconv.iconv("utf-8", "X-UKNOWN", "heh") を実行すると、 /soft/iconv.rb:4: [BUG] rb_sys_fail(iconv("utf-8", "X-UKNOWN")) - errno == 0 と言われます。 ランタイムが一致していない場合、errnoをうまく更新できないために、 iconvで失敗した場合に、Iconv::BrokenLibrary例外 を出力するのが正しいはずです。 所で、根本的にはerrnoがうまく取れればいいため、以下のようなPatchを書いてみました。 iconv.dllで使用している _errno() を調べてそれを参照するようにします。 取り込み可能でしょうか? Index: include/ruby/win32.h =================================================================== --- include/ruby/win32.h (リビジョン 27790) +++ include/ruby/win32.h (作業コピー) @@ -274,6 +274,9 @@ extern int fcntl(int, int, ...); extern rb_pid_t rb_w32_getpid(void); extern rb_pid_t rb_w32_getppid(void); + +extern void *rb_w32_GetImportFunctionPtr(const char *,const char *); + #if !defined(__BORLANDC__) extern int rb_w32_isatty(int); #endif Index: win32/win32.c =================================================================== --- win32/win32.c (リビジョン 27790) +++ win32/win32.c (作業コピー) @@ -29,6 +29,8 @@ #include #include #include +#include + #if _MSC_VER >= 1400 #include #include @@ -5641,3 +5643,32 @@ return *ip < 0; } #endif + +void * +rb_w32_GetImportFunctionPtr(const char *modname,const char *funcname){ + HMODULE hmod; + ULONG size; + const IMAGE_IMPORT_DESCRIPTOR* desc; + hmod = GetModuleHandle(modname); + if(!hmod)return NULL; + desc = ImageDirectoryEntryToData(hmod,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size); + if(!desc)return NULL; + while(desc->Name){ + PIMAGE_THUNK_DATA piat,pint; + PIMAGE_IMPORT_BY_NAME pii; + pint = (PIMAGE_THUNK_DATA)((char *)hmod + desc->Characteristics); + piat = (PIMAGE_THUNK_DATA)((char *)hmod + desc->FirstThunk); + while(piat->u1.Function){ + pii = (PIMAGE_IMPORT_BY_NAME)((char *)hmod+ pint->u1.AddressOfData); + if(strcmp(pii->Name,funcname)==0){ + return (void *)piat->u1.Function; + } + piat++; + pint++; + } + desc++; + } + return NULL; +} + + Index: win32/Makefile.sub =================================================================== --- win32/Makefile.sub (リビジョン 27790) +++ win32/Makefile.sub (作業コピー) @@ -212,7 +212,7 @@ EXTLIBS = !endif !if !defined(LIBS) -LIBS = oldnames.lib user32.lib advapi32.lib shell32.lib ws2_32.lib $(EXTLIBS) +LIBS = oldnames.lib user32.lib advapi32.lib shell32.lib ws2_32.lib imagehlp.lib $(EXTLIBS) !endif !if "$(ENABLE_WIN95)" == "yes" LIBS = unicows.lib $(LIBS) Index: ext/iconv/iconv.c =================================================================== --- ext/iconv/iconv.c (リビジョン 27790) +++ ext/iconv/iconv.c (作業コピー) @@ -130,6 +130,14 @@ static VALUE charset_map; + +#ifdef _WIN32 +static int* (* _iconv_errno)(void); +#undef errno +#define errno (*_iconv_errno()) +#endif + + /* * Document-method: charset_map * call-seq: Iconv.charset_map @@ -1212,5 +1220,12 @@ rb_gc_register_address(&charset_map); charset_map = rb_hash_new(); rb_define_singleton_method(rb_cIconv, "charset_map", charset_map_get, 0); + +#ifdef _WIN32 + _iconv_errno = rb_w32_GetImportFunctionPtr("iconv.dll","_errno"); + if(!_iconv_errno) + _iconv_errno = _errno; +#endif + } ---------------------------------------- http://redmine.ruby-lang.org