From: Daniel Berger Date: 2006-05-29T12:12:57+09:00 Subject: Re: String segfault with wide character function, Windows Daniel Berger wrote: > Ruby 1.8.4 (one click) > Windows XP > > Check this out segfault: > > # strtest.rb > require 'Win32API' > > GetFullPathNameW = Win32API.new('kernel32','GetFullPathNameW','PLPP', 'L') > > path = "C:\\test" > buf = 0.chr * 260 > > if GetFullPathNameW.call(path, buf.size, buf, 0) == 0 > puts "Failed" > end > > #p buf > p buf.split("\0\0").first # boom! > > # Result > strtest.rb:13: [BUG] Segmentation fault > ruby 1.8.4 (2005-12-24) [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. > > I noticed that if I dropped the 'buf' to 245 or fewer characters, it > works ok. Also, it segfaults on just about any op that modifies buf, > not just String#split. > > Any ideas? > > Thanks, > > Dan > > The solution was found by Heesob, which I have pasted below (taken from the win32utils-devel mailing list): 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