Ruby Installer for Windows: use of Win32OLE bug causes crash

J

Jos Backus

This is with the latest Ruby Installer for Windows, 181-13-rc2.

When I run the script below I see:

C:\localbin>diskspace.rb
(offline mode: enter name=value pairs on standard input)
^Z
(eval):1214: [BUG] Segmentation fault
ruby 1.8.1 (2003-12-25) [i386-mswin32]


This application has requested the Runtime to terminate it in an unusual
way.
Please contact the application's support team for more information.

C:\localbin>

When I replace the get_diskinfo call with a call to fake_get_diskinfo,
skipping the Win32OLE calls, the program works fine (but is useless, of
course). I have added a comment to (closed) bug 522 on RubyForge.

Any help is appreciated.

#!ruby

require 'win32ole'
require 'cgi'
require 'stringio'

outputfilename = "diskspace.htm"

hosts = []
File.open("diskspace_hosts.txt").each_line do |line|
next if line =~ /^\s*(#|$)/
hosts << line.chomp
end

hosts =%w(localhost localhost localhost somehost)

class DiskInfo
attr_reader :deviceid, :size, :freespace
def initialize(deviceid, size, freespace)
@deviceid, @size, @freespace = deviceid, size.to_i, freespace.to_i
end
def pct_free
freespace.to_f / size * 100
end
end

def fake_get_diskinfo(host)
result = []
result << DiskInfo.new('C:', 10000000000, 5000000000)
result << DiskInfo.new('D:', 20000000000, 8000000000)
end

# Returns a list of DiskInfo objects for host, or nil
def get_diskinfo(host)
result = []
begin
wmi = WIN32OLE.connect("winmgmts://#{host}/root/cimv2")
rescue
return nil
end
disks = wmi.ExecQuery("Select * from Win32_LogicalDisk")
disks.each do |disk|
next if disk.Size.nil?
result << DiskInfo.new(disk.DeviceID, disk.Size, disk.FreeSpace)
end
result
end

# Map freespace percentage to color codes
def alert_color(value)
case value
when 20..100; "lightgreen"
when 10...20; "yellow"
when 5...10; "orange"
when 0...5; "red"
else raise # Shouldn't happen
end
end

diskdata = hosts.collect do |host|
[ host, get_diskinfo(host) ]
end

File.open(outputfilename, "w") do |file|
# Hack alert:
# Since cgi.out writes to $DEFAULT_OUTPUT we capture the output in outstring by directing $DEFAULT_OUTPUT to it.
# We need to do this because we want to strip the first 3 lines from the output (the HTTP header).
outstring = StringIO.new
$DEFAULT_OUTPUT = outstring

cgi = CGI.new("html4") # add HTML generation methods
cgi.out {
cgi.html {
cgi.head { "\n" + cgi.title{"Disk Space Overview"} } +
cgi.body { "\n" +
cgi.h2 { "Disk space by host by drive" } +
cgi.p { "Last updated: " + Time.now.to_s } +
cgi.table {
cgi.tr { cgi.th({"width" => "120%", "align" => "left"}) { "Host" } + cgi.th { "Disk" } + cgi.th { "Total" } + cgi.th { "Free" } + cgi.th { "%" } } +
diskdata.collect do |host, di|
unless di
cgi.tr { cgi.td("bgcolor" => "red") { host } }
else
di.collect { |disk|
cgi.tr {
cgi.td { host } +
cgi.td { disk.deviceid } +
cgi.td { disk.size / 1024 ** 3 } +
cgi.td { disk.freespace / 1024 ** 3 } +
cgi.td("bgcolor" => alert_color(disk.pct_free)) { "%3.2d" % disk.pct_free }
}
}
end
end.join("\n")
}
}
}
}

outstring.rewind
file.puts outstring.readlines[3..-1] # Drop HTTP header
outstring.close
end

exit

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
S

Shashank Date

Jos Backus said:
This is with the latest Ruby Installer for Windows, 181-13-rc2.

When I run the script below I see:

C:\localbin>diskspace.rb
(offline mode: enter name=value pairs on standard input)
^Z
(eval):1214: [BUG] Segmentation fault
ruby 1.8.1 (2003-12-25) [i386-mswin32]

Thanks for reporting this with an example ... we (the Ruby-Installer team)
were
unable to test this before putting out the rc2 for want of such an example.

I do not know if we will able to fix it, but at least we will be able to
test it better.

-- shanko
 
J

Jos Backus

Thanks for reporting this with an example ... we (the Ruby-Installer team)
were
unable to test this before putting out the rc2 for want of such an example.

I have been drilling down into this problem most of the afternoon, and I have
been stripping diskspace.rb to where a _source_ change of removing a specific
line causes an error. So it looks like some kind of memory corruption problem
during the lexing/parsing phase? I'll dig further.
I do not know if we will able to fix it, but at least we will be able to
test it better.

Thanks. Please let me know if you can repro this problem. I am on Win2K3
Server.

Cheers,
--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
J

Jos Backus

I have been drilling down into this problem most of the afternoon, and I have
been stripping diskspace.rb to where a _source_ change of removing a specific
line causes an error. So it looks like some kind of memory corruption problem
during the lexing/parsing phase? I'll dig further.

Oops, I forgot to mention that the specific line I'm removing is EMPTY. And I
can reproduce this in different parts of the source file. It's definitely
vertical whitespace-related. Oddest bug I've seen in a while.

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
S

Shashank Date

Jos Backus said:
Oops, I forgot to mention that the specific line I'm removing is EMPTY. And I
can reproduce this in different parts of the source file. It's definitely
vertical whitespace-related. Oddest bug I've seen in a while.

Strange ! Which line is that ?
-- shanko
 
S

Shashank Date

Jos Backus said:
Please let me know if you can repro this problem. I am on Win2K3
Server.

Yes, I was able to reproduce this also on Win XP (Home).
-- shanko
 
J

Jos Backus

--yrj/dFKFPuw6o+aM
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Strange ! Which line is that ?

There are a few positions in the file where this happens. Starting from the
bottom I can "move" the empty line I'm deleting up and get the same error, but
it doesn't work near the top of the file. I'm assuming the bug is such that
Ruby needs to have seen a declaration of a particular kind before the problem
manifests itself. In the attached file, which works in its current form on 2K3
I was able to trigger the problem arbitrarily by extending some of the string
constants beyond a certain length or removing expression terms (e.g. 1 * 1 ->
1) in addition to changing the vertical whitespace (horizontal whitespace
seemed to have no influence). I saw the line issue at line 74 in the attached
file, and the first problem occurred when I tried adding an "align" => "right"
argument to a cgi.td call. But I'd be surprised if you could duplicate the
subtle failures 2K3 showed on XP, as I wasn't able to.

It sure would be nice to hear the win32ole author pipe up.
-- shanko

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'

--yrj/dFKFPuw6o+aM
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diskspace_noerror.rb"

require 'win32ole'
require 'cgi'
require 'stringio'

outputfilename = "NUL.aaaa"

hosts = []
File.open("dhhhhhhhhhhh.txt").each_line do |line|

foo = ""
hosts << line.chomp
end

hosts = %w(localhost localhost localhost localhost)

class DiskInfo
attr_reader :deviceid, :size, :freespace
def initialize(deviceid, size=1, freespace=1)
@deviceid, @size, @freespace = deviceid, size, freespace
end
def p
1 + 1
end
end


def get_diskinfo(host)
result = []
result << DiskInfo.new('')
result << DiskInfo.new('')
result = []
begin
wmi = WIN32OLE.connect("winmgmts://#{host}/root/cimv2")
rescue
return nil
end
disks = wmi.ExecQuery("Select * from Win32_LogicalDisk")
disks.each do |disk|

next if disk.Size.nil?
next if disk.Size.to_i == 0 and disk.FreeSpace.to_i == 0
result << DiskInfo.new(disk.DeviceID, disk.Size.to_i, disk.FreeSpace.to_i)
end
result
end


def alert_color(value)
case value
when 10...20; ""
when 5...10; ""
when 0...5; ""
else raise
end
end

diskdata = hosts.collect do |host|
[ host, get_diskinfo(host) ]
end

cgi = CGI.new("html4")
cgi.out {
diskdata.collect { |host, di|
di.collect { |disk|
cgi.tr {
cgi.td { "" } +
cgi.td { "" } +
cgi.td { "" } +
cgi.td { "" }
}
}
}
}

File.open(outputfilename, "w") do |file|
foo = "" + ""
end


exit

File.open(outputfilename, "w") do |file|
foo = ""
bar = ""

cgi = CGI.new("html4")
cgi.out {
cgi.html {
cgi.head { "" + cgi.title{" "} } +
cgi.body { "" +
cgi.h2 { " " } +
cgi.p { "" + Time.now.to_s } +
cgi.table {
cgi.tr { cgi.th({"width" => " ", "alig" => "le"}) { "Host" } + cgi.th { "Disk" } + cgi.th { "Total" } + cgi.th { "Free" } + cgi.th { "%" } } +
diskdata.collect { |host, di|
unless di
cgi.tr { cgi.td { "" } }
else
di.collect { |disk|
cgi.tr {
cgi.td { "" } +
cgi.td { "" } +
cgi.td { "" / 1 * 3 } +
cgi.td { "" / 1 * 3 } +
cgi.td() { "" % disk.size }
}
}
end
}
}.join("")
}
}
}


foo = ""
file.puts outstring.readlines[1,1]
file.puts
foo = "" + ""
end
--yrj/dFKFPuw6o+aM--
 
S

Shashank Date

Jos Backus said:
In the attached file, which works in its current form on 2K3

I was able to run it on Win XP without a problem. Incidently I was also able
to run your original program with minor modifications (see line 13 and
94 thru 97 of the attached ...).

But it failed when I uncommented lines 94 and 97 ** AND ** installed
the flash disk so that there were two logical drives.
I was able to trigger the problem arbitrarily by extending some of the string
constants beyond a certain length or removing expression terms (e.g. 1 * 1 ->
1) in addition to changing the vertical whitespace (horizontal whitespace
seemed to have no influence). I saw the line issue at line 74 in the attached
file, and the first problem occurred when I tried adding an "align" => "right"
argument to a cgi.td call.

I will give that a try ...
It sure would be nice to hear the win32ole author pipe up.

At this point it does not seem like a win32ole issue since the following
snippet
works (at least on Win XP and ruby-1.8.1-rc13):
#---------------------------------------------
require 'win32ole'

host = "localhost"
wmi = WIN32OLE.connect("winmgmts://#{host}/root/cimv2")
disks = wmi.ExecQuery("Select * from Win32_LogicalDisk")
p disks

disks.each do |disk|
next if disk.Size.nil?
p disk.DeviceID, disk.Size, disk.FreeSpace
end
#---------------------------------------------
 
J

Jos Backus

At this point it does not seem like a win32ole issue since the following
snippet
works (at least on Win XP and ruby-1.8.1-rc13):
#---------------------------------------------
require 'win32ole'

host = "localhost"
wmi = WIN32OLE.connect("winmgmts://#{host}/root/cimv2")
disks = wmi.ExecQuery("Select * from Win32_LogicalDisk")
p disks

disks.each do |disk|
next if disk.Size.nil?
p disk.DeviceID, disk.Size, disk.FreeSpace
end
#---------------------------------------------

But it breaks the moment you add any CGI call. Now what is more likely to be
the culprit, cgi.rb et al. (all written in Ruby afaIk) or win32ole.so? My
money's on a module that interacts heavily with COM/OLE/the Win32 API, not the
interpreter. Adding cgi.rb to the program does trigger the problem but I'm
confident that the real problem is inside win32ole. Note also that in the most
stripped example, among others, removing the require 'fileutils' makes the
error go away. That to me smells like a file descriptor/memory issue of some
sort.

Of course I could be all wrong :) Methinks the win32ole author should be able
to track this one down using the failing examples given. That sure would be
nice, as the win32ole stuff is incredibly powerful.

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
J

Jos Backus

Yes, I was able to reproduce this also on Win XP (Home).

Good I can no longer reproduce this using yesterday's CVS -HEAD. The
problem also seems to have disappeared when using this snapshot (in case you
can't easily build from source).

ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.9.0-20040402-i386-mswin32.zip

Perhaps you can verify this result, that would be helpful. This would mean
that it's not a win32ole issue but a Ruby problem that has recently been
fixed. Hopefully whatever the fix is makes it into 1.8.2.

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
S

Shashank Date

Jos Backus said:
Good I can no longer reproduce this using yesterday's CVS -HEAD. The
problem also seems to have disappeared when using this snapshot (in case you
can't easily build from source).

ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ruby-1.9.0-20040402-i386-mswin32.zip

Perhaps you can verify this result, that would be helpful. This would mean
that it's not a win32ole issue but a Ruby problem that has recently been
fixed. Hopefully whatever the fix is makes it into 1.8.2.

Good news indeed ! I will give that a try over the week-end.

I will request you to consider joining the Ruby Installer team. Your
experience in
trying to track down bugs and fix them on the Win32 platform is very
valuable and we
all will greatly benefit from it.
http://rubyforge.org/projects/rubyinstaller/

-- shanko
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top