Bug #14384
closedCompatibilityError is thrown when formatting a non-ASCII string with a binary string argument
Description
The following script:
# coding: utf-8
require 'socket'
begin
TCPSocket.open('nowhere', 80)
rescue => e
puts "証明書をリクエストできませんでした: %s" % e.message
end
Produces an error on Windows instead of printing message:
PS C:\work\puppet> ruby tcp.rb
tcp.rb:7:in `%': incompatible character encodings: UTF-8 and ASCII-8BIT (Encoding::CompatibilityError)
from tcp.rb:7:in `rescue in <main>'
from tcp.rb:4:in `<main>'
The SocketError's exception message is a binary string (ASCII_8BIT). The exception message comes from the rb_w32_strerror
method which uses FormatMessage
instead of FormatMessageW
.
The following works around the issue:
puts "証明書をリクエストできませんでした: %s".encode(Encoding.default_external) % e.message.force_encoding(Encoding.default_external)
The exception is not raised if the format string consists of ASCII only, e.g. puts "Connection failed: %s" % e.message
, however, the output is not formatted correctly:
PS C:\work\puppet> ruby tcp.rb
Connection failed: getaddrinfo: ���̂悤�ȃz�X�g�͕s���ł��B
Changing that to:
puts "Connection failed: %s" % e.message.force_encoding(Encoding.default_external)
Does correctly output the message:
PS C:\work\puppet> ruby tcp.rb
Connection failed: getaddrinfo: そのようなホストは不明です。
So the issue is a combination of the encoding of the format and argument strings.
My environment:
PS C:\work\puppet> gem env
RubyGems Environment:
- RUBYGEMS VERSION: 2.5.2
- RUBY VERSION: 2.3.3 (2016-11-21 patchlevel 222) [x64-mingw32]
- INSTALLATION DIRECTORY: C:/Ruby23-x64/lib/ruby/gems/2.3.0
- USER INSTALLATION DIRECTORY: C:/Users/Administrator/.gem/ruby/2.3.0
- RUBY EXECUTABLE: C:/Ruby23-x64/bin/ruby.exe
- EXECUTABLE DIRECTORY: C:/Ruby23-x64/bin
- SPEC CACHE DIRECTORY: C:/Users/Administrator/.gem/specs
- SYSTEM CONFIGURATION DIRECTORY: C:/ProgramData
- RUBYGEMS PLATFORMS:
- ruby
- x64-mingw32
- GEM PATHS:
- C:/Ruby23-x64/lib/ruby/gems/2.3.0
- C:/Users/Administrator/.gem/ruby/2.3.0
- GEM CONFIGURATION:
- :update_sources => true
- :verbose => true
- :backtrace => false
- :bulk_threshold => 1000
- REMOTE SOURCES:
- https://rubygems.org/
- SHELL PATH:
- C:\Ruby23-x64\bin
- C:\Windows\system32
- C:\Windows
- C:\Windows\System32\Wbem
- C:\Windows\System32\WindowsPowerShell\v1.0\
- C:\Program Files\Git\cmd
- C:\Packer\SysInternals
PS C:\work\puppet>
PS C:\work\puppet> ruby --version
ruby 2.3.3p222 (2016-11-21 revision 56859) [x64-mingw32]
PS C:\work\puppet> gem --version
2.5.2
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Status changed from Open to Closed
Applied in changeset trunk|r62017.
init.c: encode socket error message
- ext/socket/init.c (rsock_raise_socket_error): on Windows, encode
error messages from wide characters to the default encodings.
[ruby-core:84972] [Bug #14384]
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
The message does not come from rb_w32_strerror
but gai_strerror
in WinSock2 library.