[Win32utils-devel] win32-dir, unicode

Daniel Berger djberg96 at gmail.com
Mon May 29 00:22:36 EDT 2006


Heesob Park wrote:
> Hi,
> 
> 2006/5/28, Daniel Berger <djberg96 at gmail.com>:
>> Heesob Park wrote:
>>> Hi,
>>>
>>> 2006/5/28, Daniel Berger <djberg96 at gmail.com>:
>>>> Heesob Park wrote:
>>>>> Hi,
>>> <snip>
>>>> Thanks Heesob, but I'm getting some weird segfaults with wide character
>>>> functions and buffers over 245 characters.  I posted about this to
>>>> ruby-talk as well.  Here's some sample code that demonstrates the problem:
>>>>
>>>> require 'Win32API'
>>>>
>>>> GetFullPathNameW = Win32API.new('kernel32', 'GetFullPathNameW', 'PLPP', 'L')
>>>>
>>>> path = "C:\\test"
>>>> buf  = 0.chr * 260 # 245 or less works ok
>>>>
>>>> if GetFullPathNameW.call(path, buf.size, buf, 0) == 0
>>>>    puts "Failed"
>>>>    exit
>>>> end
>>>>
>>>> p buf.split("\0\0").first # BOOM!
>>>>
>>>> I'm not sure what the significance of 245 or less is.  I can inspect
>>>> 'buf', copy and paste it to a separate editor as a string and run ops on
>>>> it with no problem, so I'm very curious as to what's making Ruby segfault.
>>>>
>>> I'm very curious too.
>>>
>>> Your sample code don't segfault.
>>> But I came across segfaults several times in modifing create_junction method.
>>> It's behaviour is very unstable, as I insert p method,it sometimes runs OK.
>>> It's location was mainly split method or get_last_error method.
>>>
>>> I guess it's not related with 245 or 260, but it seems to underlying C
>>> pointer memory access failure problem.
>>> Can you give me a sample stable segfault generating code?
>> To add even more mystery to this problem, that code isn't segfaulting
>> for me at the moment, though it was regularly last night (I still have
>> the console window open that shows the segfaults to prove it to myself).
>>
>> I saw the same behavior you mentioned - inserting a 'puts' would
>> sometimes cause code that was previously segfaulting to suddenly work.
>>
>> Well, let's put the Unicode stuff on hold for now.  Perhaps deep
>> inspection of string.c some day will reveal what the potential problem is.
>>
> I have found out what is the problem.
> It's not bug of Ruby or Windows, it is only bug of code.
> 
> First try this:
> 
> require 'Win32API'
> GetFullPathNameW = Win32API.new('kernel32','GetFullPathNameW','PLPP', 'L')
> for i in 1..100
> path = "c:\\test"
> buf  = 0.chr * 260
> if GetFullPathNameW.call(path, buf.size, buf, 0) == 0
>     puts "Failed"
> end
> p buf.split("\0\0").first
> end
> 
> It will cause various errors like
> uninitialized constant GetFullPathNameW (NameError)
> or
> segfault.
> 
> Next, try this:
> 
> require 'Win32API'
> GetFullPathNameW = Win32API.new('kernel32','GetFullPathNameW','PLPP', 'L')
> for i in 1..100
> path = "c:\\test"
> buf  = 0.chr * 260
> # buf.size/2 -> actual length of buf
> if GetFullPathNameW.call(path, buf.size/2, buf, 0) == 0
>     puts "Failed"
> end
> p buf.split("\0\0").first
> end
> 
> It runs Ok. but the result is not correct.
> 
> Next , try this:
> 
> require 'Win32API'
> GetFullPathNameW = Win32API.new('kernel32','GetFullPathNameW','PLPP', 'L')
> for i in 1..100
> # append \0 to path
> path = "c:\\test\0"
> buf  = 0.chr * 260
> # buf.size/2 -> actual length of buf in unicode string
> if GetFullPathNameW.call(path, buf.size/2, buf, 0) == 0
>     puts "Failed"
> end
> p buf.split("\0\0").first
> end
> 
> It runs ok. The result is correct.
> 
> Finally, the complete and correct code is like this:
> 
> require 'Win32API'
> GetFullPathNameW = Win32API.new('kernel32','GetFullPathNameW','PLPP', 'L')
> for i in 1..100
> path = "c\0:\0\\\0t\0e\0s\0t\0\0"
> buf  = 0.chr * 260
> # buf.size/2 -> actual length of buf in unicode string
> if GetFullPathNameW.call(path, buf.size/2, buf, 0) == 0
>     puts "Failed"
> end
> buf = buf.split("\0\0").first
> buf = (buf.size % 2).zero? ? buf : buf+"\0"
> p buf
> end
> 
> Remeber, Ruby's string is terminated with "\0" implicitly, but UTF16
> string requires double "\0".
> For ascii chars, it happens trailing three "\0"  : one for ascii char
> and two for string termination.
> 
> Regards,
> 
> Park Heesob

While I understand why this code works, I'm still not entirely clear why 
the previous code would cause the interpreter to segfault.  Bad pointer 
address?

In any case, excellent work, thank you!

Now I'm trying to work out a general approach for the windows-pr stuff. 
   Given a method like this:

def GetFullPathName(file, buf, buf_size, part)
    if $KCODE != 'NONE'
       GetFullPathNameW.call(file, buf, buf_size, part)
    else
       GetFullPathName.call(file, buf, buf_size, part)
    end
end

Should I modify it to try to do a best-guess?

if $KCODE != 'NONE'
    GetFullPathNameW.call(file, buf, buf_size/2, part)
end

Or do you think that's the user's job?

Thanks,

Dan



More information about the win32utils-devel mailing list