Bug #3296
closedwindows で iconv.dll の使用する MSVC runtime DLL のバージョンが、ruby 本体が使用するものと一致していない場合に[BUG]が出る。
Description
=begin
樽家です。
ランタイムが一致していない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 <share.h>
#include <shlobj.h>
#include <mbstring.h>
+#include <imagehlp.h>
+
#if _MSC_VER >= 1400
#include <crtdbg.h>
#include <rtcapi.h>
@@ -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
}
=end
Updated by nobu (Nobuyoshi Nakada) over 14 years ago
=begin
なかだです。
At Sat, 15 May 2010 01:24:56 +0900,
masaya tarui wrote in [ruby-dev:41317]:
所で、根本的にはerrnoがうまく取れればいいため、以下のようなPatchを書いてみました。
iconv.dllで使用している _errno() を調べてそれを参照するようにします。
取り込み可能でしょうか?
これだけのためにそこまでする必要あるかなぁ、というのが正直な感想
ですが、それは置いておくにしてもこれだけでは効果がないと思います。
なぜなら、iconv.soから見えるerrnoを変えたところでrb_sys_fail()か
ら見えるerrnoにはまったく変わりが無いからです。
この問題はiconvに限らないので、できることなら拡張ライブラリをあ
まりいじらずに自動的に解決できる方法があるといいのですが、中には
複数の外部ライブラリをリンクするものもあったりするので、ちょっと
難しそうに思えます。
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦
=end
Updated by nobu (Nobuyoshi Nakada) over 14 years ago
- Status changed from Open to Closed
=begin
This issue was solved with changeset r27805.
Masaya, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
=end