openssl: avoid undefined behavior on empty SSL_write

SSL_write(3ssl) manpage has this in the WARNINGS section:

       When calling SSL_write() with num=0 bytes to be sent the
       behaviour is undefined.

And indeed, the new test case demonstrates failures when
empty strings are used.  So, match the behavior of IO#write,
IO#write_nonblock, and IO#syswrite by returning zero, as the
OpenSSL::SSL::SSLSocket API already closely mimics the IO one.

* ext/openssl/ossl_ssl.c (ossl_ssl_write_internal):
  avoid undefined behavior
* test/openssl/test_pair.rb (test_write_zero): new test
  [ruby-core:76751] [Bug #12660]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2016-08-06 21:50:10 +00:00
Родитель a62dcd947c
Коммит 7513d54659
3 изменённых файлов: 25 добавлений и 1 удалений

Просмотреть файл

@ -1,3 +1,10 @@
Sun Aug 7 06:48:21 2016 Eric Wong <e@80x24.org>
* ext/openssl/ossl_ssl.c (ossl_ssl_write_internal):
avoid undefined behavior
* test/openssl/test_pair.rb (test_write_zero): new test
[ruby-core:76751] [Bug #12660]
Sat Aug 6 09:35:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* id_table.h (rb_id_table_iterator_result): add dummy sentinel

Просмотреть файл

@ -1744,7 +1744,13 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)
if (ssl_started(ssl)) {
for (;;){
nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LENINT(str));
int num = RSTRING_LENINT(str);
/* SSL_write(3ssl) manpage states num == 0 is undefined */
if (num == 0)
goto end;
nwrite = SSL_write(ssl, RSTRING_PTR(str), num);
switch(ssl_get_error(ssl, nwrite)){
case SSL_ERROR_NONE:
goto end;

Просмотреть файл

@ -311,6 +311,17 @@ module OpenSSL::TestPairM
}
end
def test_write_zero
ssl_pair {|s1, s2|
assert_equal 0, s2.write_nonblock('', exception: false)
assert_kind_of Symbol, s1.read_nonblock(1, exception: false)
assert_equal 0, s2.syswrite('')
assert_kind_of Symbol, s1.read_nonblock(1, exception: false)
assert_equal 0, s2.write('')
assert_kind_of Symbol, s1.read_nonblock(1, exception: false)
}
end
def tcp_pair
host = "127.0.0.1"
serv = TCPServer.new(host, 0)