Project

General

Profile

Bug #3296

windows で iconv.dll の使用する MSVC runtime DLL のバージョンが、ruby 本体が使用するものと一致していない場合に[BUG]が出る。

Added by tarui (Masaya Tarui) over 9 years ago. Updated over 8 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
ruby -v:
ruby 1.9.2dev (2010-05-14 revision 27797) [i386-mswin32_90]
Backport:

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
#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

    • } =end

History

#1

Updated by nobu (Nobuyoshi Nakada) over 9 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

#2

Updated by nobu (Nobuyoshi Nakada) over 9 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

Also available in: Atom PDF