Project

General

Profile

Actions

Bug #6303

closed

dln_load and rb_w32_check_imported cause segfault in Ruby 1.9.3 for some extension

Added by luislavena (Luis Lavena) over 12 years ago. Updated about 12 years ago.

Status:
Closed
Target version:
ruby -v:
1.9.3
Backport:
[ruby-core:44371]

Description

Hello,

NOTE: Reporting this here since bugs.ruby-lang.org seems to be down.

Recently a user reported to RubyInstaller project issues when loading
a Ruby 1.9.2 compiled extension under Ruby 1.9.3:

https://groups.google.com/d/msg/rubyinstaller/aSezE2LwfQs/TDZvPG3X5mUJ

Which I was able to study a bit better:
https://groups.google.com/d/msg/rubyinstaller/aSezE2LwfQs/UGKlButpNfMJ

To add more, my last comment was:

"Is worth to mention that this do not fail against 1.9.2 (either
building or running) but dln_load mechanism on Ruby 1.9.2 differs from
Ruby 1.9.3 and highly unlikely is going to change."

I'm not convinced by my last comment and I do believe this is a bug.
db2cli.dll links to MSVCR80 and even so, it loads properly under
1.9.2.

Looking closely to what rb_w32_check_imported does, it is supposed to
verify that the extension being loaded it is indeed using the right
ruby dll.

But is failing to obtain Name from pii (PIMAGE_IMPORT_BY_NAME struct)

I can't find any reference to dbghelp (which provides
ImageDirectoryEntryToData) being included or linked in
msvcrt-libruby191.dll

For sure I'm missing something, specially why is failing to obtain
this extension information when works for others.

Thank you.

Luis Lavena
AREA 17

Perfection in design is achieved not when there is nothing more to add,
but rather when there is nothing more to take away.
Antoine de Saint-Exupéry

Updated by phasis68 (Heesob Park) over 12 years ago

The segfault is due to the invalid pointer reference in getting PIMAGE_IMPORT_BY_NAME pointer like this:

PIMAGE_IMPORT_BY_NAME pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);

Consider the following imports dump list of ibm_db.so

DB2CLI.dll
          63317274 Import Address Table
          63317078 Import Name Table
                 0 time date stamp
                 0 Index of first forwarder reference

                  Ordinal  1300
                  Ordinal  1301
               6C SQLDriverConnectW@32
               52 SQLConnectW@28
                  Ordinal     9
                  Ordinal  1303
                  Ordinal    58
               64 SQLDescribeColW@36
                  Ordinal     4
               4A SQLColumnPrivilegesW@36
               4E SQLColumnsW@36
               FB SQLPrimaryKeysW@28
               98 SQLForeignKeysW@52
               FF SQLProcedureColumnsW@36
              103 SQLProceduresW@28
              133 SQLSpecialColumnsW@40
              137 SQLStatisticsW@36
              13B SQLTablePrivilegesW@28
              13F SQLTablesW@36
               7A SQLExecDirectW@12
               F7 SQLPrepareW@12

...

As you can see, the name table entry has two types: ordinal type and name type.
But, the rb_w32_check_imported function overlooked ordinal case.

Refer to http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html

Here is a patch:

diff --git a/dln.c b/dln.c.new
index e3dff9b..58042e1 100644
--- a/dln.c
+++ b/dln.c.new
@@ -1215,12 +1215,14 @@ rb_w32_check_imported(HMODULE ext, HMODULE mine)
PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics);
PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk);
while (piat->u1.Function) {

  •   PIMAGE_IMPORT_BY_NAME pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
    
  •   static const char prefix[] = "rb_";
    
  •   const char *name = (const char *)pii->Name;
    
  •   if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
    
  •   FARPROC addr = GetProcAddress(mine, name);
    
  •   if (addr) return (FARPROC)piat->u1.Function == addr;
    
  •   if(!IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) {
    
  •       PIMAGE_IMPORT_BY_NAME pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData);
    
  •       static const char prefix[] = "rb_";
    
  •       const char *name = (const char *)pii->Name;
    
  •       if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
    
  •       FARPROC addr = GetProcAddress(mine, name);
    
  •       if (addr) return (FARPROC)piat->u1.Function == addr;
    
  •       }
      }
      piat++;
      pint++;
    
Actions #2

Updated by nobu (Nobuyoshi Nakada) over 12 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r35352.
Luis, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • dln.c (rb_w32_check_imported): skip ordinal entries. patched by
    phasis68 (Heesob Park) at [ruby-core:44381]. [Bug #6303]

Updated by phasis68 (Heesob Park) over 12 years ago

The changeset r35352 is not same to my patch and the bug #6303 is not fixed.

After applying r35352,
require 'mswin32/ibm_db'
falls into infinite loop and runs forever.

The line
if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue;

should be

if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) {pint++;piat++;continue;}

Updated by luislavena (Luis Lavena) over 12 years ago

  • Category set to core
  • Status changed from Closed to Assigned
  • Assignee set to nobu (Nobuyoshi Nakada)
  • Target version set to 1.9.3
  • % Done changed from 100 to 80
  • ruby -v set to 1.9.3
Actions #5

Updated by nobu (Nobuyoshi Nakada) over 12 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 80 to 100

This issue was solved with changeset r35354.
Luis, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0