summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/-test-/RUBY_ALIGNOF/depend1
-rw-r--r--ext/-test-/abi/depend3
-rw-r--r--ext/-test-/arith_seq/beg_len_step/depend1
-rw-r--r--ext/-test-/arith_seq/extract/depend1
-rw-r--r--ext/-test-/array/concat/depend1
-rw-r--r--ext/-test-/array/resize/depend1
-rw-r--r--ext/-test-/asan/asan.c24
-rw-r--r--ext/-test-/asan/extconf.rb2
-rw-r--r--ext/-test-/bignum/depend19
-rw-r--r--ext/-test-/box/yay1/extconf.rb1
-rw-r--r--ext/-test-/box/yay1/yay1.c28
-rw-r--r--ext/-test-/box/yay1/yay1.def3
-rw-r--r--ext/-test-/box/yay1/yay1.h4
-rw-r--r--ext/-test-/box/yay2/extconf.rb1
-rw-r--r--ext/-test-/box/yay2/yay2.c28
-rw-r--r--ext/-test-/box/yay2/yay2.def3
-rw-r--r--ext/-test-/box/yay2/yay2.h4
-rw-r--r--ext/-test-/bug-14834/depend1
-rw-r--r--ext/-test-/bug-3571/depend1
-rw-r--r--ext/-test-/bug-5832/depend1
-rw-r--r--ext/-test-/bug_reporter/depend1
-rw-r--r--ext/-test-/class/depend2
-rw-r--r--ext/-test-/cxxanyargs/cxxanyargs.cpp26
-rw-r--r--ext/-test-/debug/depend3
-rw-r--r--ext/-test-/dln/empty/depend1
-rw-r--r--ext/-test-/econv/depend336
-rw-r--r--ext/-test-/ensure_and_callcc/depend163
-rw-r--r--ext/-test-/enumerator_kw/depend1
-rw-r--r--ext/-test-/eval/depend162
-rw-r--r--ext/-test-/exception/depend4
-rw-r--r--ext/-test-/fatal/depend3
-rw-r--r--ext/-test-/fatal/invalid.c6
-rw-r--r--ext/-test-/file/depend4
-rw-r--r--ext/-test-/float/depend2
-rw-r--r--ext/-test-/funcall/depend1
-rw-r--r--ext/-test-/gvl/call_without_gvl/depend1
-rw-r--r--ext/-test-/hash/depend2
-rw-r--r--ext/-test-/integer/depend3
-rw-r--r--ext/-test-/iseq_load/depend1
-rw-r--r--ext/-test-/iter/depend3
-rw-r--r--ext/-test-/load/dot.dot/depend1
-rw-r--r--ext/-test-/load/protect/depend1
-rw-r--r--ext/-test-/load/resolve_symbol_resolver/depend163
-rw-r--r--ext/-test-/load/resolve_symbol_target/depend164
-rw-r--r--ext/-test-/load/stringify_symbols/depend164
-rw-r--r--ext/-test-/load/stringify_target/depend164
-rw-r--r--ext/-test-/marshal/compat/depend1
-rw-r--r--ext/-test-/marshal/internal_ivar/depend1
-rw-r--r--ext/-test-/marshal/usr/depend1
-rw-r--r--ext/-test-/memory_view/depend1
-rw-r--r--ext/-test-/method/depend2
-rw-r--r--ext/-test-/notimplement/depend1
-rw-r--r--ext/-test-/num2int/depend1
-rw-r--r--ext/-test-/path_to_class/depend1
-rw-r--r--ext/-test-/popen_deadlock/depend1
-rw-r--r--ext/-test-/postponed_job/depend1
-rw-r--r--ext/-test-/printf/depend1
-rw-r--r--ext/-test-/proc/depend3
-rw-r--r--ext/-test-/random/depend3
-rw-r--r--ext/-test-/rational/depend1
-rw-r--r--ext/-test-/rb_call_super_kw/depend1
-rw-r--r--ext/-test-/recursion/depend1
-rw-r--r--ext/-test-/regexp/depend2
-rw-r--r--ext/-test-/sanitizers/depend162
-rw-r--r--ext/-test-/sanitizers/extconf.rb2
-rw-r--r--ext/-test-/sanitizers/sanitizers.c36
-rw-r--r--ext/-test-/scan_args/depend1
-rw-r--r--ext/-test-/scheduler/extconf.rb2
-rw-r--r--ext/-test-/scheduler/scheduler.c92
-rw-r--r--ext/-test-/st/foreach/depend1
-rw-r--r--ext/-test-/st/numhash/depend1
-rw-r--r--ext/-test-/st/update/depend1
-rw-r--r--ext/-test-/stack/depend179
-rw-r--r--ext/-test-/stack/stack.c4
-rw-r--r--ext/-test-/string/depend20
-rw-r--r--ext/-test-/string/fstring.c6
-rw-r--r--ext/-test-/struct/depend5
-rw-r--r--ext/-test-/symbol/depend2
-rw-r--r--ext/-test-/thread/id/depend163
-rw-r--r--ext/-test-/thread/instrumentation/depend1
-rw-r--r--ext/-test-/thread/lock_native_thread/depend163
-rw-r--r--ext/-test-/thread_fd/depend161
-rw-r--r--ext/-test-/thread_fd/extconf.rb2
-rw-r--r--ext/-test-/thread_fd/thread_fd.c30
-rw-r--r--ext/-test-/time/depend3
-rw-r--r--ext/-test-/time/leap_second.c15
-rw-r--r--ext/-test-/tracepoint/depend2
-rw-r--r--ext/-test-/tracepoint/gc_hook.c26
-rw-r--r--ext/-test-/tracepoint/tracepoint.c10
-rw-r--r--ext/-test-/typeddata/depend1
-rw-r--r--ext/-test-/vm/depend1
-rw-r--r--ext/-test-/wait/depend1
-rw-r--r--ext/.document3
-rw-r--r--ext/cgi/escape/depend1
-rw-r--r--ext/cgi/escape/escape.c30
-rw-r--r--ext/continuation/depend1
-rw-r--r--ext/coverage/coverage.c99
-rw-r--r--ext/coverage/depend3
-rw-r--r--ext/coverage/lib/coverage.rb5
-rw-r--r--ext/date/date_core.c436
-rw-r--r--ext/date/depend4
-rw-r--r--ext/date/lib/date.rb2
-rw-r--r--ext/digest/bubblebabble/depend1
-rw-r--r--ext/digest/defs.h22
-rw-r--r--ext/digest/depend1
-rw-r--r--ext/digest/digest_conf.rb18
-rw-r--r--ext/digest/lib/digest/version.rb3
-rw-r--r--ext/digest/md5/depend2
-rw-r--r--ext/digest/md5/md5cc.h8
-rw-r--r--ext/digest/md5/md5init.c1
-rw-r--r--ext/digest/rmd160/depend2
-rw-r--r--ext/digest/sha1/depend2
-rw-r--r--ext/digest/sha1/sha1.c8
-rw-r--r--ext/digest/sha2/depend2
-rw-r--r--ext/erb/escape/escape.c41
-rw-r--r--ext/erb/escape/extconf.rb1
-rw-r--r--ext/etc/depend1
-rw-r--r--ext/etc/etc.c6
-rw-r--r--ext/etc/etc.gemspec2
-rw-r--r--ext/etc/extconf.rb2
-rwxr-xr-xext/extmk.rb11
-rw-r--r--ext/fcntl/depend1
-rw-r--r--ext/fcntl/fcntl.c48
-rw-r--r--ext/io/console/console.c87
-rw-r--r--ext/io/console/depend1
-rw-r--r--ext/io/console/extconf.rb10
-rw-r--r--ext/io/nonblock/depend1
-rw-r--r--ext/io/nonblock/extconf.rb2
-rw-r--r--ext/io/nonblock/io-nonblock.gemspec4
-rw-r--r--ext/io/wait/depend2
-rw-r--r--ext/io/wait/extconf.rb23
-rw-r--r--ext/io/wait/io-wait.gemspec23
-rw-r--r--ext/io/wait/wait.c418
-rw-r--r--ext/json/fbuffer/fbuffer.h103
-rw-r--r--ext/json/generator/depend3
-rw-r--r--ext/json/generator/extconf.rb6
-rw-r--r--ext/json/generator/generator.c1002
-rw-r--r--ext/json/json.gemspec5
-rw-r--r--ext/json/json.h101
-rw-r--r--ext/json/lib/json.rb76
-rw-r--r--ext/json/lib/json/add/core.rb1
-rw-r--r--ext/json/lib/json/add/string.rb35
-rw-r--r--ext/json/lib/json/common.rb196
-rw-r--r--ext/json/lib/json/ext.rb4
-rw-r--r--ext/json/lib/json/ext/generator/state.rb25
-rw-r--r--ext/json/lib/json/generic_object.rb8
-rw-r--r--ext/json/lib/json/version.rb2
-rw-r--r--ext/json/parser/depend4
-rw-r--r--ext/json/parser/extconf.rb9
-rw-r--r--ext/json/parser/parser.c1319
-rw-r--r--ext/json/simd/conf.rb24
-rw-r--r--ext/json/simd/simd.h218
-rw-r--r--ext/json/vendor/fpconv.c39
-rw-r--r--ext/json/vendor/ryu.h819
-rw-r--r--ext/monitor/depend1
-rw-r--r--ext/monitor/monitor.c130
-rw-r--r--ext/objspace/depend13
-rw-r--r--ext/objspace/object_tracing.c9
-rw-r--r--ext/objspace/objspace.c168
-rw-r--r--ext/objspace/objspace_dump.c134
-rw-r--r--ext/openssl/History.md136
-rw-r--r--ext/openssl/depend33
-rw-r--r--ext/openssl/extconf.rb21
-rw-r--r--ext/openssl/lib/openssl.rb15
-rw-r--r--ext/openssl/lib/openssl/asn1.rb188
-rw-r--r--ext/openssl/lib/openssl/digest.rb2
-rw-r--r--ext/openssl/lib/openssl/pkey.rb84
-rw-r--r--ext/openssl/lib/openssl/ssl.rb49
-rw-r--r--ext/openssl/lib/openssl/version.rb3
-rw-r--r--ext/openssl/lib/openssl/x509.rb9
-rw-r--r--ext/openssl/openssl.gemspec5
-rw-r--r--ext/openssl/ossl.c457
-rw-r--r--ext/openssl/ossl.h25
-rw-r--r--ext/openssl/ossl_asn1.c1004
-rw-r--r--ext/openssl/ossl_asn1.h16
-rw-r--r--ext/openssl/ossl_bio.c6
-rw-r--r--ext/openssl/ossl_bn.c576
-rw-r--r--ext/openssl/ossl_cipher.c465
-rw-r--r--ext/openssl/ossl_cipher.h11
-rw-r--r--ext/openssl/ossl_config.c7
-rw-r--r--ext/openssl/ossl_digest.c116
-rw-r--r--ext/openssl/ossl_digest.h10
-rw-r--r--ext/openssl/ossl_engine.c83
-rw-r--r--ext/openssl/ossl_hmac.c57
-rw-r--r--ext/openssl/ossl_kdf.c87
-rw-r--r--ext/openssl/ossl_ns_spki.c68
-rw-r--r--ext/openssl/ossl_ocsp.c450
-rw-r--r--ext/openssl/ossl_pkcs12.c39
-rw-r--r--ext/openssl/ossl_pkcs7.c273
-rw-r--r--ext/openssl/ossl_pkey.c276
-rw-r--r--ext/openssl/ossl_pkey.h198
-rw-r--r--ext/openssl/ossl_pkey_dh.c67
-rw-r--r--ext/openssl/ossl_pkey_dsa.c37
-rw-r--r--ext/openssl/ossl_pkey_ec.c336
-rw-r--r--ext/openssl/ossl_pkey_rsa.c120
-rw-r--r--ext/openssl/ossl_provider.c7
-rw-r--r--ext/openssl/ossl_rand.c19
-rw-r--r--ext/openssl/ossl_ssl.c663
-rw-r--r--ext/openssl/ossl_ssl.h16
-rw-r--r--ext/openssl/ossl_ssl_session.c189
-rw-r--r--ext/openssl/ossl_ts.c171
-rw-r--r--ext/openssl/ossl_x509.c7
-rw-r--r--ext/openssl/ossl_x509attr.c86
-rw-r--r--ext/openssl/ossl_x509cert.c157
-rw-r--r--ext/openssl/ossl_x509crl.c140
-rw-r--r--ext/openssl/ossl_x509ext.c106
-rw-r--r--ext/openssl/ossl_x509name.c144
-rw-r--r--ext/openssl/ossl_x509req.c114
-rw-r--r--ext/openssl/ossl_x509revoked.c61
-rw-r--r--ext/openssl/ossl_x509store.c77
-rw-r--r--ext/pathname/depend174
-rw-r--r--ext/pathname/extconf.rb3
-rw-r--r--ext/pathname/lib/pathname.rb621
-rw-r--r--ext/pathname/pathname.c1668
-rw-r--r--ext/pathname/pathname.gemspec32
-rw-r--r--ext/psych/depend5
-rw-r--r--ext/psych/extconf.rb7
-rw-r--r--ext/psych/lib/psych.rb45
-rw-r--r--ext/psych/lib/psych/class_loader.rb1
-rw-r--r--ext/psych/lib/psych/core_ext.rb21
-rw-r--r--ext/psych/lib/psych/nodes/node.rb4
-rw-r--r--ext/psych/lib/psych/scalar_scanner.rb5
-rw-r--r--ext/psych/lib/psych/versions.rb4
-rw-r--r--ext/psych/lib/psych/visitors/to_ruby.rb54
-rw-r--r--ext/psych/lib/psych/visitors/yaml_tree.rb40
-rw-r--r--ext/psych/psych_to_ruby.c4
-rw-r--r--ext/pty/depend2
-rw-r--r--ext/rbconfig/sizeof/depend2
-rw-r--r--ext/ripper/depend8
-rw-r--r--ext/ripper/lib/ripper/lexer.rb2
-rw-r--r--ext/socket/depend75
-rw-r--r--ext/socket/extconf.rb1
-rw-r--r--ext/socket/getaddrinfo.c7
-rw-r--r--ext/socket/getnameinfo.c18
-rw-r--r--ext/socket/init.c9
-rw-r--r--ext/socket/ipsocket.c189
-rw-r--r--ext/socket/lib/socket.rb93
-rw-r--r--ext/socket/raddrinfo.c175
-rw-r--r--ext/socket/rubysocket.h14
-rw-r--r--ext/socket/socket.c8
-rw-r--r--ext/socket/sockssocket.c5
-rw-r--r--ext/socket/tcpserver.c2
-rw-r--r--ext/socket/tcpsocket.c26
-rw-r--r--ext/socket/udpsocket.c6
-rw-r--r--ext/socket/unixsocket.c3
-rw-r--r--ext/stringio/depend2
-rw-r--r--ext/stringio/stringio.c303
-rw-r--r--ext/strscan/depend1
-rw-r--r--ext/strscan/extconf.rb5
-rw-r--r--ext/strscan/strscan.c138
-rw-r--r--ext/win32/lib/win32/registry.rb253
-rw-r--r--ext/win32/lib/win32/resolv.rb132
-rw-r--r--ext/win32/resolv/extconf.rb3
-rw-r--r--ext/win32/resolv/resolv.c213
-rw-r--r--ext/win32/win32-registry.gemspec11
-rw-r--r--ext/zlib/depend1
-rw-r--r--ext/zlib/zlib.c31
257 files changed, 11393 insertions, 8737 deletions
diff --git a/ext/-test-/RUBY_ALIGNOF/depend b/ext/-test-/RUBY_ALIGNOF/depend
index 25364e55fb..103d20b33c 100644
--- a/ext/-test-/RUBY_ALIGNOF/depend
+++ b/ext/-test-/RUBY_ALIGNOF/depend
@@ -128,6 +128,7 @@ c.o: $(hdrdir)/ruby/internal/intern/re.h
c.o: $(hdrdir)/ruby/internal/intern/ruby.h
c.o: $(hdrdir)/ruby/internal/intern/select.h
c.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+c.o: $(hdrdir)/ruby/internal/intern/set.h
c.o: $(hdrdir)/ruby/internal/intern/signal.h
c.o: $(hdrdir)/ruby/internal/intern/sprintf.h
c.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/abi/depend b/ext/-test-/abi/depend
new file mode 100644
index 0000000000..716a7b1356
--- /dev/null
+++ b/ext/-test-/abi/depend
@@ -0,0 +1,3 @@
+# AUTOGENERATED DEPENDENCIES START
+abi.o: abi.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/arith_seq/beg_len_step/depend b/ext/-test-/arith_seq/beg_len_step/depend
index 702a0037a8..098c8ff1f0 100644
--- a/ext/-test-/arith_seq/beg_len_step/depend
+++ b/ext/-test-/arith_seq/beg_len_step/depend
@@ -127,6 +127,7 @@ beg_len_step.o: $(hdrdir)/ruby/internal/intern/re.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/ruby.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/select.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+beg_len_step.o: $(hdrdir)/ruby/internal/intern/set.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/signal.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/sprintf.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/arith_seq/extract/depend b/ext/-test-/arith_seq/extract/depend
index fdbd71dfbc..5c07cea4b4 100644
--- a/ext/-test-/arith_seq/extract/depend
+++ b/ext/-test-/arith_seq/extract/depend
@@ -127,6 +127,7 @@ extract.o: $(hdrdir)/ruby/internal/intern/re.h
extract.o: $(hdrdir)/ruby/internal/intern/ruby.h
extract.o: $(hdrdir)/ruby/internal/intern/select.h
extract.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+extract.o: $(hdrdir)/ruby/internal/intern/set.h
extract.o: $(hdrdir)/ruby/internal/intern/signal.h
extract.o: $(hdrdir)/ruby/internal/intern/sprintf.h
extract.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/array/concat/depend b/ext/-test-/array/concat/depend
index f2213a42ea..8edf45465f 100644
--- a/ext/-test-/array/concat/depend
+++ b/ext/-test-/array/concat/depend
@@ -128,6 +128,7 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/intern/re.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/ruby.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/select.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+to_ary_concat.o: $(hdrdir)/ruby/internal/intern/set.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/signal.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/array/resize/depend b/ext/-test-/array/resize/depend
index f88a9d03c1..e6a228b43d 100644
--- a/ext/-test-/array/resize/depend
+++ b/ext/-test-/array/resize/depend
@@ -127,6 +127,7 @@ resize.o: $(hdrdir)/ruby/internal/intern/re.h
resize.o: $(hdrdir)/ruby/internal/intern/ruby.h
resize.o: $(hdrdir)/ruby/internal/intern/select.h
resize.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+resize.o: $(hdrdir)/ruby/internal/intern/set.h
resize.o: $(hdrdir)/ruby/internal/intern/signal.h
resize.o: $(hdrdir)/ruby/internal/intern/sprintf.h
resize.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/asan/asan.c b/ext/-test-/asan/asan.c
deleted file mode 100644
index 45b6253fda..0000000000
--- a/ext/-test-/asan/asan.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "ruby/ruby.h"
-
-static VALUE
-asan_enabled_p(VALUE self)
-{
-#if defined(__has_feature)
- /* clang uses __has_feature for determining asan */
- return __has_feature(address_sanitizer) ? Qtrue : Qfalse;
-#elif defined(__SANITIZE_ADDRESS__)
- /* GCC sets __SANITIZE_ADDRESS__ for determining asan */
- return Qtrue;
-#else
- return Qfalse;
-#endif
-}
-
-void
-Init_asan(void)
-{
- VALUE m = rb_define_module("Test");
- VALUE c = rb_define_class_under(m, "ASAN", rb_cObject);
- rb_define_singleton_method(c, "enabled?", asan_enabled_p, 0);
-}
-
diff --git a/ext/-test-/asan/extconf.rb b/ext/-test-/asan/extconf.rb
deleted file mode 100644
index ec02742b81..0000000000
--- a/ext/-test-/asan/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'mkmf'
-create_makefile('-test-/asan')
diff --git a/ext/-test-/bignum/depend b/ext/-test-/bignum/depend
index 078915ab72..82972f1032 100644
--- a/ext/-test-/bignum/depend
+++ b/ext/-test-/bignum/depend
@@ -6,6 +6,7 @@ big2str.o: $(hdrdir)/ruby/backward.h
big2str.o: $(hdrdir)/ruby/backward/2/assume.h
big2str.o: $(hdrdir)/ruby/backward/2/attributes.h
big2str.o: $(hdrdir)/ruby/backward/2/bool.h
+big2str.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
big2str.o: $(hdrdir)/ruby/backward/2/inttypes.h
big2str.o: $(hdrdir)/ruby/backward/2/limits.h
big2str.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -127,6 +128,7 @@ big2str.o: $(hdrdir)/ruby/internal/intern/re.h
big2str.o: $(hdrdir)/ruby/internal/intern/ruby.h
big2str.o: $(hdrdir)/ruby/internal/intern/select.h
big2str.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+big2str.o: $(hdrdir)/ruby/internal/intern/set.h
big2str.o: $(hdrdir)/ruby/internal/intern/signal.h
big2str.o: $(hdrdir)/ruby/internal/intern/sprintf.h
big2str.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -158,6 +160,7 @@ big2str.o: $(hdrdir)/ruby/ruby.h
big2str.o: $(hdrdir)/ruby/st.h
big2str.o: $(hdrdir)/ruby/subst.h
big2str.o: $(top_srcdir)/internal/bignum.h
+big2str.o: $(top_srcdir)/internal/compilers.h
big2str.o: big2str.c
bigzero.o: $(RUBY_EXTCONF_H)
bigzero.o: $(arch_hdrdir)/ruby/config.h
@@ -166,6 +169,7 @@ bigzero.o: $(hdrdir)/ruby/backward.h
bigzero.o: $(hdrdir)/ruby/backward/2/assume.h
bigzero.o: $(hdrdir)/ruby/backward/2/attributes.h
bigzero.o: $(hdrdir)/ruby/backward/2/bool.h
+bigzero.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
bigzero.o: $(hdrdir)/ruby/backward/2/inttypes.h
bigzero.o: $(hdrdir)/ruby/backward/2/limits.h
bigzero.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -287,6 +291,7 @@ bigzero.o: $(hdrdir)/ruby/internal/intern/re.h
bigzero.o: $(hdrdir)/ruby/internal/intern/ruby.h
bigzero.o: $(hdrdir)/ruby/internal/intern/select.h
bigzero.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bigzero.o: $(hdrdir)/ruby/internal/intern/set.h
bigzero.o: $(hdrdir)/ruby/internal/intern/signal.h
bigzero.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bigzero.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -318,6 +323,7 @@ bigzero.o: $(hdrdir)/ruby/ruby.h
bigzero.o: $(hdrdir)/ruby/st.h
bigzero.o: $(hdrdir)/ruby/subst.h
bigzero.o: $(top_srcdir)/internal/bignum.h
+bigzero.o: $(top_srcdir)/internal/compilers.h
bigzero.o: bigzero.c
div.o: $(RUBY_EXTCONF_H)
div.o: $(arch_hdrdir)/ruby/config.h
@@ -326,6 +332,7 @@ div.o: $(hdrdir)/ruby/backward.h
div.o: $(hdrdir)/ruby/backward/2/assume.h
div.o: $(hdrdir)/ruby/backward/2/attributes.h
div.o: $(hdrdir)/ruby/backward/2/bool.h
+div.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
div.o: $(hdrdir)/ruby/backward/2/inttypes.h
div.o: $(hdrdir)/ruby/backward/2/limits.h
div.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -447,6 +454,7 @@ div.o: $(hdrdir)/ruby/internal/intern/re.h
div.o: $(hdrdir)/ruby/internal/intern/ruby.h
div.o: $(hdrdir)/ruby/internal/intern/select.h
div.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+div.o: $(hdrdir)/ruby/internal/intern/set.h
div.o: $(hdrdir)/ruby/internal/intern/signal.h
div.o: $(hdrdir)/ruby/internal/intern/sprintf.h
div.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -478,6 +486,7 @@ div.o: $(hdrdir)/ruby/ruby.h
div.o: $(hdrdir)/ruby/st.h
div.o: $(hdrdir)/ruby/subst.h
div.o: $(top_srcdir)/internal/bignum.h
+div.o: $(top_srcdir)/internal/compilers.h
div.o: div.c
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
@@ -608,6 +617,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -646,6 +656,7 @@ intpack.o: $(hdrdir)/ruby/backward.h
intpack.o: $(hdrdir)/ruby/backward/2/assume.h
intpack.o: $(hdrdir)/ruby/backward/2/attributes.h
intpack.o: $(hdrdir)/ruby/backward/2/bool.h
+intpack.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
intpack.o: $(hdrdir)/ruby/backward/2/inttypes.h
intpack.o: $(hdrdir)/ruby/backward/2/limits.h
intpack.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -767,6 +778,7 @@ intpack.o: $(hdrdir)/ruby/internal/intern/re.h
intpack.o: $(hdrdir)/ruby/internal/intern/ruby.h
intpack.o: $(hdrdir)/ruby/internal/intern/select.h
intpack.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+intpack.o: $(hdrdir)/ruby/internal/intern/set.h
intpack.o: $(hdrdir)/ruby/internal/intern/signal.h
intpack.o: $(hdrdir)/ruby/internal/intern/sprintf.h
intpack.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -798,6 +810,7 @@ intpack.o: $(hdrdir)/ruby/ruby.h
intpack.o: $(hdrdir)/ruby/st.h
intpack.o: $(hdrdir)/ruby/subst.h
intpack.o: $(top_srcdir)/internal/bignum.h
+intpack.o: $(top_srcdir)/internal/compilers.h
intpack.o: intpack.c
mul.o: $(RUBY_EXTCONF_H)
mul.o: $(arch_hdrdir)/ruby/config.h
@@ -806,6 +819,7 @@ mul.o: $(hdrdir)/ruby/backward.h
mul.o: $(hdrdir)/ruby/backward/2/assume.h
mul.o: $(hdrdir)/ruby/backward/2/attributes.h
mul.o: $(hdrdir)/ruby/backward/2/bool.h
+mul.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
mul.o: $(hdrdir)/ruby/backward/2/inttypes.h
mul.o: $(hdrdir)/ruby/backward/2/limits.h
mul.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -927,6 +941,7 @@ mul.o: $(hdrdir)/ruby/internal/intern/re.h
mul.o: $(hdrdir)/ruby/internal/intern/ruby.h
mul.o: $(hdrdir)/ruby/internal/intern/select.h
mul.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+mul.o: $(hdrdir)/ruby/internal/intern/set.h
mul.o: $(hdrdir)/ruby/internal/intern/signal.h
mul.o: $(hdrdir)/ruby/internal/intern/sprintf.h
mul.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -958,6 +973,7 @@ mul.o: $(hdrdir)/ruby/ruby.h
mul.o: $(hdrdir)/ruby/st.h
mul.o: $(hdrdir)/ruby/subst.h
mul.o: $(top_srcdir)/internal/bignum.h
+mul.o: $(top_srcdir)/internal/compilers.h
mul.o: mul.c
str2big.o: $(RUBY_EXTCONF_H)
str2big.o: $(arch_hdrdir)/ruby/config.h
@@ -966,6 +982,7 @@ str2big.o: $(hdrdir)/ruby/backward.h
str2big.o: $(hdrdir)/ruby/backward/2/assume.h
str2big.o: $(hdrdir)/ruby/backward/2/attributes.h
str2big.o: $(hdrdir)/ruby/backward/2/bool.h
+str2big.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
str2big.o: $(hdrdir)/ruby/backward/2/inttypes.h
str2big.o: $(hdrdir)/ruby/backward/2/limits.h
str2big.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -1087,6 +1104,7 @@ str2big.o: $(hdrdir)/ruby/internal/intern/re.h
str2big.o: $(hdrdir)/ruby/internal/intern/ruby.h
str2big.o: $(hdrdir)/ruby/internal/intern/select.h
str2big.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+str2big.o: $(hdrdir)/ruby/internal/intern/set.h
str2big.o: $(hdrdir)/ruby/internal/intern/signal.h
str2big.o: $(hdrdir)/ruby/internal/intern/sprintf.h
str2big.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1118,5 +1136,6 @@ str2big.o: $(hdrdir)/ruby/ruby.h
str2big.o: $(hdrdir)/ruby/st.h
str2big.o: $(hdrdir)/ruby/subst.h
str2big.o: $(top_srcdir)/internal/bignum.h
+str2big.o: $(top_srcdir)/internal/compilers.h
str2big.o: str2big.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/box/yay1/extconf.rb b/ext/-test-/box/yay1/extconf.rb
new file mode 100644
index 0000000000..54387cedf1
--- /dev/null
+++ b/ext/-test-/box/yay1/extconf.rb
@@ -0,0 +1 @@
+create_makefile('-test-/box/yay1')
diff --git a/ext/-test-/box/yay1/yay1.c b/ext/-test-/box/yay1/yay1.c
new file mode 100644
index 0000000000..564a221c8c
--- /dev/null
+++ b/ext/-test-/box/yay1/yay1.c
@@ -0,0 +1,28 @@
+#include "yay1.h"
+
+VALUE
+yay_value(void)
+{
+ return rb_str_new_cstr("yay");
+}
+
+static VALUE
+yay1_f_version(VALUE klass)
+{
+ return rb_str_new_cstr("1.0.0");
+}
+
+static VALUE
+yay1_yay(VALUE klass)
+{
+ return yay_value();
+}
+
+void
+Init_yay1(void)
+{
+ VALUE mod = rb_define_module("Yay");
+ rb_define_const(mod, "VERSION", rb_str_new_cstr("1.0.0"));
+ rb_define_singleton_method(mod, "version", yay1_f_version, 0);
+ rb_define_singleton_method(mod, "yay", yay1_yay, 0);
+}
diff --git a/ext/-test-/box/yay1/yay1.def b/ext/-test-/box/yay1/yay1.def
new file mode 100644
index 0000000000..510fbe7017
--- /dev/null
+++ b/ext/-test-/box/yay1/yay1.def
@@ -0,0 +1,3 @@
+EXPORTS
+ Init_yay1
+ yay_value
diff --git a/ext/-test-/box/yay1/yay1.h b/ext/-test-/box/yay1/yay1.h
new file mode 100644
index 0000000000..c4dade928a
--- /dev/null
+++ b/ext/-test-/box/yay1/yay1.h
@@ -0,0 +1,4 @@
+#include <ruby.h>
+#include "ruby/internal/dllexport.h"
+
+RUBY_FUNC_EXPORTED VALUE yay_value(void);
diff --git a/ext/-test-/box/yay2/extconf.rb b/ext/-test-/box/yay2/extconf.rb
new file mode 100644
index 0000000000..850ef3edc9
--- /dev/null
+++ b/ext/-test-/box/yay2/extconf.rb
@@ -0,0 +1 @@
+create_makefile('-test-/box/yay2')
diff --git a/ext/-test-/box/yay2/yay2.c b/ext/-test-/box/yay2/yay2.c
new file mode 100644
index 0000000000..b632ae8495
--- /dev/null
+++ b/ext/-test-/box/yay2/yay2.c
@@ -0,0 +1,28 @@
+#include "yay2.h"
+
+VALUE
+yay_value(void)
+{
+ return rb_str_new_cstr("yaaay");
+}
+
+static VALUE
+yay2_f_version(VALUE klass)
+{
+ return rb_str_new_cstr("2.0.0");
+}
+
+static VALUE
+yay2_yay(VALUE klass)
+{
+ return yay_value();
+}
+
+void
+Init_yay2(void)
+{
+ VALUE mod = rb_define_module("Yay");
+ rb_define_const(mod, "VERSION", rb_str_new_cstr("2.0.0"));
+ rb_define_singleton_method(mod, "version", yay2_f_version, 0);
+ rb_define_singleton_method(mod, "yay", yay2_yay, 0);
+}
diff --git a/ext/-test-/box/yay2/yay2.def b/ext/-test-/box/yay2/yay2.def
new file mode 100644
index 0000000000..163fc44c04
--- /dev/null
+++ b/ext/-test-/box/yay2/yay2.def
@@ -0,0 +1,3 @@
+EXPORTS
+ Init_yay2
+ yay_value
diff --git a/ext/-test-/box/yay2/yay2.h b/ext/-test-/box/yay2/yay2.h
new file mode 100644
index 0000000000..c4dade928a
--- /dev/null
+++ b/ext/-test-/box/yay2/yay2.h
@@ -0,0 +1,4 @@
+#include <ruby.h>
+#include "ruby/internal/dllexport.h"
+
+RUBY_FUNC_EXPORTED VALUE yay_value(void);
diff --git a/ext/-test-/bug-14834/depend b/ext/-test-/bug-14834/depend
index 38429918b1..f83939d559 100644
--- a/ext/-test-/bug-14834/depend
+++ b/ext/-test-/bug-14834/depend
@@ -128,6 +128,7 @@ bug-14834.o: $(hdrdir)/ruby/internal/intern/re.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/select.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug-14834.o: $(hdrdir)/ruby/internal/intern/set.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/signal.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug-14834.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/bug-3571/depend b/ext/-test-/bug-3571/depend
index 84517a9c15..69c970b6f2 100644
--- a/ext/-test-/bug-3571/depend
+++ b/ext/-test-/bug-3571/depend
@@ -128,6 +128,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/re.h
bug.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug.o: $(hdrdir)/ruby/internal/intern/select.h
bug.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug.o: $(hdrdir)/ruby/internal/intern/set.h
bug.o: $(hdrdir)/ruby/internal/intern/signal.h
bug.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/bug-5832/depend b/ext/-test-/bug-5832/depend
index 84517a9c15..69c970b6f2 100644
--- a/ext/-test-/bug-5832/depend
+++ b/ext/-test-/bug-5832/depend
@@ -128,6 +128,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/re.h
bug.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug.o: $(hdrdir)/ruby/internal/intern/select.h
bug.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug.o: $(hdrdir)/ruby/internal/intern/set.h
bug.o: $(hdrdir)/ruby/internal/intern/signal.h
bug.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/bug_reporter/depend b/ext/-test-/bug_reporter/depend
index 1c73234247..e9993c3295 100644
--- a/ext/-test-/bug_reporter/depend
+++ b/ext/-test-/bug_reporter/depend
@@ -128,6 +128,7 @@ bug_reporter.o: $(hdrdir)/ruby/internal/intern/re.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/select.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug_reporter.o: $(hdrdir)/ruby/internal/intern/set.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/signal.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/class/depend b/ext/-test-/class/depend
index b0595fdc46..557206cefb 100644
--- a/ext/-test-/class/depend
+++ b/ext/-test-/class/depend
@@ -127,6 +127,7 @@ class2name.o: $(hdrdir)/ruby/internal/intern/re.h
class2name.o: $(hdrdir)/ruby/internal/intern/ruby.h
class2name.o: $(hdrdir)/ruby/internal/intern/select.h
class2name.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+class2name.o: $(hdrdir)/ruby/internal/intern/set.h
class2name.o: $(hdrdir)/ruby/internal/intern/signal.h
class2name.o: $(hdrdir)/ruby/internal/intern/sprintf.h
class2name.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -287,6 +288,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/cxxanyargs/cxxanyargs.cpp b/ext/-test-/cxxanyargs/cxxanyargs.cpp
index eded13e2ee..c7df7f9038 100644
--- a/ext/-test-/cxxanyargs/cxxanyargs.cpp
+++ b/ext/-test-/cxxanyargs/cxxanyargs.cpp
@@ -97,31 +97,6 @@ struct test_rb_define_hooked_variable {
};
VALUE test_rb_define_hooked_variable::v = Qundef;
-namespace test_rb_iterate {
- VALUE
- iter(VALUE self)
- {
- return rb_funcall(self, rb_intern("yield"), 0);
- }
-
- VALUE
- block(RB_BLOCK_CALL_FUNC_ARGLIST(arg, param))
- {
- return rb_funcall(arg, rb_intern("=="), 1, param);
- }
-
- VALUE
- test(VALUE self)
- {
-#ifdef HAVE_NULLPTR
- rb_iterate(iter, self, nullptr, self);
-#endif
-
- rb_iterate(iter, self, RUBY_METHOD_FUNC(block), self); // old
- return rb_iterate(iter, self, block, self); // new
- }
-}
-
namespace test_rb_block_call {
VALUE
block(RB_BLOCK_CALL_FUNC_ARGLIST(arg, param))
@@ -936,7 +911,6 @@ Init_cxxanyargs(void)
test(rb_define_virtual_variable);
test(rb_define_hooked_variable);
- test(rb_iterate);
test(rb_block_call);
test(rb_rescue);
test(rb_rescue2);
diff --git a/ext/-test-/debug/depend b/ext/-test-/debug/depend
index 67e32c6aa6..4ae0378ef2 100644
--- a/ext/-test-/debug/depend
+++ b/ext/-test-/debug/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ inspector.o: $(hdrdir)/ruby/internal/intern/re.h
inspector.o: $(hdrdir)/ruby/internal/intern/ruby.h
inspector.o: $(hdrdir)/ruby/internal/intern/select.h
inspector.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+inspector.o: $(hdrdir)/ruby/internal/intern/set.h
inspector.o: $(hdrdir)/ruby/internal/intern/signal.h
inspector.o: $(hdrdir)/ruby/internal/intern/sprintf.h
inspector.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ profile_frames.o: $(hdrdir)/ruby/internal/intern/re.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/ruby.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/select.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+profile_frames.o: $(hdrdir)/ruby/internal/intern/set.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/signal.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/sprintf.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/dln/empty/depend b/ext/-test-/dln/empty/depend
index d3e606df57..58f1508598 100644
--- a/ext/-test-/dln/empty/depend
+++ b/ext/-test-/dln/empty/depend
@@ -128,6 +128,7 @@ empty.o: $(hdrdir)/ruby/internal/intern/re.h
empty.o: $(hdrdir)/ruby/internal/intern/ruby.h
empty.o: $(hdrdir)/ruby/internal/intern/select.h
empty.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+empty.o: $(hdrdir)/ruby/internal/intern/set.h
empty.o: $(hdrdir)/ruby/internal/intern/signal.h
empty.o: $(hdrdir)/ruby/internal/intern/sprintf.h
empty.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/econv/depend b/ext/-test-/econv/depend
new file mode 100644
index 0000000000..3a5bc9c659
--- /dev/null
+++ b/ext/-test-/econv/depend
@@ -0,0 +1,336 @@
+# AUTOGENERATED DEPENDENCIES START
+append.o: $(RUBY_EXTCONF_H)
+append.o: $(arch_hdrdir)/ruby/config.h
+append.o: $(hdrdir)/ruby.h
+append.o: $(hdrdir)/ruby/assert.h
+append.o: $(hdrdir)/ruby/backward.h
+append.o: $(hdrdir)/ruby/backward/2/assume.h
+append.o: $(hdrdir)/ruby/backward/2/attributes.h
+append.o: $(hdrdir)/ruby/backward/2/bool.h
+append.o: $(hdrdir)/ruby/backward/2/inttypes.h
+append.o: $(hdrdir)/ruby/backward/2/limits.h
+append.o: $(hdrdir)/ruby/backward/2/long_long.h
+append.o: $(hdrdir)/ruby/backward/2/stdalign.h
+append.o: $(hdrdir)/ruby/backward/2/stdarg.h
+append.o: $(hdrdir)/ruby/defines.h
+append.o: $(hdrdir)/ruby/encoding.h
+append.o: $(hdrdir)/ruby/intern.h
+append.o: $(hdrdir)/ruby/internal/abi.h
+append.o: $(hdrdir)/ruby/internal/anyargs.h
+append.o: $(hdrdir)/ruby/internal/arithmetic.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+append.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+append.o: $(hdrdir)/ruby/internal/assume.h
+append.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+append.o: $(hdrdir)/ruby/internal/attr/artificial.h
+append.o: $(hdrdir)/ruby/internal/attr/cold.h
+append.o: $(hdrdir)/ruby/internal/attr/const.h
+append.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+append.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+append.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+append.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+append.o: $(hdrdir)/ruby/internal/attr/error.h
+append.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+append.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+append.o: $(hdrdir)/ruby/internal/attr/format.h
+append.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+append.o: $(hdrdir)/ruby/internal/attr/noalias.h
+append.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+append.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+append.o: $(hdrdir)/ruby/internal/attr/noinline.h
+append.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+append.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+append.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+append.o: $(hdrdir)/ruby/internal/attr/pure.h
+append.o: $(hdrdir)/ruby/internal/attr/restrict.h
+append.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+append.o: $(hdrdir)/ruby/internal/attr/warning.h
+append.o: $(hdrdir)/ruby/internal/attr/weakref.h
+append.o: $(hdrdir)/ruby/internal/cast.h
+append.o: $(hdrdir)/ruby/internal/compiler_is.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+append.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+append.o: $(hdrdir)/ruby/internal/compiler_since.h
+append.o: $(hdrdir)/ruby/internal/config.h
+append.o: $(hdrdir)/ruby/internal/constant_p.h
+append.o: $(hdrdir)/ruby/internal/core.h
+append.o: $(hdrdir)/ruby/internal/core/rarray.h
+append.o: $(hdrdir)/ruby/internal/core/rbasic.h
+append.o: $(hdrdir)/ruby/internal/core/rbignum.h
+append.o: $(hdrdir)/ruby/internal/core/rclass.h
+append.o: $(hdrdir)/ruby/internal/core/rdata.h
+append.o: $(hdrdir)/ruby/internal/core/rfile.h
+append.o: $(hdrdir)/ruby/internal/core/rhash.h
+append.o: $(hdrdir)/ruby/internal/core/robject.h
+append.o: $(hdrdir)/ruby/internal/core/rregexp.h
+append.o: $(hdrdir)/ruby/internal/core/rstring.h
+append.o: $(hdrdir)/ruby/internal/core/rstruct.h
+append.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+append.o: $(hdrdir)/ruby/internal/ctype.h
+append.o: $(hdrdir)/ruby/internal/dllexport.h
+append.o: $(hdrdir)/ruby/internal/dosish.h
+append.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+append.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+append.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+append.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+append.o: $(hdrdir)/ruby/internal/encoding/re.h
+append.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+append.o: $(hdrdir)/ruby/internal/encoding/string.h
+append.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+append.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+append.o: $(hdrdir)/ruby/internal/error.h
+append.o: $(hdrdir)/ruby/internal/eval.h
+append.o: $(hdrdir)/ruby/internal/event.h
+append.o: $(hdrdir)/ruby/internal/fl_type.h
+append.o: $(hdrdir)/ruby/internal/gc.h
+append.o: $(hdrdir)/ruby/internal/glob.h
+append.o: $(hdrdir)/ruby/internal/globals.h
+append.o: $(hdrdir)/ruby/internal/has/attribute.h
+append.o: $(hdrdir)/ruby/internal/has/builtin.h
+append.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+append.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+append.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+append.o: $(hdrdir)/ruby/internal/has/extension.h
+append.o: $(hdrdir)/ruby/internal/has/feature.h
+append.o: $(hdrdir)/ruby/internal/has/warning.h
+append.o: $(hdrdir)/ruby/internal/intern/array.h
+append.o: $(hdrdir)/ruby/internal/intern/bignum.h
+append.o: $(hdrdir)/ruby/internal/intern/class.h
+append.o: $(hdrdir)/ruby/internal/intern/compar.h
+append.o: $(hdrdir)/ruby/internal/intern/complex.h
+append.o: $(hdrdir)/ruby/internal/intern/cont.h
+append.o: $(hdrdir)/ruby/internal/intern/dir.h
+append.o: $(hdrdir)/ruby/internal/intern/enum.h
+append.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+append.o: $(hdrdir)/ruby/internal/intern/error.h
+append.o: $(hdrdir)/ruby/internal/intern/eval.h
+append.o: $(hdrdir)/ruby/internal/intern/file.h
+append.o: $(hdrdir)/ruby/internal/intern/hash.h
+append.o: $(hdrdir)/ruby/internal/intern/io.h
+append.o: $(hdrdir)/ruby/internal/intern/load.h
+append.o: $(hdrdir)/ruby/internal/intern/marshal.h
+append.o: $(hdrdir)/ruby/internal/intern/numeric.h
+append.o: $(hdrdir)/ruby/internal/intern/object.h
+append.o: $(hdrdir)/ruby/internal/intern/parse.h
+append.o: $(hdrdir)/ruby/internal/intern/proc.h
+append.o: $(hdrdir)/ruby/internal/intern/process.h
+append.o: $(hdrdir)/ruby/internal/intern/random.h
+append.o: $(hdrdir)/ruby/internal/intern/range.h
+append.o: $(hdrdir)/ruby/internal/intern/rational.h
+append.o: $(hdrdir)/ruby/internal/intern/re.h
+append.o: $(hdrdir)/ruby/internal/intern/ruby.h
+append.o: $(hdrdir)/ruby/internal/intern/select.h
+append.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+append.o: $(hdrdir)/ruby/internal/intern/set.h
+append.o: $(hdrdir)/ruby/internal/intern/signal.h
+append.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+append.o: $(hdrdir)/ruby/internal/intern/string.h
+append.o: $(hdrdir)/ruby/internal/intern/struct.h
+append.o: $(hdrdir)/ruby/internal/intern/thread.h
+append.o: $(hdrdir)/ruby/internal/intern/time.h
+append.o: $(hdrdir)/ruby/internal/intern/variable.h
+append.o: $(hdrdir)/ruby/internal/intern/vm.h
+append.o: $(hdrdir)/ruby/internal/interpreter.h
+append.o: $(hdrdir)/ruby/internal/iterator.h
+append.o: $(hdrdir)/ruby/internal/memory.h
+append.o: $(hdrdir)/ruby/internal/method.h
+append.o: $(hdrdir)/ruby/internal/module.h
+append.o: $(hdrdir)/ruby/internal/newobj.h
+append.o: $(hdrdir)/ruby/internal/scan_args.h
+append.o: $(hdrdir)/ruby/internal/special_consts.h
+append.o: $(hdrdir)/ruby/internal/static_assert.h
+append.o: $(hdrdir)/ruby/internal/stdalign.h
+append.o: $(hdrdir)/ruby/internal/stdbool.h
+append.o: $(hdrdir)/ruby/internal/stdckdint.h
+append.o: $(hdrdir)/ruby/internal/symbol.h
+append.o: $(hdrdir)/ruby/internal/value.h
+append.o: $(hdrdir)/ruby/internal/value_type.h
+append.o: $(hdrdir)/ruby/internal/variable.h
+append.o: $(hdrdir)/ruby/internal/warning_push.h
+append.o: $(hdrdir)/ruby/internal/xmalloc.h
+append.o: $(hdrdir)/ruby/missing.h
+append.o: $(hdrdir)/ruby/onigmo.h
+append.o: $(hdrdir)/ruby/oniguruma.h
+append.o: $(hdrdir)/ruby/ruby.h
+append.o: $(hdrdir)/ruby/st.h
+append.o: $(hdrdir)/ruby/subst.h
+append.o: append.c
+init.o: $(RUBY_EXTCONF_H)
+init.o: $(arch_hdrdir)/ruby/config.h
+init.o: $(hdrdir)/ruby.h
+init.o: $(hdrdir)/ruby/assert.h
+init.o: $(hdrdir)/ruby/backward.h
+init.o: $(hdrdir)/ruby/backward/2/assume.h
+init.o: $(hdrdir)/ruby/backward/2/attributes.h
+init.o: $(hdrdir)/ruby/backward/2/bool.h
+init.o: $(hdrdir)/ruby/backward/2/inttypes.h
+init.o: $(hdrdir)/ruby/backward/2/limits.h
+init.o: $(hdrdir)/ruby/backward/2/long_long.h
+init.o: $(hdrdir)/ruby/backward/2/stdalign.h
+init.o: $(hdrdir)/ruby/backward/2/stdarg.h
+init.o: $(hdrdir)/ruby/defines.h
+init.o: $(hdrdir)/ruby/intern.h
+init.o: $(hdrdir)/ruby/internal/abi.h
+init.o: $(hdrdir)/ruby/internal/anyargs.h
+init.o: $(hdrdir)/ruby/internal/arithmetic.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+init.o: $(hdrdir)/ruby/internal/assume.h
+init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+init.o: $(hdrdir)/ruby/internal/attr/artificial.h
+init.o: $(hdrdir)/ruby/internal/attr/cold.h
+init.o: $(hdrdir)/ruby/internal/attr/const.h
+init.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+init.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+init.o: $(hdrdir)/ruby/internal/attr/error.h
+init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+init.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+init.o: $(hdrdir)/ruby/internal/attr/format.h
+init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+init.o: $(hdrdir)/ruby/internal/attr/noalias.h
+init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+init.o: $(hdrdir)/ruby/internal/attr/noinline.h
+init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+init.o: $(hdrdir)/ruby/internal/attr/pure.h
+init.o: $(hdrdir)/ruby/internal/attr/restrict.h
+init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+init.o: $(hdrdir)/ruby/internal/attr/warning.h
+init.o: $(hdrdir)/ruby/internal/attr/weakref.h
+init.o: $(hdrdir)/ruby/internal/cast.h
+init.o: $(hdrdir)/ruby/internal/compiler_is.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+init.o: $(hdrdir)/ruby/internal/compiler_since.h
+init.o: $(hdrdir)/ruby/internal/config.h
+init.o: $(hdrdir)/ruby/internal/constant_p.h
+init.o: $(hdrdir)/ruby/internal/core.h
+init.o: $(hdrdir)/ruby/internal/core/rarray.h
+init.o: $(hdrdir)/ruby/internal/core/rbasic.h
+init.o: $(hdrdir)/ruby/internal/core/rbignum.h
+init.o: $(hdrdir)/ruby/internal/core/rclass.h
+init.o: $(hdrdir)/ruby/internal/core/rdata.h
+init.o: $(hdrdir)/ruby/internal/core/rfile.h
+init.o: $(hdrdir)/ruby/internal/core/rhash.h
+init.o: $(hdrdir)/ruby/internal/core/robject.h
+init.o: $(hdrdir)/ruby/internal/core/rregexp.h
+init.o: $(hdrdir)/ruby/internal/core/rstring.h
+init.o: $(hdrdir)/ruby/internal/core/rstruct.h
+init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+init.o: $(hdrdir)/ruby/internal/ctype.h
+init.o: $(hdrdir)/ruby/internal/dllexport.h
+init.o: $(hdrdir)/ruby/internal/dosish.h
+init.o: $(hdrdir)/ruby/internal/error.h
+init.o: $(hdrdir)/ruby/internal/eval.h
+init.o: $(hdrdir)/ruby/internal/event.h
+init.o: $(hdrdir)/ruby/internal/fl_type.h
+init.o: $(hdrdir)/ruby/internal/gc.h
+init.o: $(hdrdir)/ruby/internal/glob.h
+init.o: $(hdrdir)/ruby/internal/globals.h
+init.o: $(hdrdir)/ruby/internal/has/attribute.h
+init.o: $(hdrdir)/ruby/internal/has/builtin.h
+init.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+init.o: $(hdrdir)/ruby/internal/has/extension.h
+init.o: $(hdrdir)/ruby/internal/has/feature.h
+init.o: $(hdrdir)/ruby/internal/has/warning.h
+init.o: $(hdrdir)/ruby/internal/intern/array.h
+init.o: $(hdrdir)/ruby/internal/intern/bignum.h
+init.o: $(hdrdir)/ruby/internal/intern/class.h
+init.o: $(hdrdir)/ruby/internal/intern/compar.h
+init.o: $(hdrdir)/ruby/internal/intern/complex.h
+init.o: $(hdrdir)/ruby/internal/intern/cont.h
+init.o: $(hdrdir)/ruby/internal/intern/dir.h
+init.o: $(hdrdir)/ruby/internal/intern/enum.h
+init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+init.o: $(hdrdir)/ruby/internal/intern/error.h
+init.o: $(hdrdir)/ruby/internal/intern/eval.h
+init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/hash.h
+init.o: $(hdrdir)/ruby/internal/intern/io.h
+init.o: $(hdrdir)/ruby/internal/intern/load.h
+init.o: $(hdrdir)/ruby/internal/intern/marshal.h
+init.o: $(hdrdir)/ruby/internal/intern/numeric.h
+init.o: $(hdrdir)/ruby/internal/intern/object.h
+init.o: $(hdrdir)/ruby/internal/intern/parse.h
+init.o: $(hdrdir)/ruby/internal/intern/proc.h
+init.o: $(hdrdir)/ruby/internal/intern/process.h
+init.o: $(hdrdir)/ruby/internal/intern/random.h
+init.o: $(hdrdir)/ruby/internal/intern/range.h
+init.o: $(hdrdir)/ruby/internal/intern/rational.h
+init.o: $(hdrdir)/ruby/internal/intern/re.h
+init.o: $(hdrdir)/ruby/internal/intern/ruby.h
+init.o: $(hdrdir)/ruby/internal/intern/select.h
+init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
+init.o: $(hdrdir)/ruby/internal/intern/signal.h
+init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+init.o: $(hdrdir)/ruby/internal/intern/string.h
+init.o: $(hdrdir)/ruby/internal/intern/struct.h
+init.o: $(hdrdir)/ruby/internal/intern/thread.h
+init.o: $(hdrdir)/ruby/internal/intern/time.h
+init.o: $(hdrdir)/ruby/internal/intern/variable.h
+init.o: $(hdrdir)/ruby/internal/intern/vm.h
+init.o: $(hdrdir)/ruby/internal/interpreter.h
+init.o: $(hdrdir)/ruby/internal/iterator.h
+init.o: $(hdrdir)/ruby/internal/memory.h
+init.o: $(hdrdir)/ruby/internal/method.h
+init.o: $(hdrdir)/ruby/internal/module.h
+init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/scan_args.h
+init.o: $(hdrdir)/ruby/internal/special_consts.h
+init.o: $(hdrdir)/ruby/internal/static_assert.h
+init.o: $(hdrdir)/ruby/internal/stdalign.h
+init.o: $(hdrdir)/ruby/internal/stdbool.h
+init.o: $(hdrdir)/ruby/internal/stdckdint.h
+init.o: $(hdrdir)/ruby/internal/symbol.h
+init.o: $(hdrdir)/ruby/internal/value.h
+init.o: $(hdrdir)/ruby/internal/value_type.h
+init.o: $(hdrdir)/ruby/internal/variable.h
+init.o: $(hdrdir)/ruby/internal/warning_push.h
+init.o: $(hdrdir)/ruby/internal/xmalloc.h
+init.o: $(hdrdir)/ruby/missing.h
+init.o: $(hdrdir)/ruby/ruby.h
+init.o: $(hdrdir)/ruby/st.h
+init.o: $(hdrdir)/ruby/subst.h
+init.o: init.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/ensure_and_callcc/depend b/ext/-test-/ensure_and_callcc/depend
new file mode 100644
index 0000000000..54431847a6
--- /dev/null
+++ b/ext/-test-/ensure_and_callcc/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+ensure_and_callcc.o: $(RUBY_EXTCONF_H)
+ensure_and_callcc.o: $(arch_hdrdir)/ruby/config.h
+ensure_and_callcc.o: $(hdrdir)/ruby.h
+ensure_and_callcc.o: $(hdrdir)/ruby/assert.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/assume.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/attributes.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/bool.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/inttypes.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/limits.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/long_long.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/stdalign.h
+ensure_and_callcc.o: $(hdrdir)/ruby/backward/2/stdarg.h
+ensure_and_callcc.o: $(hdrdir)/ruby/defines.h
+ensure_and_callcc.o: $(hdrdir)/ruby/intern.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/abi.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/anyargs.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/assume.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/artificial.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/cold.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/const.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/error.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/format.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noalias.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noinline.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/pure.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/restrict.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/warning.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/attr/weakref.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/cast.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/compiler_since.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/config.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/constant_p.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rarray.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rbasic.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rbignum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rclass.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rdata.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rfile.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rhash.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/robject.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rregexp.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rstring.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rstruct.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/ctype.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/dllexport.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/dosish.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/error.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/eval.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/event.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/fl_type.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/gc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/glob.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/globals.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/builtin.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/extension.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/feature.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/has/warning.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/array.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/bignum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/class.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/compar.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/complex.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/cont.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/dir.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/enum.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/error.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/eval.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/file.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/hash.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/io.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/load.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/marshal.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/numeric.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/object.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/parse.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/proc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/process.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/random.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/range.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/rational.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/re.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/ruby.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/select.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/set.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/signal.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/string.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/struct.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/thread.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/time.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/variable.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/intern/vm.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/interpreter.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/iterator.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/memory.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/method.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/module.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/newobj.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/scan_args.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/special_consts.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/static_assert.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/stdalign.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/stdbool.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/stdckdint.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/symbol.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/value.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/value_type.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/variable.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/warning_push.h
+ensure_and_callcc.o: $(hdrdir)/ruby/internal/xmalloc.h
+ensure_and_callcc.o: $(hdrdir)/ruby/missing.h
+ensure_and_callcc.o: $(hdrdir)/ruby/ruby.h
+ensure_and_callcc.o: $(hdrdir)/ruby/st.h
+ensure_and_callcc.o: $(hdrdir)/ruby/subst.h
+ensure_and_callcc.o: ensure_and_callcc.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/enumerator_kw/depend b/ext/-test-/enumerator_kw/depend
index 85daa55b53..b6d2f0a998 100644
--- a/ext/-test-/enumerator_kw/depend
+++ b/ext/-test-/enumerator_kw/depend
@@ -128,6 +128,7 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/intern/re.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/ruby.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/select.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enumerator_kw.o: $(hdrdir)/ruby/internal/intern/set.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/signal.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/eval/depend b/ext/-test-/eval/depend
new file mode 100644
index 0000000000..03a1c7d7ef
--- /dev/null
+++ b/ext/-test-/eval/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+eval.o: $(RUBY_EXTCONF_H)
+eval.o: $(arch_hdrdir)/ruby/config.h
+eval.o: $(hdrdir)/ruby/assert.h
+eval.o: $(hdrdir)/ruby/backward.h
+eval.o: $(hdrdir)/ruby/backward/2/assume.h
+eval.o: $(hdrdir)/ruby/backward/2/attributes.h
+eval.o: $(hdrdir)/ruby/backward/2/bool.h
+eval.o: $(hdrdir)/ruby/backward/2/inttypes.h
+eval.o: $(hdrdir)/ruby/backward/2/limits.h
+eval.o: $(hdrdir)/ruby/backward/2/long_long.h
+eval.o: $(hdrdir)/ruby/backward/2/stdalign.h
+eval.o: $(hdrdir)/ruby/backward/2/stdarg.h
+eval.o: $(hdrdir)/ruby/defines.h
+eval.o: $(hdrdir)/ruby/intern.h
+eval.o: $(hdrdir)/ruby/internal/abi.h
+eval.o: $(hdrdir)/ruby/internal/anyargs.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+eval.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+eval.o: $(hdrdir)/ruby/internal/assume.h
+eval.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+eval.o: $(hdrdir)/ruby/internal/attr/artificial.h
+eval.o: $(hdrdir)/ruby/internal/attr/cold.h
+eval.o: $(hdrdir)/ruby/internal/attr/const.h
+eval.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+eval.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+eval.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+eval.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+eval.o: $(hdrdir)/ruby/internal/attr/error.h
+eval.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+eval.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+eval.o: $(hdrdir)/ruby/internal/attr/format.h
+eval.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+eval.o: $(hdrdir)/ruby/internal/attr/noalias.h
+eval.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+eval.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+eval.o: $(hdrdir)/ruby/internal/attr/noinline.h
+eval.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+eval.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+eval.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+eval.o: $(hdrdir)/ruby/internal/attr/pure.h
+eval.o: $(hdrdir)/ruby/internal/attr/restrict.h
+eval.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+eval.o: $(hdrdir)/ruby/internal/attr/warning.h
+eval.o: $(hdrdir)/ruby/internal/attr/weakref.h
+eval.o: $(hdrdir)/ruby/internal/cast.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+eval.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+eval.o: $(hdrdir)/ruby/internal/compiler_since.h
+eval.o: $(hdrdir)/ruby/internal/config.h
+eval.o: $(hdrdir)/ruby/internal/constant_p.h
+eval.o: $(hdrdir)/ruby/internal/core.h
+eval.o: $(hdrdir)/ruby/internal/core/rarray.h
+eval.o: $(hdrdir)/ruby/internal/core/rbasic.h
+eval.o: $(hdrdir)/ruby/internal/core/rbignum.h
+eval.o: $(hdrdir)/ruby/internal/core/rclass.h
+eval.o: $(hdrdir)/ruby/internal/core/rdata.h
+eval.o: $(hdrdir)/ruby/internal/core/rfile.h
+eval.o: $(hdrdir)/ruby/internal/core/rhash.h
+eval.o: $(hdrdir)/ruby/internal/core/robject.h
+eval.o: $(hdrdir)/ruby/internal/core/rregexp.h
+eval.o: $(hdrdir)/ruby/internal/core/rstring.h
+eval.o: $(hdrdir)/ruby/internal/core/rstruct.h
+eval.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+eval.o: $(hdrdir)/ruby/internal/ctype.h
+eval.o: $(hdrdir)/ruby/internal/dllexport.h
+eval.o: $(hdrdir)/ruby/internal/dosish.h
+eval.o: $(hdrdir)/ruby/internal/error.h
+eval.o: $(hdrdir)/ruby/internal/eval.h
+eval.o: $(hdrdir)/ruby/internal/event.h
+eval.o: $(hdrdir)/ruby/internal/fl_type.h
+eval.o: $(hdrdir)/ruby/internal/gc.h
+eval.o: $(hdrdir)/ruby/internal/glob.h
+eval.o: $(hdrdir)/ruby/internal/globals.h
+eval.o: $(hdrdir)/ruby/internal/has/attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/builtin.h
+eval.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+eval.o: $(hdrdir)/ruby/internal/has/extension.h
+eval.o: $(hdrdir)/ruby/internal/has/feature.h
+eval.o: $(hdrdir)/ruby/internal/has/warning.h
+eval.o: $(hdrdir)/ruby/internal/intern/array.h
+eval.o: $(hdrdir)/ruby/internal/intern/bignum.h
+eval.o: $(hdrdir)/ruby/internal/intern/class.h
+eval.o: $(hdrdir)/ruby/internal/intern/compar.h
+eval.o: $(hdrdir)/ruby/internal/intern/complex.h
+eval.o: $(hdrdir)/ruby/internal/intern/cont.h
+eval.o: $(hdrdir)/ruby/internal/intern/dir.h
+eval.o: $(hdrdir)/ruby/internal/intern/enum.h
+eval.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+eval.o: $(hdrdir)/ruby/internal/intern/error.h
+eval.o: $(hdrdir)/ruby/internal/intern/eval.h
+eval.o: $(hdrdir)/ruby/internal/intern/file.h
+eval.o: $(hdrdir)/ruby/internal/intern/hash.h
+eval.o: $(hdrdir)/ruby/internal/intern/io.h
+eval.o: $(hdrdir)/ruby/internal/intern/load.h
+eval.o: $(hdrdir)/ruby/internal/intern/marshal.h
+eval.o: $(hdrdir)/ruby/internal/intern/numeric.h
+eval.o: $(hdrdir)/ruby/internal/intern/object.h
+eval.o: $(hdrdir)/ruby/internal/intern/parse.h
+eval.o: $(hdrdir)/ruby/internal/intern/proc.h
+eval.o: $(hdrdir)/ruby/internal/intern/process.h
+eval.o: $(hdrdir)/ruby/internal/intern/random.h
+eval.o: $(hdrdir)/ruby/internal/intern/range.h
+eval.o: $(hdrdir)/ruby/internal/intern/rational.h
+eval.o: $(hdrdir)/ruby/internal/intern/re.h
+eval.o: $(hdrdir)/ruby/internal/intern/ruby.h
+eval.o: $(hdrdir)/ruby/internal/intern/select.h
+eval.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+eval.o: $(hdrdir)/ruby/internal/intern/set.h
+eval.o: $(hdrdir)/ruby/internal/intern/signal.h
+eval.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+eval.o: $(hdrdir)/ruby/internal/intern/string.h
+eval.o: $(hdrdir)/ruby/internal/intern/struct.h
+eval.o: $(hdrdir)/ruby/internal/intern/thread.h
+eval.o: $(hdrdir)/ruby/internal/intern/time.h
+eval.o: $(hdrdir)/ruby/internal/intern/variable.h
+eval.o: $(hdrdir)/ruby/internal/intern/vm.h
+eval.o: $(hdrdir)/ruby/internal/interpreter.h
+eval.o: $(hdrdir)/ruby/internal/iterator.h
+eval.o: $(hdrdir)/ruby/internal/memory.h
+eval.o: $(hdrdir)/ruby/internal/method.h
+eval.o: $(hdrdir)/ruby/internal/module.h
+eval.o: $(hdrdir)/ruby/internal/newobj.h
+eval.o: $(hdrdir)/ruby/internal/scan_args.h
+eval.o: $(hdrdir)/ruby/internal/special_consts.h
+eval.o: $(hdrdir)/ruby/internal/static_assert.h
+eval.o: $(hdrdir)/ruby/internal/stdalign.h
+eval.o: $(hdrdir)/ruby/internal/stdbool.h
+eval.o: $(hdrdir)/ruby/internal/stdckdint.h
+eval.o: $(hdrdir)/ruby/internal/symbol.h
+eval.o: $(hdrdir)/ruby/internal/value.h
+eval.o: $(hdrdir)/ruby/internal/value_type.h
+eval.o: $(hdrdir)/ruby/internal/variable.h
+eval.o: $(hdrdir)/ruby/internal/warning_push.h
+eval.o: $(hdrdir)/ruby/internal/xmalloc.h
+eval.o: $(hdrdir)/ruby/missing.h
+eval.o: $(hdrdir)/ruby/ruby.h
+eval.o: $(hdrdir)/ruby/st.h
+eval.o: $(hdrdir)/ruby/subst.h
+eval.o: eval.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/exception/depend b/ext/-test-/exception/depend
index 7a0544b1e1..690e5ad377 100644
--- a/ext/-test-/exception/depend
+++ b/ext/-test-/exception/depend
@@ -127,6 +127,7 @@ dataerror.o: $(hdrdir)/ruby/internal/intern/re.h
dataerror.o: $(hdrdir)/ruby/internal/intern/ruby.h
dataerror.o: $(hdrdir)/ruby/internal/intern/select.h
dataerror.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+dataerror.o: $(hdrdir)/ruby/internal/intern/set.h
dataerror.o: $(hdrdir)/ruby/internal/intern/signal.h
dataerror.o: $(hdrdir)/ruby/internal/intern/sprintf.h
dataerror.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -297,6 +298,7 @@ enc_raise.o: $(hdrdir)/ruby/internal/intern/re.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/ruby.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/select.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enc_raise.o: $(hdrdir)/ruby/internal/intern/set.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/signal.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -459,6 +461,7 @@ ensured.o: $(hdrdir)/ruby/internal/intern/re.h
ensured.o: $(hdrdir)/ruby/internal/intern/ruby.h
ensured.o: $(hdrdir)/ruby/internal/intern/select.h
ensured.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ensured.o: $(hdrdir)/ruby/internal/intern/set.h
ensured.o: $(hdrdir)/ruby/internal/intern/signal.h
ensured.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ensured.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -619,6 +622,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/fatal/depend b/ext/-test-/fatal/depend
index 36b0ad4205..306bc9099c 100644
--- a/ext/-test-/fatal/depend
+++ b/ext/-test-/fatal/depend
@@ -129,6 +129,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -289,6 +290,7 @@ invalid.o: $(hdrdir)/ruby/internal/intern/re.h
invalid.o: $(hdrdir)/ruby/internal/intern/ruby.h
invalid.o: $(hdrdir)/ruby/internal/intern/select.h
invalid.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+invalid.o: $(hdrdir)/ruby/internal/intern/set.h
invalid.o: $(hdrdir)/ruby/internal/intern/signal.h
invalid.o: $(hdrdir)/ruby/internal/intern/sprintf.h
invalid.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -449,6 +451,7 @@ rb_fatal.o: $(hdrdir)/ruby/internal/intern/re.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/select.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_fatal.o: $(hdrdir)/ruby/internal/intern/set.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/fatal/invalid.c b/ext/-test-/fatal/invalid.c
index 393465416a..6fd970b181 100644
--- a/ext/-test-/fatal/invalid.c
+++ b/ext/-test-/fatal/invalid.c
@@ -1,11 +1,5 @@
#include <ruby.h>
-#if SIZEOF_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) NUM2ULONG(x)
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) NUM2ULL(x)
-#endif
-
static VALUE
invalid_call(VALUE obj, VALUE address)
{
diff --git a/ext/-test-/file/depend b/ext/-test-/file/depend
index e985f914b2..fe320f3d44 100644
--- a/ext/-test-/file/depend
+++ b/ext/-test-/file/depend
@@ -137,6 +137,7 @@ fs.o: $(hdrdir)/ruby/internal/intern/re.h
fs.o: $(hdrdir)/ruby/internal/intern/ruby.h
fs.o: $(hdrdir)/ruby/internal/intern/select.h
fs.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+fs.o: $(hdrdir)/ruby/internal/intern/set.h
fs.o: $(hdrdir)/ruby/internal/intern/signal.h
fs.o: $(hdrdir)/ruby/internal/intern/sprintf.h
fs.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -300,6 +301,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -469,6 +471,7 @@ newline_conv.o: $(hdrdir)/ruby/internal/intern/re.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/ruby.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/select.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+newline_conv.o: $(hdrdir)/ruby/internal/intern/set.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/signal.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/sprintf.h
newline_conv.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -641,6 +644,7 @@ stat.o: $(hdrdir)/ruby/internal/intern/re.h
stat.o: $(hdrdir)/ruby/internal/intern/ruby.h
stat.o: $(hdrdir)/ruby/internal/intern/select.h
stat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stat.o: $(hdrdir)/ruby/internal/intern/set.h
stat.o: $(hdrdir)/ruby/internal/intern/signal.h
stat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
stat.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/float/depend b/ext/-test-/float/depend
index 3e34818d5f..334ed33c3b 100644
--- a/ext/-test-/float/depend
+++ b/ext/-test-/float/depend
@@ -131,6 +131,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -291,6 +292,7 @@ nextafter.o: $(hdrdir)/ruby/internal/intern/re.h
nextafter.o: $(hdrdir)/ruby/internal/intern/ruby.h
nextafter.o: $(hdrdir)/ruby/internal/intern/select.h
nextafter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+nextafter.o: $(hdrdir)/ruby/internal/intern/set.h
nextafter.o: $(hdrdir)/ruby/internal/intern/signal.h
nextafter.o: $(hdrdir)/ruby/internal/intern/sprintf.h
nextafter.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/funcall/depend b/ext/-test-/funcall/depend
index a5a30873ac..e54370306f 100644
--- a/ext/-test-/funcall/depend
+++ b/ext/-test-/funcall/depend
@@ -128,6 +128,7 @@ funcall.o: $(hdrdir)/ruby/internal/intern/re.h
funcall.o: $(hdrdir)/ruby/internal/intern/ruby.h
funcall.o: $(hdrdir)/ruby/internal/intern/select.h
funcall.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+funcall.o: $(hdrdir)/ruby/internal/intern/set.h
funcall.o: $(hdrdir)/ruby/internal/intern/signal.h
funcall.o: $(hdrdir)/ruby/internal/intern/sprintf.h
funcall.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/gvl/call_without_gvl/depend b/ext/-test-/gvl/call_without_gvl/depend
index 6463d4527d..236d1e1d3b 100644
--- a/ext/-test-/gvl/call_without_gvl/depend
+++ b/ext/-test-/gvl/call_without_gvl/depend
@@ -127,6 +127,7 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/intern/re.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/ruby.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/select.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+call_without_gvl.o: $(hdrdir)/ruby/internal/intern/set.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/signal.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/hash/depend b/ext/-test-/hash/depend
index 4bc4bfcdd6..416b93f9de 100644
--- a/ext/-test-/hash/depend
+++ b/ext/-test-/hash/depend
@@ -128,6 +128,7 @@ delete.o: $(hdrdir)/ruby/internal/intern/re.h
delete.o: $(hdrdir)/ruby/internal/intern/ruby.h
delete.o: $(hdrdir)/ruby/internal/intern/select.h
delete.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+delete.o: $(hdrdir)/ruby/internal/intern/set.h
delete.o: $(hdrdir)/ruby/internal/intern/signal.h
delete.o: $(hdrdir)/ruby/internal/intern/sprintf.h
delete.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/integer/depend b/ext/-test-/integer/depend
index d89965e3d9..0ea007e814 100644
--- a/ext/-test-/integer/depend
+++ b/ext/-test-/integer/depend
@@ -128,6 +128,7 @@ core_ext.o: $(hdrdir)/ruby/internal/intern/re.h
core_ext.o: $(hdrdir)/ruby/internal/intern/ruby.h
core_ext.o: $(hdrdir)/ruby/internal/intern/select.h
core_ext.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+core_ext.o: $(hdrdir)/ruby/internal/intern/set.h
core_ext.o: $(hdrdir)/ruby/internal/intern/signal.h
core_ext.o: $(hdrdir)/ruby/internal/intern/sprintf.h
core_ext.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -296,6 +297,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -456,6 +458,7 @@ my_integer.o: $(hdrdir)/ruby/internal/intern/re.h
my_integer.o: $(hdrdir)/ruby/internal/intern/ruby.h
my_integer.o: $(hdrdir)/ruby/internal/intern/select.h
my_integer.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+my_integer.o: $(hdrdir)/ruby/internal/intern/set.h
my_integer.o: $(hdrdir)/ruby/internal/intern/signal.h
my_integer.o: $(hdrdir)/ruby/internal/intern/sprintf.h
my_integer.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/iseq_load/depend b/ext/-test-/iseq_load/depend
index fd07b3199c..9361ddb938 100644
--- a/ext/-test-/iseq_load/depend
+++ b/ext/-test-/iseq_load/depend
@@ -128,6 +128,7 @@ iseq_load.o: $(hdrdir)/ruby/internal/intern/re.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/ruby.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/select.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+iseq_load.o: $(hdrdir)/ruby/internal/intern/set.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/signal.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/sprintf.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/iter/depend b/ext/-test-/iter/depend
index cff4b1bb43..161947382c 100644
--- a/ext/-test-/iter/depend
+++ b/ext/-test-/iter/depend
@@ -128,6 +128,7 @@ break.o: $(hdrdir)/ruby/internal/intern/re.h
break.o: $(hdrdir)/ruby/internal/intern/ruby.h
break.o: $(hdrdir)/ruby/internal/intern/select.h
break.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+break.o: $(hdrdir)/ruby/internal/intern/set.h
break.o: $(hdrdir)/ruby/internal/intern/signal.h
break.o: $(hdrdir)/ruby/internal/intern/sprintf.h
break.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ yield.o: $(hdrdir)/ruby/internal/intern/re.h
yield.o: $(hdrdir)/ruby/internal/intern/ruby.h
yield.o: $(hdrdir)/ruby/internal/intern/select.h
yield.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+yield.o: $(hdrdir)/ruby/internal/intern/set.h
yield.o: $(hdrdir)/ruby/internal/intern/signal.h
yield.o: $(hdrdir)/ruby/internal/intern/sprintf.h
yield.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/load/dot.dot/depend b/ext/-test-/load/dot.dot/depend
index f9be79e957..339837d183 100644
--- a/ext/-test-/load/dot.dot/depend
+++ b/ext/-test-/load/dot.dot/depend
@@ -128,6 +128,7 @@ dot.dot.o: $(hdrdir)/ruby/internal/intern/re.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/ruby.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/select.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+dot.dot.o: $(hdrdir)/ruby/internal/intern/set.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/signal.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/sprintf.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/load/protect/depend b/ext/-test-/load/protect/depend
index 324c17237a..c76c6f88ed 100644
--- a/ext/-test-/load/protect/depend
+++ b/ext/-test-/load/protect/depend
@@ -128,6 +128,7 @@ protect.o: $(hdrdir)/ruby/internal/intern/re.h
protect.o: $(hdrdir)/ruby/internal/intern/ruby.h
protect.o: $(hdrdir)/ruby/internal/intern/select.h
protect.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+protect.o: $(hdrdir)/ruby/internal/intern/set.h
protect.o: $(hdrdir)/ruby/internal/intern/signal.h
protect.o: $(hdrdir)/ruby/internal/intern/sprintf.h
protect.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/load/resolve_symbol_resolver/depend b/ext/-test-/load/resolve_symbol_resolver/depend
new file mode 100644
index 0000000000..f422898b69
--- /dev/null
+++ b/ext/-test-/load/resolve_symbol_resolver/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+resolve_symbol_resolver.o: $(RUBY_EXTCONF_H)
+resolve_symbol_resolver.o: $(arch_hdrdir)/ruby/config.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/assert.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/assume.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/attributes.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/bool.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/inttypes.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/limits.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/long_long.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/stdalign.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/backward/2/stdarg.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/defines.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/intern.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/abi.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/anyargs.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/assume.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/artificial.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/cold.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/const.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/error.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/format.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noalias.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noinline.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/pure.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/restrict.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/warning.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/attr/weakref.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/cast.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/compiler_since.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/config.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/constant_p.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rarray.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rbasic.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rbignum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rclass.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rdata.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rfile.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rhash.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/robject.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rregexp.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rstring.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rstruct.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/ctype.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/dllexport.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/dosish.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/error.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/eval.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/event.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/fl_type.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/gc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/glob.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/globals.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/builtin.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/extension.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/feature.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/has/warning.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/array.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/bignum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/class.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/compar.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/complex.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/cont.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/dir.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/enum.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/error.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/eval.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/file.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/hash.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/io.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/load.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/marshal.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/numeric.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/object.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/parse.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/proc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/process.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/random.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/range.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/rational.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/re.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/ruby.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/select.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/set.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/signal.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/string.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/struct.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/thread.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/time.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/variable.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/intern/vm.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/interpreter.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/iterator.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/memory.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/method.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/module.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/newobj.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/scan_args.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/special_consts.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/static_assert.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/stdalign.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/stdbool.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/stdckdint.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/symbol.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/value.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/value_type.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/variable.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/warning_push.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/internal/xmalloc.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/missing.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/ruby.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/st.h
+resolve_symbol_resolver.o: $(hdrdir)/ruby/subst.h
+resolve_symbol_resolver.o: resolve_symbol_resolver.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/load/resolve_symbol_target/depend b/ext/-test-/load/resolve_symbol_target/depend
new file mode 100644
index 0000000000..aa0b5327be
--- /dev/null
+++ b/ext/-test-/load/resolve_symbol_target/depend
@@ -0,0 +1,164 @@
+# AUTOGENERATED DEPENDENCIES START
+resolve_symbol_target.o: $(RUBY_EXTCONF_H)
+resolve_symbol_target.o: $(arch_hdrdir)/ruby/config.h
+resolve_symbol_target.o: $(hdrdir)/ruby.h
+resolve_symbol_target.o: $(hdrdir)/ruby/assert.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/assume.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/attributes.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/bool.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/inttypes.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/limits.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/long_long.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/stdalign.h
+resolve_symbol_target.o: $(hdrdir)/ruby/backward/2/stdarg.h
+resolve_symbol_target.o: $(hdrdir)/ruby/defines.h
+resolve_symbol_target.o: $(hdrdir)/ruby/intern.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/abi.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/anyargs.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/assume.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/artificial.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/cold.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/const.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/error.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/format.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noalias.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noinline.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/pure.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/restrict.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/warning.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/attr/weakref.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/cast.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/compiler_since.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/config.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/constant_p.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rarray.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rbasic.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rbignum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rclass.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rdata.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rfile.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rhash.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/robject.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rregexp.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rstring.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rstruct.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/ctype.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/dllexport.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/dosish.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/error.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/eval.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/event.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/fl_type.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/gc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/glob.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/globals.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/builtin.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/extension.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/feature.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/has/warning.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/array.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/bignum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/class.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/compar.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/complex.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/cont.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/dir.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/enum.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/error.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/eval.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/file.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/hash.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/io.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/load.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/marshal.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/numeric.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/object.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/parse.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/proc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/process.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/random.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/range.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/rational.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/re.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/ruby.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/select.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/set.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/signal.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/string.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/struct.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/thread.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/time.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/variable.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/intern/vm.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/interpreter.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/iterator.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/memory.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/method.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/module.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/newobj.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/scan_args.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/special_consts.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/static_assert.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/stdalign.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/stdbool.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/stdckdint.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/symbol.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/value.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/value_type.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/variable.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/warning_push.h
+resolve_symbol_target.o: $(hdrdir)/ruby/internal/xmalloc.h
+resolve_symbol_target.o: $(hdrdir)/ruby/missing.h
+resolve_symbol_target.o: $(hdrdir)/ruby/ruby.h
+resolve_symbol_target.o: $(hdrdir)/ruby/st.h
+resolve_symbol_target.o: $(hdrdir)/ruby/subst.h
+resolve_symbol_target.o: resolve_symbol_target.c
+resolve_symbol_target.o: resolve_symbol_target.h
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/load/stringify_symbols/depend b/ext/-test-/load/stringify_symbols/depend
new file mode 100644
index 0000000000..2d4d79a7b7
--- /dev/null
+++ b/ext/-test-/load/stringify_symbols/depend
@@ -0,0 +1,164 @@
+# AUTOGENERATED DEPENDENCIES START
+stringify_symbols.o: $(RUBY_EXTCONF_H)
+stringify_symbols.o: $(arch_hdrdir)/ruby/config.h
+stringify_symbols.o: $(hdrdir)/ruby.h
+stringify_symbols.o: $(hdrdir)/ruby/assert.h
+stringify_symbols.o: $(hdrdir)/ruby/backward.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/assume.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/attributes.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/bool.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/inttypes.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/limits.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/long_long.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/stdalign.h
+stringify_symbols.o: $(hdrdir)/ruby/backward/2/stdarg.h
+stringify_symbols.o: $(hdrdir)/ruby/defines.h
+stringify_symbols.o: $(hdrdir)/ruby/intern.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/abi.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/anyargs.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/assume.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/artificial.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/cold.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/const.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/error.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/format.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noalias.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noinline.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/pure.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/restrict.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/warning.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/attr/weakref.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/cast.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/compiler_since.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/config.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/constant_p.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rarray.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rbasic.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rbignum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rclass.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rdata.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rfile.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rhash.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/robject.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rregexp.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rstring.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rstruct.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/ctype.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/dllexport.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/dosish.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/error.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/eval.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/event.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/fl_type.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/gc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/glob.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/globals.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/builtin.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/extension.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/feature.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/has/warning.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/array.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/bignum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/class.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/compar.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/complex.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/cont.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/dir.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/enum.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/error.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/eval.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/file.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/hash.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/io.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/load.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/marshal.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/numeric.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/object.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/parse.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/proc.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/process.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/random.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/range.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/rational.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/re.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/ruby.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/select.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/set.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/signal.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/string.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/struct.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/thread.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/time.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/variable.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/intern/vm.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/interpreter.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/iterator.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/memory.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/method.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/module.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/newobj.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/scan_args.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/special_consts.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/static_assert.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/stdalign.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/stdbool.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/stdckdint.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/symbol.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/value.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/value_type.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/variable.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/warning_push.h
+stringify_symbols.o: $(hdrdir)/ruby/internal/xmalloc.h
+stringify_symbols.o: $(hdrdir)/ruby/missing.h
+stringify_symbols.o: $(hdrdir)/ruby/ruby.h
+stringify_symbols.o: $(hdrdir)/ruby/st.h
+stringify_symbols.o: $(hdrdir)/ruby/subst.h
+stringify_symbols.o: $(hdrdir)/ruby/util.h
+stringify_symbols.o: stringify_symbols.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/load/stringify_target/depend b/ext/-test-/load/stringify_target/depend
new file mode 100644
index 0000000000..c66575d4e4
--- /dev/null
+++ b/ext/-test-/load/stringify_target/depend
@@ -0,0 +1,164 @@
+# AUTOGENERATED DEPENDENCIES START
+stringify_target.o: $(RUBY_EXTCONF_H)
+stringify_target.o: $(arch_hdrdir)/ruby/config.h
+stringify_target.o: $(hdrdir)/ruby.h
+stringify_target.o: $(hdrdir)/ruby/assert.h
+stringify_target.o: $(hdrdir)/ruby/backward.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/assume.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/attributes.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/bool.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/inttypes.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/limits.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/long_long.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/stdalign.h
+stringify_target.o: $(hdrdir)/ruby/backward/2/stdarg.h
+stringify_target.o: $(hdrdir)/ruby/defines.h
+stringify_target.o: $(hdrdir)/ruby/intern.h
+stringify_target.o: $(hdrdir)/ruby/internal/abi.h
+stringify_target.o: $(hdrdir)/ruby/internal/anyargs.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+stringify_target.o: $(hdrdir)/ruby/internal/assume.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/artificial.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/cold.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/const.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/error.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/format.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noalias.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noinline.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/pure.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/restrict.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/warning.h
+stringify_target.o: $(hdrdir)/ruby/internal/attr/weakref.h
+stringify_target.o: $(hdrdir)/ruby/internal/cast.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+stringify_target.o: $(hdrdir)/ruby/internal/compiler_since.h
+stringify_target.o: $(hdrdir)/ruby/internal/config.h
+stringify_target.o: $(hdrdir)/ruby/internal/constant_p.h
+stringify_target.o: $(hdrdir)/ruby/internal/core.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rarray.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rbasic.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rbignum.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rclass.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rdata.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rfile.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rhash.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/robject.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rregexp.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rstring.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rstruct.h
+stringify_target.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+stringify_target.o: $(hdrdir)/ruby/internal/ctype.h
+stringify_target.o: $(hdrdir)/ruby/internal/dllexport.h
+stringify_target.o: $(hdrdir)/ruby/internal/dosish.h
+stringify_target.o: $(hdrdir)/ruby/internal/error.h
+stringify_target.o: $(hdrdir)/ruby/internal/eval.h
+stringify_target.o: $(hdrdir)/ruby/internal/event.h
+stringify_target.o: $(hdrdir)/ruby/internal/fl_type.h
+stringify_target.o: $(hdrdir)/ruby/internal/gc.h
+stringify_target.o: $(hdrdir)/ruby/internal/glob.h
+stringify_target.o: $(hdrdir)/ruby/internal/globals.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/builtin.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/extension.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/feature.h
+stringify_target.o: $(hdrdir)/ruby/internal/has/warning.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/array.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/bignum.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/class.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/compar.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/complex.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/cont.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/dir.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/enum.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/error.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/eval.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/file.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/hash.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/io.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/load.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/marshal.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/numeric.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/object.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/parse.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/proc.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/process.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/random.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/range.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/rational.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/re.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/ruby.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/select.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/set.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/signal.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/string.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/struct.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/thread.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/time.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/variable.h
+stringify_target.o: $(hdrdir)/ruby/internal/intern/vm.h
+stringify_target.o: $(hdrdir)/ruby/internal/interpreter.h
+stringify_target.o: $(hdrdir)/ruby/internal/iterator.h
+stringify_target.o: $(hdrdir)/ruby/internal/memory.h
+stringify_target.o: $(hdrdir)/ruby/internal/method.h
+stringify_target.o: $(hdrdir)/ruby/internal/module.h
+stringify_target.o: $(hdrdir)/ruby/internal/newobj.h
+stringify_target.o: $(hdrdir)/ruby/internal/scan_args.h
+stringify_target.o: $(hdrdir)/ruby/internal/special_consts.h
+stringify_target.o: $(hdrdir)/ruby/internal/static_assert.h
+stringify_target.o: $(hdrdir)/ruby/internal/stdalign.h
+stringify_target.o: $(hdrdir)/ruby/internal/stdbool.h
+stringify_target.o: $(hdrdir)/ruby/internal/stdckdint.h
+stringify_target.o: $(hdrdir)/ruby/internal/symbol.h
+stringify_target.o: $(hdrdir)/ruby/internal/value.h
+stringify_target.o: $(hdrdir)/ruby/internal/value_type.h
+stringify_target.o: $(hdrdir)/ruby/internal/variable.h
+stringify_target.o: $(hdrdir)/ruby/internal/warning_push.h
+stringify_target.o: $(hdrdir)/ruby/internal/xmalloc.h
+stringify_target.o: $(hdrdir)/ruby/missing.h
+stringify_target.o: $(hdrdir)/ruby/ruby.h
+stringify_target.o: $(hdrdir)/ruby/st.h
+stringify_target.o: $(hdrdir)/ruby/subst.h
+stringify_target.o: stringify_target.c
+stringify_target.o: stringify_target.h
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/marshal/compat/depend b/ext/-test-/marshal/compat/depend
index 8bcd9f8b5e..36b9235c23 100644
--- a/ext/-test-/marshal/compat/depend
+++ b/ext/-test-/marshal/compat/depend
@@ -128,6 +128,7 @@ usrcompat.o: $(hdrdir)/ruby/internal/intern/re.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/ruby.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/select.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+usrcompat.o: $(hdrdir)/ruby/internal/intern/set.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/signal.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/marshal/internal_ivar/depend b/ext/-test-/marshal/internal_ivar/depend
index f8be031efc..a2e093d809 100644
--- a/ext/-test-/marshal/internal_ivar/depend
+++ b/ext/-test-/marshal/internal_ivar/depend
@@ -128,6 +128,7 @@ internal_ivar.o: $(hdrdir)/ruby/internal/intern/re.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/ruby.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/select.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+internal_ivar.o: $(hdrdir)/ruby/internal/intern/set.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/signal.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/sprintf.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/marshal/usr/depend b/ext/-test-/marshal/usr/depend
index 09e8207d3a..5ffb8c58de 100644
--- a/ext/-test-/marshal/usr/depend
+++ b/ext/-test-/marshal/usr/depend
@@ -128,6 +128,7 @@ usrmarshal.o: $(hdrdir)/ruby/internal/intern/re.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/ruby.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/select.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+usrmarshal.o: $(hdrdir)/ruby/internal/intern/set.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/signal.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/sprintf.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/memory_view/depend b/ext/-test-/memory_view/depend
index 0c92fc1236..a6ffd76f45 100644
--- a/ext/-test-/memory_view/depend
+++ b/ext/-test-/memory_view/depend
@@ -128,6 +128,7 @@ memory_view.o: $(hdrdir)/ruby/internal/intern/re.h
memory_view.o: $(hdrdir)/ruby/internal/intern/ruby.h
memory_view.o: $(hdrdir)/ruby/internal/intern/select.h
memory_view.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+memory_view.o: $(hdrdir)/ruby/internal/intern/set.h
memory_view.o: $(hdrdir)/ruby/internal/intern/signal.h
memory_view.o: $(hdrdir)/ruby/internal/intern/sprintf.h
memory_view.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/method/depend b/ext/-test-/method/depend
index dce2a815a4..95745b3dae 100644
--- a/ext/-test-/method/depend
+++ b/ext/-test-/method/depend
@@ -128,6 +128,7 @@ arity.o: $(hdrdir)/ruby/internal/intern/re.h
arity.o: $(hdrdir)/ruby/internal/intern/ruby.h
arity.o: $(hdrdir)/ruby/internal/intern/select.h
arity.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+arity.o: $(hdrdir)/ruby/internal/intern/set.h
arity.o: $(hdrdir)/ruby/internal/intern/signal.h
arity.o: $(hdrdir)/ruby/internal/intern/sprintf.h
arity.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/notimplement/depend b/ext/-test-/notimplement/depend
index 84517a9c15..69c970b6f2 100644
--- a/ext/-test-/notimplement/depend
+++ b/ext/-test-/notimplement/depend
@@ -128,6 +128,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/re.h
bug.o: $(hdrdir)/ruby/internal/intern/ruby.h
bug.o: $(hdrdir)/ruby/internal/intern/select.h
bug.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug.o: $(hdrdir)/ruby/internal/intern/set.h
bug.o: $(hdrdir)/ruby/internal/intern/signal.h
bug.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bug.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/num2int/depend b/ext/-test-/num2int/depend
index 5550033be7..75536363ac 100644
--- a/ext/-test-/num2int/depend
+++ b/ext/-test-/num2int/depend
@@ -128,6 +128,7 @@ num2int.o: $(hdrdir)/ruby/internal/intern/re.h
num2int.o: $(hdrdir)/ruby/internal/intern/ruby.h
num2int.o: $(hdrdir)/ruby/internal/intern/select.h
num2int.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+num2int.o: $(hdrdir)/ruby/internal/intern/set.h
num2int.o: $(hdrdir)/ruby/internal/intern/signal.h
num2int.o: $(hdrdir)/ruby/internal/intern/sprintf.h
num2int.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/path_to_class/depend b/ext/-test-/path_to_class/depend
index a1657c9574..e535058e09 100644
--- a/ext/-test-/path_to_class/depend
+++ b/ext/-test-/path_to_class/depend
@@ -128,6 +128,7 @@ path_to_class.o: $(hdrdir)/ruby/internal/intern/re.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/ruby.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/select.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+path_to_class.o: $(hdrdir)/ruby/internal/intern/set.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/signal.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/sprintf.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/popen_deadlock/depend b/ext/-test-/popen_deadlock/depend
index 1904e64e59..0b8932e8b8 100644
--- a/ext/-test-/popen_deadlock/depend
+++ b/ext/-test-/popen_deadlock/depend
@@ -128,6 +128,7 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/re.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/ruby.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/select.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/set.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/signal.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/sprintf.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/postponed_job/depend b/ext/-test-/postponed_job/depend
index 72250896b0..ff567e3921 100644
--- a/ext/-test-/postponed_job/depend
+++ b/ext/-test-/postponed_job/depend
@@ -129,6 +129,7 @@ postponed_job.o: $(hdrdir)/ruby/internal/intern/re.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/ruby.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/select.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+postponed_job.o: $(hdrdir)/ruby/internal/intern/set.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/signal.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/sprintf.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/printf/depend b/ext/-test-/printf/depend
index 0530df78bf..be895cf769 100644
--- a/ext/-test-/printf/depend
+++ b/ext/-test-/printf/depend
@@ -138,6 +138,7 @@ printf.o: $(hdrdir)/ruby/internal/intern/re.h
printf.o: $(hdrdir)/ruby/internal/intern/ruby.h
printf.o: $(hdrdir)/ruby/internal/intern/select.h
printf.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+printf.o: $(hdrdir)/ruby/internal/intern/set.h
printf.o: $(hdrdir)/ruby/internal/intern/signal.h
printf.o: $(hdrdir)/ruby/internal/intern/sprintf.h
printf.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/proc/depend b/ext/-test-/proc/depend
index 45e12bcd09..97834db0a2 100644
--- a/ext/-test-/proc/depend
+++ b/ext/-test-/proc/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ receiver.o: $(hdrdir)/ruby/internal/intern/re.h
receiver.o: $(hdrdir)/ruby/internal/intern/ruby.h
receiver.o: $(hdrdir)/ruby/internal/intern/select.h
receiver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+receiver.o: $(hdrdir)/ruby/internal/intern/set.h
receiver.o: $(hdrdir)/ruby/internal/intern/signal.h
receiver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
receiver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ super.o: $(hdrdir)/ruby/internal/intern/re.h
super.o: $(hdrdir)/ruby/internal/intern/ruby.h
super.o: $(hdrdir)/ruby/internal/intern/select.h
super.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+super.o: $(hdrdir)/ruby/internal/intern/set.h
super.o: $(hdrdir)/ruby/internal/intern/signal.h
super.o: $(hdrdir)/ruby/internal/intern/sprintf.h
super.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/random/depend b/ext/-test-/random/depend
index 71f5f6e1e6..380c30fbe4 100644
--- a/ext/-test-/random/depend
+++ b/ext/-test-/random/depend
@@ -127,6 +127,7 @@ bad_version.o: $(hdrdir)/ruby/internal/intern/re.h
bad_version.o: $(hdrdir)/ruby/internal/intern/ruby.h
bad_version.o: $(hdrdir)/ruby/internal/intern/select.h
bad_version.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bad_version.o: $(hdrdir)/ruby/internal/intern/set.h
bad_version.o: $(hdrdir)/ruby/internal/intern/signal.h
bad_version.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bad_version.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -447,6 +449,7 @@ loop.o: $(hdrdir)/ruby/internal/intern/re.h
loop.o: $(hdrdir)/ruby/internal/intern/ruby.h
loop.o: $(hdrdir)/ruby/internal/intern/select.h
loop.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+loop.o: $(hdrdir)/ruby/internal/intern/set.h
loop.o: $(hdrdir)/ruby/internal/intern/signal.h
loop.o: $(hdrdir)/ruby/internal/intern/sprintf.h
loop.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/rational/depend b/ext/-test-/rational/depend
index 363d779302..56d6ab77d6 100644
--- a/ext/-test-/rational/depend
+++ b/ext/-test-/rational/depend
@@ -132,6 +132,7 @@ rat.o: $(hdrdir)/ruby/internal/intern/re.h
rat.o: $(hdrdir)/ruby/internal/intern/ruby.h
rat.o: $(hdrdir)/ruby/internal/intern/select.h
rat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rat.o: $(hdrdir)/ruby/internal/intern/set.h
rat.o: $(hdrdir)/ruby/internal/intern/signal.h
rat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rat.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/rb_call_super_kw/depend b/ext/-test-/rb_call_super_kw/depend
index 04a0fac12c..bf34323ca7 100644
--- a/ext/-test-/rb_call_super_kw/depend
+++ b/ext/-test-/rb_call_super_kw/depend
@@ -128,6 +128,7 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/re.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/select.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/set.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/recursion/depend b/ext/-test-/recursion/depend
index 2a65c98b09..b6487eb4df 100644
--- a/ext/-test-/recursion/depend
+++ b/ext/-test-/recursion/depend
@@ -128,6 +128,7 @@ recursion.o: $(hdrdir)/ruby/internal/intern/re.h
recursion.o: $(hdrdir)/ruby/internal/intern/ruby.h
recursion.o: $(hdrdir)/ruby/internal/intern/select.h
recursion.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+recursion.o: $(hdrdir)/ruby/internal/intern/set.h
recursion.o: $(hdrdir)/ruby/internal/intern/signal.h
recursion.o: $(hdrdir)/ruby/internal/intern/sprintf.h
recursion.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/regexp/depend b/ext/-test-/regexp/depend
index 0127a66a2e..5ba1b92f18 100644
--- a/ext/-test-/regexp/depend
+++ b/ext/-test-/regexp/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/re.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/ruby.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/select.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/set.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/signal.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/sprintf.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/sanitizers/depend b/ext/-test-/sanitizers/depend
new file mode 100644
index 0000000000..0e6e632803
--- /dev/null
+++ b/ext/-test-/sanitizers/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+sanitizers.o: $(RUBY_EXTCONF_H)
+sanitizers.o: $(arch_hdrdir)/ruby/config.h
+sanitizers.o: $(hdrdir)/ruby/assert.h
+sanitizers.o: $(hdrdir)/ruby/backward.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/assume.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/attributes.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/bool.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/inttypes.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/limits.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/long_long.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/stdalign.h
+sanitizers.o: $(hdrdir)/ruby/backward/2/stdarg.h
+sanitizers.o: $(hdrdir)/ruby/defines.h
+sanitizers.o: $(hdrdir)/ruby/intern.h
+sanitizers.o: $(hdrdir)/ruby/internal/abi.h
+sanitizers.o: $(hdrdir)/ruby/internal/anyargs.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+sanitizers.o: $(hdrdir)/ruby/internal/assume.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/artificial.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/cold.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/const.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/format.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noalias.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noinline.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/pure.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/restrict.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/warning.h
+sanitizers.o: $(hdrdir)/ruby/internal/attr/weakref.h
+sanitizers.o: $(hdrdir)/ruby/internal/cast.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+sanitizers.o: $(hdrdir)/ruby/internal/compiler_since.h
+sanitizers.o: $(hdrdir)/ruby/internal/config.h
+sanitizers.o: $(hdrdir)/ruby/internal/constant_p.h
+sanitizers.o: $(hdrdir)/ruby/internal/core.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rarray.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rbasic.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rbignum.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rclass.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rdata.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rfile.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rhash.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/robject.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rregexp.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rstring.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rstruct.h
+sanitizers.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+sanitizers.o: $(hdrdir)/ruby/internal/ctype.h
+sanitizers.o: $(hdrdir)/ruby/internal/dllexport.h
+sanitizers.o: $(hdrdir)/ruby/internal/dosish.h
+sanitizers.o: $(hdrdir)/ruby/internal/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/eval.h
+sanitizers.o: $(hdrdir)/ruby/internal/event.h
+sanitizers.o: $(hdrdir)/ruby/internal/fl_type.h
+sanitizers.o: $(hdrdir)/ruby/internal/gc.h
+sanitizers.o: $(hdrdir)/ruby/internal/glob.h
+sanitizers.o: $(hdrdir)/ruby/internal/globals.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/builtin.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/extension.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/feature.h
+sanitizers.o: $(hdrdir)/ruby/internal/has/warning.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/array.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/bignum.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/class.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/compar.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/complex.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/cont.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/dir.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/enum.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/error.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/eval.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/file.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/hash.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/io.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/load.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/marshal.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/numeric.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/object.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/parse.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/proc.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/process.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/random.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/range.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/rational.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/re.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/ruby.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/select.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/set.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/signal.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/string.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/struct.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/thread.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/time.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/variable.h
+sanitizers.o: $(hdrdir)/ruby/internal/intern/vm.h
+sanitizers.o: $(hdrdir)/ruby/internal/interpreter.h
+sanitizers.o: $(hdrdir)/ruby/internal/iterator.h
+sanitizers.o: $(hdrdir)/ruby/internal/memory.h
+sanitizers.o: $(hdrdir)/ruby/internal/method.h
+sanitizers.o: $(hdrdir)/ruby/internal/module.h
+sanitizers.o: $(hdrdir)/ruby/internal/newobj.h
+sanitizers.o: $(hdrdir)/ruby/internal/scan_args.h
+sanitizers.o: $(hdrdir)/ruby/internal/special_consts.h
+sanitizers.o: $(hdrdir)/ruby/internal/static_assert.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdalign.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdbool.h
+sanitizers.o: $(hdrdir)/ruby/internal/stdckdint.h
+sanitizers.o: $(hdrdir)/ruby/internal/symbol.h
+sanitizers.o: $(hdrdir)/ruby/internal/value.h
+sanitizers.o: $(hdrdir)/ruby/internal/value_type.h
+sanitizers.o: $(hdrdir)/ruby/internal/variable.h
+sanitizers.o: $(hdrdir)/ruby/internal/warning_push.h
+sanitizers.o: $(hdrdir)/ruby/internal/xmalloc.h
+sanitizers.o: $(hdrdir)/ruby/missing.h
+sanitizers.o: $(hdrdir)/ruby/ruby.h
+sanitizers.o: $(hdrdir)/ruby/st.h
+sanitizers.o: $(hdrdir)/ruby/subst.h
+sanitizers.o: sanitizers.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/sanitizers/extconf.rb b/ext/-test-/sanitizers/extconf.rb
new file mode 100644
index 0000000000..c94a96de6c
--- /dev/null
+++ b/ext/-test-/sanitizers/extconf.rb
@@ -0,0 +1,2 @@
+require 'mkmf'
+create_makefile('-test-/sanitizers')
diff --git a/ext/-test-/sanitizers/sanitizers.c b/ext/-test-/sanitizers/sanitizers.c
new file mode 100644
index 0000000000..97a85b26ef
--- /dev/null
+++ b/ext/-test-/sanitizers/sanitizers.c
@@ -0,0 +1,36 @@
+#include "ruby/ruby.h"
+
+static VALUE
+asan_enabled_p(VALUE self)
+{
+#if defined(__has_feature)
+ /* clang uses __has_feature for determining asan */
+ return __has_feature(address_sanitizer) ? Qtrue : Qfalse;
+#elif defined(__SANITIZE_ADDRESS__)
+ /* GCC sets __SANITIZE_ADDRESS__ for determining asan */
+ return Qtrue;
+#else
+ return Qfalse;
+#endif
+}
+
+static VALUE
+lsan_enabled_p(VALUE self)
+{
+#if defined(__has_feature)
+ /* clang uses __has_feature for determining LSAN */
+ return __has_feature(leak_sanitizer) ? Qtrue : Qfalse;
+#else
+ return Qfalse;
+#endif
+}
+
+void
+Init_sanitizers(void)
+{
+ VALUE m = rb_define_module("Test");
+ VALUE c = rb_define_class_under(m, "Sanitizers", rb_cObject);
+ rb_define_singleton_method(c, "asan_enabled?", asan_enabled_p, 0);
+ rb_define_singleton_method(c, "lsan_enabled?", lsan_enabled_p, 0);
+}
+
diff --git a/ext/-test-/scan_args/depend b/ext/-test-/scan_args/depend
index 922e5bbd5c..ca0fc19238 100644
--- a/ext/-test-/scan_args/depend
+++ b/ext/-test-/scan_args/depend
@@ -128,6 +128,7 @@ scan_args.o: $(hdrdir)/ruby/internal/intern/re.h
scan_args.o: $(hdrdir)/ruby/internal/intern/ruby.h
scan_args.o: $(hdrdir)/ruby/internal/intern/select.h
scan_args.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+scan_args.o: $(hdrdir)/ruby/internal/intern/set.h
scan_args.o: $(hdrdir)/ruby/internal/intern/signal.h
scan_args.o: $(hdrdir)/ruby/internal/intern/sprintf.h
scan_args.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/scheduler/extconf.rb b/ext/-test-/scheduler/extconf.rb
new file mode 100644
index 0000000000..159699bd8e
--- /dev/null
+++ b/ext/-test-/scheduler/extconf.rb
@@ -0,0 +1,2 @@
+# frozen_string_literal: false
+create_makefile("-test-/scheduler")
diff --git a/ext/-test-/scheduler/scheduler.c b/ext/-test-/scheduler/scheduler.c
new file mode 100644
index 0000000000..b742a5573b
--- /dev/null
+++ b/ext/-test-/scheduler/scheduler.c
@@ -0,0 +1,92 @@
+#include "ruby/ruby.h"
+#include "ruby/thread.h"
+#include "ruby/io.h"
+#include "ruby/fiber/scheduler.h"
+
+/*
+ * Test extension for reproducing the gRPC interrupt handling bug.
+ *
+ * This reproduces the exact issue from grpc/grpc commit 69f229e (June 2025):
+ * https://github.com/grpc/grpc/commit/69f229edd1d79ab7a7dfda98e3aef6fd807adcad
+ *
+ * The bug occurs when:
+ * 1. A fiber scheduler uses Thread.handle_interrupt(::SignalException => :never)
+ * (like Async::Scheduler does)
+ * 2. Native code uses rb_thread_call_without_gvl in a retry loop that checks
+ * the interrupted flag and retries (like gRPC's completion queue)
+ * 3. A signal (SIGINT/SIGTERM) is sent
+ * 4. The unblock_func sets interrupted=1, but Thread.handle_interrupt defers the signal
+ * 5. The loop sees interrupted=1 and retries without yielding to the scheduler
+ * 6. The deferred interrupt never gets processed -> infinite hang
+ *
+ * The fix is in vm_check_ints_blocking() in thread.c, which should yield to
+ * the fiber scheduler when interrupts are pending, allowing the scheduler to
+ * detect Thread.pending_interrupt? and exit its run loop.
+ */
+
+struct blocking_state {
+ int notify_descriptor;
+ volatile int interrupted;
+};
+
+static void
+unblock_callback(void *argument)
+{
+ struct blocking_state *blocking_state = (struct blocking_state *)argument;
+ blocking_state->interrupted = 1;
+}
+
+static void *
+blocking_operation(void *argument)
+{
+ struct blocking_state *blocking_state = (struct blocking_state *)argument;
+
+ ssize_t ret = write(blocking_state->notify_descriptor, "x", 1);
+ (void)ret; // ignore the result for now
+
+ while (!blocking_state->interrupted) {
+ struct timeval tv = {1, 0}; // 1 second timeout.
+ int result = select(0, NULL, NULL, NULL, &tv);
+
+ if (result == -1 && errno == EINTR) {
+ blocking_state->interrupted = 1;
+ }
+
+ // Otherwise, timeout -> loop again.
+ }
+
+ return NULL;
+}
+
+static VALUE
+scheduler_blocking_loop(VALUE self, VALUE notify)
+{
+ struct blocking_state blocking_state = {
+ .notify_descriptor = rb_io_descriptor(notify),
+ .interrupted = 0,
+ };
+
+ while (true) {
+ blocking_state.interrupted = 0;
+
+ rb_thread_call_without_gvl(
+ blocking_operation, &blocking_state,
+ unblock_callback, &blocking_state
+ );
+
+ // The bug: When interrupted, loop retries without yielding to scheduler.
+ // With Thread.handle_interrupt(:never), this causes an infinite hang,
+ // because the deferred interrupt never gets a chance to be processed.
+ } while (blocking_state.interrupted);
+
+ return Qnil;
+}
+
+void
+Init_scheduler(void)
+{
+ VALUE mBug = rb_define_module("Bug");
+ VALUE mScheduler = rb_define_module_under(mBug, "Scheduler");
+
+ rb_define_module_function(mScheduler, "blocking_loop", scheduler_blocking_loop, 1);
+}
diff --git a/ext/-test-/st/foreach/depend b/ext/-test-/st/foreach/depend
index 36273f8df8..29aab2bb29 100644
--- a/ext/-test-/st/foreach/depend
+++ b/ext/-test-/st/foreach/depend
@@ -128,6 +128,7 @@ foreach.o: $(hdrdir)/ruby/internal/intern/re.h
foreach.o: $(hdrdir)/ruby/internal/intern/ruby.h
foreach.o: $(hdrdir)/ruby/internal/intern/select.h
foreach.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+foreach.o: $(hdrdir)/ruby/internal/intern/set.h
foreach.o: $(hdrdir)/ruby/internal/intern/signal.h
foreach.o: $(hdrdir)/ruby/internal/intern/sprintf.h
foreach.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/st/numhash/depend b/ext/-test-/st/numhash/depend
index a0916183b6..18320d55f5 100644
--- a/ext/-test-/st/numhash/depend
+++ b/ext/-test-/st/numhash/depend
@@ -128,6 +128,7 @@ numhash.o: $(hdrdir)/ruby/internal/intern/re.h
numhash.o: $(hdrdir)/ruby/internal/intern/ruby.h
numhash.o: $(hdrdir)/ruby/internal/intern/select.h
numhash.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+numhash.o: $(hdrdir)/ruby/internal/intern/set.h
numhash.o: $(hdrdir)/ruby/internal/intern/signal.h
numhash.o: $(hdrdir)/ruby/internal/intern/sprintf.h
numhash.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/st/update/depend b/ext/-test-/st/update/depend
index 96ba194df0..247f0efd6b 100644
--- a/ext/-test-/st/update/depend
+++ b/ext/-test-/st/update/depend
@@ -128,6 +128,7 @@ update.o: $(hdrdir)/ruby/internal/intern/re.h
update.o: $(hdrdir)/ruby/internal/intern/ruby.h
update.o: $(hdrdir)/ruby/internal/intern/select.h
update.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+update.o: $(hdrdir)/ruby/internal/intern/set.h
update.o: $(hdrdir)/ruby/internal/intern/signal.h
update.o: $(hdrdir)/ruby/internal/intern/sprintf.h
update.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/stack/depend b/ext/-test-/stack/depend
new file mode 100644
index 0000000000..77e93bb201
--- /dev/null
+++ b/ext/-test-/stack/depend
@@ -0,0 +1,179 @@
+# AUTOGENERATED DEPENDENCIES START
+stack.o: $(RUBY_EXTCONF_H)
+stack.o: $(arch_hdrdir)/ruby/config.h
+stack.o: $(hdrdir)/ruby.h
+stack.o: $(hdrdir)/ruby/assert.h
+stack.o: $(hdrdir)/ruby/backward.h
+stack.o: $(hdrdir)/ruby/backward/2/assume.h
+stack.o: $(hdrdir)/ruby/backward/2/attributes.h
+stack.o: $(hdrdir)/ruby/backward/2/bool.h
+stack.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+stack.o: $(hdrdir)/ruby/backward/2/inttypes.h
+stack.o: $(hdrdir)/ruby/backward/2/limits.h
+stack.o: $(hdrdir)/ruby/backward/2/long_long.h
+stack.o: $(hdrdir)/ruby/backward/2/stdalign.h
+stack.o: $(hdrdir)/ruby/backward/2/stdarg.h
+stack.o: $(hdrdir)/ruby/defines.h
+stack.o: $(hdrdir)/ruby/encoding.h
+stack.o: $(hdrdir)/ruby/intern.h
+stack.o: $(hdrdir)/ruby/internal/abi.h
+stack.o: $(hdrdir)/ruby/internal/anyargs.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+stack.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+stack.o: $(hdrdir)/ruby/internal/assume.h
+stack.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+stack.o: $(hdrdir)/ruby/internal/attr/artificial.h
+stack.o: $(hdrdir)/ruby/internal/attr/cold.h
+stack.o: $(hdrdir)/ruby/internal/attr/const.h
+stack.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+stack.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+stack.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+stack.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+stack.o: $(hdrdir)/ruby/internal/attr/error.h
+stack.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+stack.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+stack.o: $(hdrdir)/ruby/internal/attr/format.h
+stack.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+stack.o: $(hdrdir)/ruby/internal/attr/noalias.h
+stack.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+stack.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+stack.o: $(hdrdir)/ruby/internal/attr/noinline.h
+stack.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+stack.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+stack.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+stack.o: $(hdrdir)/ruby/internal/attr/pure.h
+stack.o: $(hdrdir)/ruby/internal/attr/restrict.h
+stack.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+stack.o: $(hdrdir)/ruby/internal/attr/warning.h
+stack.o: $(hdrdir)/ruby/internal/attr/weakref.h
+stack.o: $(hdrdir)/ruby/internal/cast.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+stack.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+stack.o: $(hdrdir)/ruby/internal/compiler_since.h
+stack.o: $(hdrdir)/ruby/internal/config.h
+stack.o: $(hdrdir)/ruby/internal/constant_p.h
+stack.o: $(hdrdir)/ruby/internal/core.h
+stack.o: $(hdrdir)/ruby/internal/core/rarray.h
+stack.o: $(hdrdir)/ruby/internal/core/rbasic.h
+stack.o: $(hdrdir)/ruby/internal/core/rbignum.h
+stack.o: $(hdrdir)/ruby/internal/core/rclass.h
+stack.o: $(hdrdir)/ruby/internal/core/rdata.h
+stack.o: $(hdrdir)/ruby/internal/core/rfile.h
+stack.o: $(hdrdir)/ruby/internal/core/rhash.h
+stack.o: $(hdrdir)/ruby/internal/core/robject.h
+stack.o: $(hdrdir)/ruby/internal/core/rregexp.h
+stack.o: $(hdrdir)/ruby/internal/core/rstring.h
+stack.o: $(hdrdir)/ruby/internal/core/rstruct.h
+stack.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+stack.o: $(hdrdir)/ruby/internal/ctype.h
+stack.o: $(hdrdir)/ruby/internal/dllexport.h
+stack.o: $(hdrdir)/ruby/internal/dosish.h
+stack.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+stack.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+stack.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+stack.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+stack.o: $(hdrdir)/ruby/internal/encoding/re.h
+stack.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+stack.o: $(hdrdir)/ruby/internal/encoding/string.h
+stack.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+stack.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+stack.o: $(hdrdir)/ruby/internal/error.h
+stack.o: $(hdrdir)/ruby/internal/eval.h
+stack.o: $(hdrdir)/ruby/internal/event.h
+stack.o: $(hdrdir)/ruby/internal/fl_type.h
+stack.o: $(hdrdir)/ruby/internal/gc.h
+stack.o: $(hdrdir)/ruby/internal/glob.h
+stack.o: $(hdrdir)/ruby/internal/globals.h
+stack.o: $(hdrdir)/ruby/internal/has/attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/builtin.h
+stack.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+stack.o: $(hdrdir)/ruby/internal/has/extension.h
+stack.o: $(hdrdir)/ruby/internal/has/feature.h
+stack.o: $(hdrdir)/ruby/internal/has/warning.h
+stack.o: $(hdrdir)/ruby/internal/intern/array.h
+stack.o: $(hdrdir)/ruby/internal/intern/bignum.h
+stack.o: $(hdrdir)/ruby/internal/intern/class.h
+stack.o: $(hdrdir)/ruby/internal/intern/compar.h
+stack.o: $(hdrdir)/ruby/internal/intern/complex.h
+stack.o: $(hdrdir)/ruby/internal/intern/cont.h
+stack.o: $(hdrdir)/ruby/internal/intern/dir.h
+stack.o: $(hdrdir)/ruby/internal/intern/enum.h
+stack.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+stack.o: $(hdrdir)/ruby/internal/intern/error.h
+stack.o: $(hdrdir)/ruby/internal/intern/eval.h
+stack.o: $(hdrdir)/ruby/internal/intern/file.h
+stack.o: $(hdrdir)/ruby/internal/intern/hash.h
+stack.o: $(hdrdir)/ruby/internal/intern/io.h
+stack.o: $(hdrdir)/ruby/internal/intern/load.h
+stack.o: $(hdrdir)/ruby/internal/intern/marshal.h
+stack.o: $(hdrdir)/ruby/internal/intern/numeric.h
+stack.o: $(hdrdir)/ruby/internal/intern/object.h
+stack.o: $(hdrdir)/ruby/internal/intern/parse.h
+stack.o: $(hdrdir)/ruby/internal/intern/proc.h
+stack.o: $(hdrdir)/ruby/internal/intern/process.h
+stack.o: $(hdrdir)/ruby/internal/intern/random.h
+stack.o: $(hdrdir)/ruby/internal/intern/range.h
+stack.o: $(hdrdir)/ruby/internal/intern/rational.h
+stack.o: $(hdrdir)/ruby/internal/intern/re.h
+stack.o: $(hdrdir)/ruby/internal/intern/ruby.h
+stack.o: $(hdrdir)/ruby/internal/intern/select.h
+stack.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stack.o: $(hdrdir)/ruby/internal/intern/set.h
+stack.o: $(hdrdir)/ruby/internal/intern/signal.h
+stack.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+stack.o: $(hdrdir)/ruby/internal/intern/string.h
+stack.o: $(hdrdir)/ruby/internal/intern/struct.h
+stack.o: $(hdrdir)/ruby/internal/intern/thread.h
+stack.o: $(hdrdir)/ruby/internal/intern/time.h
+stack.o: $(hdrdir)/ruby/internal/intern/variable.h
+stack.o: $(hdrdir)/ruby/internal/intern/vm.h
+stack.o: $(hdrdir)/ruby/internal/interpreter.h
+stack.o: $(hdrdir)/ruby/internal/iterator.h
+stack.o: $(hdrdir)/ruby/internal/memory.h
+stack.o: $(hdrdir)/ruby/internal/method.h
+stack.o: $(hdrdir)/ruby/internal/module.h
+stack.o: $(hdrdir)/ruby/internal/newobj.h
+stack.o: $(hdrdir)/ruby/internal/scan_args.h
+stack.o: $(hdrdir)/ruby/internal/special_consts.h
+stack.o: $(hdrdir)/ruby/internal/static_assert.h
+stack.o: $(hdrdir)/ruby/internal/stdalign.h
+stack.o: $(hdrdir)/ruby/internal/stdbool.h
+stack.o: $(hdrdir)/ruby/internal/stdckdint.h
+stack.o: $(hdrdir)/ruby/internal/symbol.h
+stack.o: $(hdrdir)/ruby/internal/value.h
+stack.o: $(hdrdir)/ruby/internal/value_type.h
+stack.o: $(hdrdir)/ruby/internal/variable.h
+stack.o: $(hdrdir)/ruby/internal/warning_push.h
+stack.o: $(hdrdir)/ruby/internal/xmalloc.h
+stack.o: $(hdrdir)/ruby/missing.h
+stack.o: $(hdrdir)/ruby/onigmo.h
+stack.o: $(hdrdir)/ruby/oniguruma.h
+stack.o: $(hdrdir)/ruby/ruby.h
+stack.o: $(hdrdir)/ruby/st.h
+stack.o: $(hdrdir)/ruby/subst.h
+stack.o: $(top_srcdir)/encindex.h
+stack.o: $(top_srcdir)/internal/compilers.h
+stack.o: $(top_srcdir)/internal/string.h
+stack.o: stack.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/stack/stack.c b/ext/-test-/stack/stack.c
index 8ff32f9737..f0e65e74b2 100644
--- a/ext/-test-/stack/stack.c
+++ b/ext/-test-/stack/stack.c
@@ -2,7 +2,7 @@
#include "internal/string.h"
static VALUE
-stack_alloca_overflow(VALUE self)
+stack_overflow(VALUE self)
{
size_t i = 0;
@@ -30,6 +30,6 @@ asan_p(VALUE klass)
void
Init_stack(VALUE klass)
{
- rb_define_singleton_method(rb_cThread, "alloca_overflow", stack_alloca_overflow, 0);
+ rb_define_singleton_method(rb_cThread, "stack_overflow", stack_overflow, 0);
rb_define_singleton_method(rb_cThread, "asan?", asan_p, 0);
}
diff --git a/ext/-test-/string/depend b/ext/-test-/string/depend
index 044b6109ff..478ae3b82b 100644
--- a/ext/-test-/string/depend
+++ b/ext/-test-/string/depend
@@ -139,6 +139,7 @@ capacity.o: $(hdrdir)/ruby/internal/intern/re.h
capacity.o: $(hdrdir)/ruby/internal/intern/ruby.h
capacity.o: $(hdrdir)/ruby/internal/intern/select.h
capacity.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+capacity.o: $(hdrdir)/ruby/internal/intern/set.h
capacity.o: $(hdrdir)/ruby/internal/intern/signal.h
capacity.o: $(hdrdir)/ruby/internal/intern/sprintf.h
capacity.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -171,6 +172,7 @@ capacity.o: $(hdrdir)/ruby/oniguruma.h
capacity.o: $(hdrdir)/ruby/ruby.h
capacity.o: $(hdrdir)/ruby/st.h
capacity.o: $(hdrdir)/ruby/subst.h
+capacity.o: $(top_srcdir)/encindex.h
capacity.o: $(top_srcdir)/internal/compilers.h
capacity.o: $(top_srcdir)/internal/string.h
capacity.o: capacity.c
@@ -472,6 +474,7 @@ coderange.o: $(hdrdir)/ruby/internal/intern/re.h
coderange.o: $(hdrdir)/ruby/internal/intern/ruby.h
coderange.o: $(hdrdir)/ruby/internal/intern/select.h
coderange.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+coderange.o: $(hdrdir)/ruby/internal/intern/set.h
coderange.o: $(hdrdir)/ruby/internal/intern/signal.h
coderange.o: $(hdrdir)/ruby/internal/intern/sprintf.h
coderange.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -644,6 +647,7 @@ cstr.o: $(hdrdir)/ruby/internal/intern/re.h
cstr.o: $(hdrdir)/ruby/internal/intern/ruby.h
cstr.o: $(hdrdir)/ruby/internal/intern/select.h
cstr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+cstr.o: $(hdrdir)/ruby/internal/intern/set.h
cstr.o: $(hdrdir)/ruby/internal/intern/signal.h
cstr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
cstr.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -676,6 +680,7 @@ cstr.o: $(hdrdir)/ruby/oniguruma.h
cstr.o: $(hdrdir)/ruby/ruby.h
cstr.o: $(hdrdir)/ruby/st.h
cstr.o: $(hdrdir)/ruby/subst.h
+cstr.o: $(top_srcdir)/encindex.h
cstr.o: $(top_srcdir)/internal.h
cstr.o: $(top_srcdir)/internal/compilers.h
cstr.o: $(top_srcdir)/internal/string.h
@@ -809,6 +814,7 @@ ellipsize.o: $(hdrdir)/ruby/internal/intern/re.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/ruby.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/select.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ellipsize.o: $(hdrdir)/ruby/internal/intern/set.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/signal.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -979,6 +985,7 @@ enc_associate.o: $(hdrdir)/ruby/internal/intern/re.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/ruby.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/select.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enc_associate.o: $(hdrdir)/ruby/internal/intern/set.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/signal.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1151,6 +1158,7 @@ enc_dummy.o: $(hdrdir)/ruby/internal/intern/re.h
enc_dummy.o: $(hdrdir)/ruby/internal/intern/ruby.h
enc_dummy.o: $(hdrdir)/ruby/internal/intern/select.h
enc_dummy.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enc_dummy.o: $(hdrdir)/ruby/internal/intern/set.h
enc_dummy.o: $(hdrdir)/ruby/internal/intern/signal.h
enc_dummy.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enc_dummy.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1322,6 +1330,7 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/re.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/ruby.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/select.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/set.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/signal.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/sprintf.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1495,6 +1504,7 @@ fstring.o: $(hdrdir)/ruby/internal/intern/re.h
fstring.o: $(hdrdir)/ruby/internal/intern/ruby.h
fstring.o: $(hdrdir)/ruby/internal/intern/select.h
fstring.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+fstring.o: $(hdrdir)/ruby/internal/intern/set.h
fstring.o: $(hdrdir)/ruby/internal/intern/signal.h
fstring.o: $(hdrdir)/ruby/internal/intern/sprintf.h
fstring.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1527,6 +1537,7 @@ fstring.o: $(hdrdir)/ruby/oniguruma.h
fstring.o: $(hdrdir)/ruby/ruby.h
fstring.o: $(hdrdir)/ruby/st.h
fstring.o: $(hdrdir)/ruby/subst.h
+fstring.o: $(top_srcdir)/encindex.h
fstring.o: $(top_srcdir)/internal/compilers.h
fstring.o: $(top_srcdir)/internal/string.h
fstring.o: fstring.c
@@ -1659,6 +1670,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1819,6 +1831,7 @@ modify.o: $(hdrdir)/ruby/internal/intern/re.h
modify.o: $(hdrdir)/ruby/internal/intern/ruby.h
modify.o: $(hdrdir)/ruby/internal/intern/select.h
modify.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+modify.o: $(hdrdir)/ruby/internal/intern/set.h
modify.o: $(hdrdir)/ruby/internal/intern/signal.h
modify.o: $(hdrdir)/ruby/internal/intern/sprintf.h
modify.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1989,6 +2002,7 @@ new.o: $(hdrdir)/ruby/internal/intern/re.h
new.o: $(hdrdir)/ruby/internal/intern/ruby.h
new.o: $(hdrdir)/ruby/internal/intern/select.h
new.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+new.o: $(hdrdir)/ruby/internal/intern/set.h
new.o: $(hdrdir)/ruby/internal/intern/signal.h
new.o: $(hdrdir)/ruby/internal/intern/sprintf.h
new.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2151,6 +2165,7 @@ nofree.o: $(hdrdir)/ruby/internal/intern/re.h
nofree.o: $(hdrdir)/ruby/internal/intern/ruby.h
nofree.o: $(hdrdir)/ruby/internal/intern/select.h
nofree.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+nofree.o: $(hdrdir)/ruby/internal/intern/set.h
nofree.o: $(hdrdir)/ruby/internal/intern/signal.h
nofree.o: $(hdrdir)/ruby/internal/intern/sprintf.h
nofree.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2320,6 +2335,7 @@ normalize.o: $(hdrdir)/ruby/internal/intern/re.h
normalize.o: $(hdrdir)/ruby/internal/intern/ruby.h
normalize.o: $(hdrdir)/ruby/internal/intern/select.h
normalize.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+normalize.o: $(hdrdir)/ruby/internal/intern/set.h
normalize.o: $(hdrdir)/ruby/internal/intern/signal.h
normalize.o: $(hdrdir)/ruby/internal/intern/sprintf.h
normalize.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2493,6 +2509,7 @@ qsort.o: $(hdrdir)/ruby/internal/intern/re.h
qsort.o: $(hdrdir)/ruby/internal/intern/ruby.h
qsort.o: $(hdrdir)/ruby/internal/intern/select.h
qsort.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+qsort.o: $(hdrdir)/ruby/internal/intern/set.h
qsort.o: $(hdrdir)/ruby/internal/intern/signal.h
qsort.o: $(hdrdir)/ruby/internal/intern/sprintf.h
qsort.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2656,6 +2673,7 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/intern/re.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/select.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_interned_str.o: $(hdrdir)/ruby/internal/intern/set.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2816,6 +2834,7 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/intern/re.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/ruby.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/select.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rb_str_dup.o: $(hdrdir)/ruby/internal/intern/set.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/signal.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2976,6 +2995,7 @@ set_len.o: $(hdrdir)/ruby/internal/intern/re.h
set_len.o: $(hdrdir)/ruby/internal/intern/ruby.h
set_len.o: $(hdrdir)/ruby/internal/intern/select.h
set_len.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+set_len.o: $(hdrdir)/ruby/internal/intern/set.h
set_len.o: $(hdrdir)/ruby/internal/intern/signal.h
set_len.o: $(hdrdir)/ruby/internal/intern/sprintf.h
set_len.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/string/fstring.c b/ext/-test-/string/fstring.c
index 71c4b7f97e..0b5940f28c 100644
--- a/ext/-test-/string/fstring.c
+++ b/ext/-test-/string/fstring.c
@@ -12,20 +12,20 @@ VALUE
bug_s_fstring_fake_str(VALUE self)
{
static const char literal[] = "abcdefghijklmnopqrstuvwxyz";
- struct RString fake_str;
+ struct RString fake_str = {RBASIC_INIT};
return rb_str_to_interned_str(rb_setup_fake_str(&fake_str, literal, sizeof(literal) - 1, 0));
}
VALUE
bug_s_rb_enc_interned_str(VALUE self, VALUE encoding)
{
- return rb_enc_interned_str("foo", 3, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
+ return rb_enc_interned_str("foo", 3, NIL_P(encoding) ? NULL : RTYPEDDATA_GET_DATA(encoding));
}
VALUE
bug_s_rb_enc_str_new(VALUE self, VALUE encoding)
{
- return rb_enc_str_new("foo", 3, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
+ return rb_enc_str_new("foo", 3, NIL_P(encoding) ? NULL : RTYPEDDATA_GET_DATA(encoding));
}
void
diff --git a/ext/-test-/struct/depend b/ext/-test-/struct/depend
index 951dddd5dd..e2638e4cdf 100644
--- a/ext/-test-/struct/depend
+++ b/ext/-test-/struct/depend
@@ -128,6 +128,7 @@ data.o: $(hdrdir)/ruby/internal/intern/re.h
data.o: $(hdrdir)/ruby/internal/intern/ruby.h
data.o: $(hdrdir)/ruby/internal/intern/select.h
data.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+data.o: $(hdrdir)/ruby/internal/intern/set.h
data.o: $(hdrdir)/ruby/internal/intern/signal.h
data.o: $(hdrdir)/ruby/internal/intern/sprintf.h
data.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ duplicate.o: $(hdrdir)/ruby/internal/intern/re.h
duplicate.o: $(hdrdir)/ruby/internal/intern/ruby.h
duplicate.o: $(hdrdir)/ruby/internal/intern/select.h
duplicate.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+duplicate.o: $(hdrdir)/ruby/internal/intern/set.h
duplicate.o: $(hdrdir)/ruby/internal/intern/signal.h
duplicate.o: $(hdrdir)/ruby/internal/intern/sprintf.h
duplicate.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -448,6 +450,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -608,6 +611,7 @@ len.o: $(hdrdir)/ruby/internal/intern/re.h
len.o: $(hdrdir)/ruby/internal/intern/ruby.h
len.o: $(hdrdir)/ruby/internal/intern/select.h
len.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+len.o: $(hdrdir)/ruby/internal/intern/set.h
len.o: $(hdrdir)/ruby/internal/intern/signal.h
len.o: $(hdrdir)/ruby/internal/intern/sprintf.h
len.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -768,6 +772,7 @@ member.o: $(hdrdir)/ruby/internal/intern/re.h
member.o: $(hdrdir)/ruby/internal/intern/ruby.h
member.o: $(hdrdir)/ruby/internal/intern/select.h
member.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+member.o: $(hdrdir)/ruby/internal/intern/set.h
member.o: $(hdrdir)/ruby/internal/intern/signal.h
member.o: $(hdrdir)/ruby/internal/intern/sprintf.h
member.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/symbol/depend b/ext/-test-/symbol/depend
index 7c76596fdf..b1d8e1aab6 100644
--- a/ext/-test-/symbol/depend
+++ b/ext/-test-/symbol/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ type.o: $(hdrdir)/ruby/internal/intern/re.h
type.o: $(hdrdir)/ruby/internal/intern/ruby.h
type.o: $(hdrdir)/ruby/internal/intern/select.h
type.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+type.o: $(hdrdir)/ruby/internal/intern/set.h
type.o: $(hdrdir)/ruby/internal/intern/signal.h
type.o: $(hdrdir)/ruby/internal/intern/sprintf.h
type.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/thread/id/depend b/ext/-test-/thread/id/depend
new file mode 100644
index 0000000000..6b76b31ddc
--- /dev/null
+++ b/ext/-test-/thread/id/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+id.o: $(RUBY_EXTCONF_H)
+id.o: $(arch_hdrdir)/ruby/config.h
+id.o: $(hdrdir)/ruby.h
+id.o: $(hdrdir)/ruby/assert.h
+id.o: $(hdrdir)/ruby/backward.h
+id.o: $(hdrdir)/ruby/backward/2/assume.h
+id.o: $(hdrdir)/ruby/backward/2/attributes.h
+id.o: $(hdrdir)/ruby/backward/2/bool.h
+id.o: $(hdrdir)/ruby/backward/2/inttypes.h
+id.o: $(hdrdir)/ruby/backward/2/limits.h
+id.o: $(hdrdir)/ruby/backward/2/long_long.h
+id.o: $(hdrdir)/ruby/backward/2/stdalign.h
+id.o: $(hdrdir)/ruby/backward/2/stdarg.h
+id.o: $(hdrdir)/ruby/defines.h
+id.o: $(hdrdir)/ruby/intern.h
+id.o: $(hdrdir)/ruby/internal/abi.h
+id.o: $(hdrdir)/ruby/internal/anyargs.h
+id.o: $(hdrdir)/ruby/internal/arithmetic.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+id.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+id.o: $(hdrdir)/ruby/internal/assume.h
+id.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+id.o: $(hdrdir)/ruby/internal/attr/artificial.h
+id.o: $(hdrdir)/ruby/internal/attr/cold.h
+id.o: $(hdrdir)/ruby/internal/attr/const.h
+id.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+id.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+id.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+id.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+id.o: $(hdrdir)/ruby/internal/attr/error.h
+id.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+id.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+id.o: $(hdrdir)/ruby/internal/attr/format.h
+id.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+id.o: $(hdrdir)/ruby/internal/attr/noalias.h
+id.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+id.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+id.o: $(hdrdir)/ruby/internal/attr/noinline.h
+id.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+id.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+id.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+id.o: $(hdrdir)/ruby/internal/attr/pure.h
+id.o: $(hdrdir)/ruby/internal/attr/restrict.h
+id.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+id.o: $(hdrdir)/ruby/internal/attr/warning.h
+id.o: $(hdrdir)/ruby/internal/attr/weakref.h
+id.o: $(hdrdir)/ruby/internal/cast.h
+id.o: $(hdrdir)/ruby/internal/compiler_is.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+id.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+id.o: $(hdrdir)/ruby/internal/compiler_since.h
+id.o: $(hdrdir)/ruby/internal/config.h
+id.o: $(hdrdir)/ruby/internal/constant_p.h
+id.o: $(hdrdir)/ruby/internal/core.h
+id.o: $(hdrdir)/ruby/internal/core/rarray.h
+id.o: $(hdrdir)/ruby/internal/core/rbasic.h
+id.o: $(hdrdir)/ruby/internal/core/rbignum.h
+id.o: $(hdrdir)/ruby/internal/core/rclass.h
+id.o: $(hdrdir)/ruby/internal/core/rdata.h
+id.o: $(hdrdir)/ruby/internal/core/rfile.h
+id.o: $(hdrdir)/ruby/internal/core/rhash.h
+id.o: $(hdrdir)/ruby/internal/core/robject.h
+id.o: $(hdrdir)/ruby/internal/core/rregexp.h
+id.o: $(hdrdir)/ruby/internal/core/rstring.h
+id.o: $(hdrdir)/ruby/internal/core/rstruct.h
+id.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+id.o: $(hdrdir)/ruby/internal/ctype.h
+id.o: $(hdrdir)/ruby/internal/dllexport.h
+id.o: $(hdrdir)/ruby/internal/dosish.h
+id.o: $(hdrdir)/ruby/internal/error.h
+id.o: $(hdrdir)/ruby/internal/eval.h
+id.o: $(hdrdir)/ruby/internal/event.h
+id.o: $(hdrdir)/ruby/internal/fl_type.h
+id.o: $(hdrdir)/ruby/internal/gc.h
+id.o: $(hdrdir)/ruby/internal/glob.h
+id.o: $(hdrdir)/ruby/internal/globals.h
+id.o: $(hdrdir)/ruby/internal/has/attribute.h
+id.o: $(hdrdir)/ruby/internal/has/builtin.h
+id.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+id.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+id.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+id.o: $(hdrdir)/ruby/internal/has/extension.h
+id.o: $(hdrdir)/ruby/internal/has/feature.h
+id.o: $(hdrdir)/ruby/internal/has/warning.h
+id.o: $(hdrdir)/ruby/internal/intern/array.h
+id.o: $(hdrdir)/ruby/internal/intern/bignum.h
+id.o: $(hdrdir)/ruby/internal/intern/class.h
+id.o: $(hdrdir)/ruby/internal/intern/compar.h
+id.o: $(hdrdir)/ruby/internal/intern/complex.h
+id.o: $(hdrdir)/ruby/internal/intern/cont.h
+id.o: $(hdrdir)/ruby/internal/intern/dir.h
+id.o: $(hdrdir)/ruby/internal/intern/enum.h
+id.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+id.o: $(hdrdir)/ruby/internal/intern/error.h
+id.o: $(hdrdir)/ruby/internal/intern/eval.h
+id.o: $(hdrdir)/ruby/internal/intern/file.h
+id.o: $(hdrdir)/ruby/internal/intern/hash.h
+id.o: $(hdrdir)/ruby/internal/intern/io.h
+id.o: $(hdrdir)/ruby/internal/intern/load.h
+id.o: $(hdrdir)/ruby/internal/intern/marshal.h
+id.o: $(hdrdir)/ruby/internal/intern/numeric.h
+id.o: $(hdrdir)/ruby/internal/intern/object.h
+id.o: $(hdrdir)/ruby/internal/intern/parse.h
+id.o: $(hdrdir)/ruby/internal/intern/proc.h
+id.o: $(hdrdir)/ruby/internal/intern/process.h
+id.o: $(hdrdir)/ruby/internal/intern/random.h
+id.o: $(hdrdir)/ruby/internal/intern/range.h
+id.o: $(hdrdir)/ruby/internal/intern/rational.h
+id.o: $(hdrdir)/ruby/internal/intern/re.h
+id.o: $(hdrdir)/ruby/internal/intern/ruby.h
+id.o: $(hdrdir)/ruby/internal/intern/select.h
+id.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+id.o: $(hdrdir)/ruby/internal/intern/set.h
+id.o: $(hdrdir)/ruby/internal/intern/signal.h
+id.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+id.o: $(hdrdir)/ruby/internal/intern/string.h
+id.o: $(hdrdir)/ruby/internal/intern/struct.h
+id.o: $(hdrdir)/ruby/internal/intern/thread.h
+id.o: $(hdrdir)/ruby/internal/intern/time.h
+id.o: $(hdrdir)/ruby/internal/intern/variable.h
+id.o: $(hdrdir)/ruby/internal/intern/vm.h
+id.o: $(hdrdir)/ruby/internal/interpreter.h
+id.o: $(hdrdir)/ruby/internal/iterator.h
+id.o: $(hdrdir)/ruby/internal/memory.h
+id.o: $(hdrdir)/ruby/internal/method.h
+id.o: $(hdrdir)/ruby/internal/module.h
+id.o: $(hdrdir)/ruby/internal/newobj.h
+id.o: $(hdrdir)/ruby/internal/scan_args.h
+id.o: $(hdrdir)/ruby/internal/special_consts.h
+id.o: $(hdrdir)/ruby/internal/static_assert.h
+id.o: $(hdrdir)/ruby/internal/stdalign.h
+id.o: $(hdrdir)/ruby/internal/stdbool.h
+id.o: $(hdrdir)/ruby/internal/stdckdint.h
+id.o: $(hdrdir)/ruby/internal/symbol.h
+id.o: $(hdrdir)/ruby/internal/value.h
+id.o: $(hdrdir)/ruby/internal/value_type.h
+id.o: $(hdrdir)/ruby/internal/variable.h
+id.o: $(hdrdir)/ruby/internal/warning_push.h
+id.o: $(hdrdir)/ruby/internal/xmalloc.h
+id.o: $(hdrdir)/ruby/missing.h
+id.o: $(hdrdir)/ruby/ruby.h
+id.o: $(hdrdir)/ruby/st.h
+id.o: $(hdrdir)/ruby/subst.h
+id.o: id.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/thread/instrumentation/depend b/ext/-test-/thread/instrumentation/depend
index a37e4d5675..63e1c7e44f 100644
--- a/ext/-test-/thread/instrumentation/depend
+++ b/ext/-test-/thread/instrumentation/depend
@@ -128,6 +128,7 @@ instrumentation.o: $(hdrdir)/ruby/internal/intern/re.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/ruby.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/select.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+instrumentation.o: $(hdrdir)/ruby/internal/intern/set.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/signal.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/sprintf.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/thread/lock_native_thread/depend b/ext/-test-/thread/lock_native_thread/depend
new file mode 100644
index 0000000000..a32843e531
--- /dev/null
+++ b/ext/-test-/thread/lock_native_thread/depend
@@ -0,0 +1,163 @@
+# AUTOGENERATED DEPENDENCIES START
+lock_native_thread.o: $(RUBY_EXTCONF_H)
+lock_native_thread.o: $(arch_hdrdir)/ruby/config.h
+lock_native_thread.o: $(hdrdir)/ruby/assert.h
+lock_native_thread.o: $(hdrdir)/ruby/backward.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/assume.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/attributes.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/bool.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/inttypes.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/limits.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/long_long.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/stdalign.h
+lock_native_thread.o: $(hdrdir)/ruby/backward/2/stdarg.h
+lock_native_thread.o: $(hdrdir)/ruby/defines.h
+lock_native_thread.o: $(hdrdir)/ruby/intern.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/abi.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/anyargs.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/assume.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/artificial.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/cold.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/const.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/error.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/format.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noalias.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noinline.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/pure.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/restrict.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/warning.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/attr/weakref.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/cast.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/compiler_since.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/config.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/constant_p.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rarray.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rbasic.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rbignum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rclass.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rdata.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rfile.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rhash.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/robject.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rregexp.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rstring.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rstruct.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/ctype.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/dllexport.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/dosish.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/error.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/eval.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/event.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/fl_type.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/gc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/glob.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/globals.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/builtin.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/extension.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/feature.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/has/warning.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/array.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/bignum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/class.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/compar.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/complex.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/cont.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/dir.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/enum.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/error.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/eval.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/file.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/hash.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/io.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/load.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/marshal.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/numeric.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/object.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/parse.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/proc.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/process.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/random.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/range.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/rational.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/re.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/ruby.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/select.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/set.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/signal.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/string.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/struct.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/thread.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/time.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/variable.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/intern/vm.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/interpreter.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/iterator.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/memory.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/method.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/module.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/newobj.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/scan_args.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/special_consts.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/static_assert.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/stdalign.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/stdbool.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/stdckdint.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/symbol.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/value.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/value_type.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/variable.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/warning_push.h
+lock_native_thread.o: $(hdrdir)/ruby/internal/xmalloc.h
+lock_native_thread.o: $(hdrdir)/ruby/missing.h
+lock_native_thread.o: $(hdrdir)/ruby/ruby.h
+lock_native_thread.o: $(hdrdir)/ruby/st.h
+lock_native_thread.o: $(hdrdir)/ruby/subst.h
+lock_native_thread.o: $(hdrdir)/ruby/thread.h
+lock_native_thread.o: lock_native_thread.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/thread_fd/depend b/ext/-test-/thread_fd/depend
deleted file mode 100644
index 0fda9f6dbf..0000000000
--- a/ext/-test-/thread_fd/depend
+++ /dev/null
@@ -1,161 +0,0 @@
-# AUTOGENERATED DEPENDENCIES START
-thread_fd.o: $(RUBY_EXTCONF_H)
-thread_fd.o: $(arch_hdrdir)/ruby/config.h
-thread_fd.o: $(hdrdir)/ruby/assert.h
-thread_fd.o: $(hdrdir)/ruby/backward.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/assume.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/attributes.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/bool.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/inttypes.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/limits.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/long_long.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/stdalign.h
-thread_fd.o: $(hdrdir)/ruby/backward/2/stdarg.h
-thread_fd.o: $(hdrdir)/ruby/defines.h
-thread_fd.o: $(hdrdir)/ruby/intern.h
-thread_fd.o: $(hdrdir)/ruby/internal/abi.h
-thread_fd.o: $(hdrdir)/ruby/internal/anyargs.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-thread_fd.o: $(hdrdir)/ruby/internal/assume.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/artificial.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/cold.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/const.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/error.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/format.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/noalias.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/noinline.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/pure.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/restrict.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/warning.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/weakref.h
-thread_fd.o: $(hdrdir)/ruby/internal/cast.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-thread_fd.o: $(hdrdir)/ruby/internal/compiler_since.h
-thread_fd.o: $(hdrdir)/ruby/internal/config.h
-thread_fd.o: $(hdrdir)/ruby/internal/constant_p.h
-thread_fd.o: $(hdrdir)/ruby/internal/core.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rarray.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rbasic.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rbignum.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rclass.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rdata.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rfile.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rhash.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/robject.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rregexp.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rstring.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rstruct.h
-thread_fd.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-thread_fd.o: $(hdrdir)/ruby/internal/ctype.h
-thread_fd.o: $(hdrdir)/ruby/internal/dllexport.h
-thread_fd.o: $(hdrdir)/ruby/internal/dosish.h
-thread_fd.o: $(hdrdir)/ruby/internal/error.h
-thread_fd.o: $(hdrdir)/ruby/internal/eval.h
-thread_fd.o: $(hdrdir)/ruby/internal/event.h
-thread_fd.o: $(hdrdir)/ruby/internal/fl_type.h
-thread_fd.o: $(hdrdir)/ruby/internal/gc.h
-thread_fd.o: $(hdrdir)/ruby/internal/glob.h
-thread_fd.o: $(hdrdir)/ruby/internal/globals.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/builtin.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/extension.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/feature.h
-thread_fd.o: $(hdrdir)/ruby/internal/has/warning.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/array.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/bignum.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/class.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/compar.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/complex.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/cont.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/dir.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/enum.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/error.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/eval.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/file.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/hash.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/io.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/load.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/marshal.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/numeric.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/object.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/parse.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/proc.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/process.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/random.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/range.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/rational.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/re.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/ruby.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/select.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/signal.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/string.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/struct.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/thread.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/time.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/variable.h
-thread_fd.o: $(hdrdir)/ruby/internal/intern/vm.h
-thread_fd.o: $(hdrdir)/ruby/internal/interpreter.h
-thread_fd.o: $(hdrdir)/ruby/internal/iterator.h
-thread_fd.o: $(hdrdir)/ruby/internal/memory.h
-thread_fd.o: $(hdrdir)/ruby/internal/method.h
-thread_fd.o: $(hdrdir)/ruby/internal/module.h
-thread_fd.o: $(hdrdir)/ruby/internal/newobj.h
-thread_fd.o: $(hdrdir)/ruby/internal/scan_args.h
-thread_fd.o: $(hdrdir)/ruby/internal/special_consts.h
-thread_fd.o: $(hdrdir)/ruby/internal/static_assert.h
-thread_fd.o: $(hdrdir)/ruby/internal/stdalign.h
-thread_fd.o: $(hdrdir)/ruby/internal/stdbool.h
-thread_fd.o: $(hdrdir)/ruby/internal/stdckdint.h
-thread_fd.o: $(hdrdir)/ruby/internal/symbol.h
-thread_fd.o: $(hdrdir)/ruby/internal/value.h
-thread_fd.o: $(hdrdir)/ruby/internal/value_type.h
-thread_fd.o: $(hdrdir)/ruby/internal/variable.h
-thread_fd.o: $(hdrdir)/ruby/internal/warning_push.h
-thread_fd.o: $(hdrdir)/ruby/internal/xmalloc.h
-thread_fd.o: $(hdrdir)/ruby/missing.h
-thread_fd.o: $(hdrdir)/ruby/ruby.h
-thread_fd.o: $(hdrdir)/ruby/st.h
-thread_fd.o: $(hdrdir)/ruby/subst.h
-thread_fd.o: thread_fd.c
-# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/thread_fd/extconf.rb b/ext/-test-/thread_fd/extconf.rb
deleted file mode 100644
index a8bbe9d169..0000000000
--- a/ext/-test-/thread_fd/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-# frozen_string_literal: true
-create_makefile('-test-/thread_fd')
diff --git a/ext/-test-/thread_fd/thread_fd.c b/ext/-test-/thread_fd/thread_fd.c
deleted file mode 100644
index 042b799dc8..0000000000
--- a/ext/-test-/thread_fd/thread_fd.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "ruby/ruby.h"
-
-static VALUE
-thread_fd_close(VALUE ign, VALUE fd)
-{
- rb_thread_fd_close(NUM2INT(fd));
- return Qnil;
-}
-
-static VALUE
-thread_fd_wait(VALUE ign, VALUE fd)
-{
- int ret = rb_thread_wait_fd(NUM2INT(fd));
- return INT2NUM(ret);
-}
-
-static VALUE
-thread_fd_writable(VALUE ign, VALUE fd)
-{
- int ret = rb_thread_fd_writable(NUM2INT(fd));
- return INT2NUM(ret);
-}
-
-void
-Init_thread_fd(void)
-{
- rb_define_singleton_method(rb_cIO, "thread_fd_close", thread_fd_close, 1);
- rb_define_singleton_method(rb_cIO, "thread_fd_wait", thread_fd_wait, 1);
- rb_define_singleton_method(rb_cIO, "thread_fd_writable", thread_fd_writable, 1);
-}
diff --git a/ext/-test-/time/depend b/ext/-test-/time/depend
index 5ed791bcc5..e5b05f3113 100644
--- a/ext/-test-/time/depend
+++ b/ext/-test-/time/depend
@@ -128,6 +128,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -289,6 +290,7 @@ leap_second.o: $(hdrdir)/ruby/internal/intern/re.h
leap_second.o: $(hdrdir)/ruby/internal/intern/ruby.h
leap_second.o: $(hdrdir)/ruby/internal/intern/select.h
leap_second.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+leap_second.o: $(hdrdir)/ruby/internal/intern/set.h
leap_second.o: $(hdrdir)/ruby/internal/intern/signal.h
leap_second.o: $(hdrdir)/ruby/internal/intern/sprintf.h
leap_second.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -453,6 +455,7 @@ new.o: $(hdrdir)/ruby/internal/intern/re.h
new.o: $(hdrdir)/ruby/internal/intern/ruby.h
new.o: $(hdrdir)/ruby/internal/intern/select.h
new.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+new.o: $(hdrdir)/ruby/internal/intern/set.h
new.o: $(hdrdir)/ruby/internal/intern/signal.h
new.o: $(hdrdir)/ruby/internal/intern/sprintf.h
new.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/time/leap_second.c b/ext/-test-/time/leap_second.c
deleted file mode 100644
index ee7011fa97..0000000000
--- a/ext/-test-/time/leap_second.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "ruby.h"
-#include "internal/time.h"
-
-static VALUE
-bug_time_s_reset_leap_second_info(VALUE klass)
-{
- ruby_reset_leap_second_info();
- return Qnil;
-}
-
-void
-Init_time_leap_second(VALUE klass)
-{
- rb_define_singleton_method(klass, "reset_leap_second_info", bug_time_s_reset_leap_second_info, 0);
-}
diff --git a/ext/-test-/tracepoint/depend b/ext/-test-/tracepoint/depend
index 133663b3bd..014ba83b16 100644
--- a/ext/-test-/tracepoint/depend
+++ b/ext/-test-/tracepoint/depend
@@ -128,6 +128,7 @@ gc_hook.o: $(hdrdir)/ruby/internal/intern/re.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/ruby.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/select.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+gc_hook.o: $(hdrdir)/ruby/internal/intern/set.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/signal.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/sprintf.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -288,6 +289,7 @@ tracepoint.o: $(hdrdir)/ruby/internal/intern/re.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/ruby.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/select.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tracepoint.o: $(hdrdir)/ruby/internal/intern/set.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/signal.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/tracepoint/gc_hook.c b/ext/-test-/tracepoint/gc_hook.c
index 54c06c54a5..525be6da63 100644
--- a/ext/-test-/tracepoint/gc_hook.c
+++ b/ext/-test-/tracepoint/gc_hook.c
@@ -2,6 +2,7 @@
#include "ruby/debug.h"
static int invoking; /* TODO: should not be global variable */
+extern VALUE tp_mBug;
static VALUE
invoke_proc_ensure(VALUE _)
@@ -17,9 +18,9 @@ invoke_proc_begin(VALUE proc)
}
static void
-invoke_proc(void *data)
+invoke_proc(void *ivar_name)
{
- VALUE proc = (VALUE)data;
+ VALUE proc = rb_ivar_get(tp_mBug, rb_intern(ivar_name));
invoking += 1;
rb_ensure(invoke_proc_begin, proc, invoke_proc_ensure, 0);
}
@@ -40,16 +41,16 @@ gc_start_end_i(VALUE tpval, void *data)
}
static VALUE
-set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
+set_gc_hook(VALUE proc, rb_event_flag_t event, const char *tp_str, const char *proc_str)
{
VALUE tpval;
ID tp_key = rb_intern(tp_str);
/* disable previous keys */
- if (rb_ivar_defined(module, tp_key) != 0 &&
- RTEST(tpval = rb_ivar_get(module, tp_key))) {
+ if (rb_ivar_defined(tp_mBug, tp_key) != 0 &&
+ RTEST(tpval = rb_ivar_get(tp_mBug, tp_key))) {
rb_tracepoint_disable(tpval);
- rb_ivar_set(module, tp_key, Qnil);
+ rb_ivar_set(tp_mBug, tp_key, Qnil);
}
if (RTEST(proc)) {
@@ -57,8 +58,9 @@ set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str,
rb_raise(rb_eTypeError, "trace_func needs to be Proc");
}
- tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc);
- rb_ivar_set(module, tp_key, tpval);
+ rb_ivar_set(tp_mBug, rb_intern(proc_str), proc);
+ tpval = rb_tracepoint_new(0, event, gc_start_end_i, (void *)proc_str);
+ rb_ivar_set(tp_mBug, tp_key, tpval);
rb_tracepoint_enable(tpval);
}
@@ -66,16 +68,16 @@ set_gc_hook(VALUE module, VALUE proc, rb_event_flag_t event, const char *tp_str,
}
static VALUE
-set_after_gc_start(VALUE module, VALUE proc)
+set_after_gc_start(VALUE _self, VALUE proc)
{
- return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_START,
+ return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_START,
"__set_after_gc_start_tpval__", "__set_after_gc_start_proc__");
}
static VALUE
-start_after_gc_exit(VALUE module, VALUE proc)
+start_after_gc_exit(VALUE _self, VALUE proc)
{
- return set_gc_hook(module, proc, RUBY_INTERNAL_EVENT_GC_EXIT,
+ return set_gc_hook(proc, RUBY_INTERNAL_EVENT_GC_EXIT,
"__set_after_gc_exit_tpval__", "__set_after_gc_exit_proc__");
}
diff --git a/ext/-test-/tracepoint/tracepoint.c b/ext/-test-/tracepoint/tracepoint.c
index 2826cc038c..001d9513b2 100644
--- a/ext/-test-/tracepoint/tracepoint.c
+++ b/ext/-test-/tracepoint/tracepoint.c
@@ -1,6 +1,8 @@
#include "ruby/ruby.h"
#include "ruby/debug.h"
+VALUE tp_mBug;
+
struct tracepoint_track {
size_t newobj_count;
size_t free_count;
@@ -89,8 +91,8 @@ void Init_gc_hook(VALUE);
void
Init_tracepoint(void)
{
- VALUE mBug = rb_define_module("Bug");
- Init_gc_hook(mBug);
- rb_define_module_function(mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
- rb_define_module_function(mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
+ tp_mBug = rb_define_module("Bug"); // GC root
+ Init_gc_hook(tp_mBug);
+ rb_define_module_function(tp_mBug, "tracepoint_track_objspace_events", tracepoint_track_objspace_events, 0);
+ rb_define_module_function(tp_mBug, "tracepoint_specify_normal_and_internal_events", tracepoint_specify_normal_and_internal_events, 0);
}
diff --git a/ext/-test-/typeddata/depend b/ext/-test-/typeddata/depend
index 6c0847c82d..b9b4915eee 100644
--- a/ext/-test-/typeddata/depend
+++ b/ext/-test-/typeddata/depend
@@ -128,6 +128,7 @@ typeddata.o: $(hdrdir)/ruby/internal/intern/re.h
typeddata.o: $(hdrdir)/ruby/internal/intern/ruby.h
typeddata.o: $(hdrdir)/ruby/internal/intern/select.h
typeddata.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+typeddata.o: $(hdrdir)/ruby/internal/intern/set.h
typeddata.o: $(hdrdir)/ruby/internal/intern/signal.h
typeddata.o: $(hdrdir)/ruby/internal/intern/sprintf.h
typeddata.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/vm/depend b/ext/-test-/vm/depend
index 422b40a32d..9313f2ee36 100644
--- a/ext/-test-/vm/depend
+++ b/ext/-test-/vm/depend
@@ -127,6 +127,7 @@ at_exit.o: $(hdrdir)/ruby/internal/intern/re.h
at_exit.o: $(hdrdir)/ruby/internal/intern/ruby.h
at_exit.o: $(hdrdir)/ruby/internal/intern/select.h
at_exit.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+at_exit.o: $(hdrdir)/ruby/internal/intern/set.h
at_exit.o: $(hdrdir)/ruby/internal/intern/signal.h
at_exit.o: $(hdrdir)/ruby/internal/intern/sprintf.h
at_exit.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/-test-/wait/depend b/ext/-test-/wait/depend
index 7997a16709..f793d84831 100644
--- a/ext/-test-/wait/depend
+++ b/ext/-test-/wait/depend
@@ -137,6 +137,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/re.h
wait.o: $(hdrdir)/ruby/internal/intern/ruby.h
wait.o: $(hdrdir)/ruby/internal/intern/select.h
wait.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+wait.o: $(hdrdir)/ruby/internal/intern/set.h
wait.o: $(hdrdir)/ruby/internal/intern/signal.h
wait.o: $(hdrdir)/ruby/internal/intern/sprintf.h
wait.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/.document b/ext/.document
index 0efd511a61..374abe6580 100644
--- a/ext/.document
+++ b/ext/.document
@@ -76,8 +76,6 @@ openssl/ossl_x509name.c
openssl/ossl_x509req.c
openssl/ossl_x509revoked.c
openssl/ossl_x509store.c
-pathname/lib
-pathname/pathname.c
psych/lib
psych/psych.c
psych/psych_emitter.c
@@ -92,6 +90,7 @@ readline/readline.c
ripper/lib
socket
stringio/stringio.c
+strscan/lib
strscan/strscan.c
syslog/syslog.c
syslog/lib
diff --git a/ext/cgi/escape/depend b/ext/cgi/escape/depend
index 746b47246a..05b59bfdea 100644
--- a/ext/cgi/escape/depend
+++ b/ext/cgi/escape/depend
@@ -138,6 +138,7 @@ escape.o: $(hdrdir)/ruby/internal/intern/re.h
escape.o: $(hdrdir)/ruby/internal/intern/ruby.h
escape.o: $(hdrdir)/ruby/internal/intern/select.h
escape.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+escape.o: $(hdrdir)/ruby/internal/intern/set.h
escape.o: $(hdrdir)/ruby/internal/intern/signal.h
escape.o: $(hdrdir)/ruby/internal/intern/sprintf.h
escape.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c
index 495ad83aa3..4773186603 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -8,7 +8,7 @@ RUBY_EXTERN const signed char ruby_digit36_to_number_table[];
#define upper_hexdigits (ruby_hexdigits+16)
#define char_to_number(c) ruby_digit36_to_number_table[(unsigned char)(c)]
-static VALUE rb_cCGI, rb_mUtil, rb_mEscape;
+static VALUE rb_cCGI, rb_mEscape, rb_mEscapeExt;
static ID id_accept_charset;
#define HTML_ESCAPE_MAX_LEN 6
@@ -45,6 +45,7 @@ escaped_length(VALUE str)
static VALUE
optimized_escape_html(VALUE str)
{
+ VALUE escaped;
VALUE vbuf;
char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
const char *cstr = RSTRING_PTR(str);
@@ -63,7 +64,6 @@ optimized_escape_html(VALUE str)
}
}
- VALUE escaped;
if (RSTRING_LEN(str) < (dest - buf)) {
escaped = rb_str_new(buf, dest - buf);
preserve_original_state(str, escaped);
@@ -471,17 +471,17 @@ Init_escape(void)
void
InitVM_escape(void)
{
- rb_cCGI = rb_define_class("CGI", rb_cObject);
- rb_mEscape = rb_define_module_under(rb_cCGI, "Escape");
- rb_mUtil = rb_define_module_under(rb_cCGI, "Util");
- rb_define_method(rb_mEscape, "escapeHTML", cgiesc_escape_html, 1);
- rb_define_method(rb_mEscape, "unescapeHTML", cgiesc_unescape_html, 1);
- rb_define_method(rb_mEscape, "escapeURIComponent", cgiesc_escape_uri_component, 1);
- rb_define_alias(rb_mEscape, "escape_uri_component", "escapeURIComponent");
- rb_define_method(rb_mEscape, "unescapeURIComponent", cgiesc_unescape_uri_component, -1);
- rb_define_alias(rb_mEscape, "unescape_uri_component", "unescapeURIComponent");
- rb_define_method(rb_mEscape, "escape", cgiesc_escape, 1);
- rb_define_method(rb_mEscape, "unescape", cgiesc_unescape, -1);
- rb_prepend_module(rb_mUtil, rb_mEscape);
- rb_extend_object(rb_cCGI, rb_mEscape);
+ rb_cCGI = rb_define_class("CGI", rb_cObject);
+ rb_mEscapeExt = rb_define_module_under(rb_cCGI, "EscapeExt");
+ rb_mEscape = rb_define_module_under(rb_cCGI, "Escape");
+ rb_define_method(rb_mEscapeExt, "escapeHTML", cgiesc_escape_html, 1);
+ rb_define_method(rb_mEscapeExt, "unescapeHTML", cgiesc_unescape_html, 1);
+ rb_define_method(rb_mEscapeExt, "escapeURIComponent", cgiesc_escape_uri_component, 1);
+ rb_define_alias(rb_mEscapeExt, "escape_uri_component", "escapeURIComponent");
+ rb_define_method(rb_mEscapeExt, "unescapeURIComponent", cgiesc_unescape_uri_component, -1);
+ rb_define_alias(rb_mEscapeExt, "unescape_uri_component", "unescapeURIComponent");
+ rb_define_method(rb_mEscapeExt, "escape", cgiesc_escape, 1);
+ rb_define_method(rb_mEscapeExt, "unescape", cgiesc_unescape, -1);
+ rb_prepend_module(rb_mEscape, rb_mEscapeExt);
+ rb_extend_object(rb_cCGI, rb_mEscapeExt);
}
diff --git a/ext/continuation/depend b/ext/continuation/depend
index b40e52e29b..b395d3d4d7 100644
--- a/ext/continuation/depend
+++ b/ext/continuation/depend
@@ -127,6 +127,7 @@ continuation.o: $(hdrdir)/ruby/internal/intern/re.h
continuation.o: $(hdrdir)/ruby/internal/intern/ruby.h
continuation.o: $(hdrdir)/ruby/internal/intern/select.h
continuation.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+continuation.o: $(hdrdir)/ruby/internal/intern/set.h
continuation.o: $(hdrdir)/ruby/internal/intern/signal.h
continuation.o: $(hdrdir)/ruby/internal/intern/sprintf.h
continuation.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c
index 1519b559cd..747f065fba 100644
--- a/ext/coverage/coverage.c
+++ b/ext/coverage/coverage.c
@@ -52,17 +52,29 @@ rb_coverage_supported(VALUE self, VALUE _mode)
/*
* call-seq:
- * Coverage.setup => nil
- * Coverage.setup(:all) => nil
- * Coverage.setup(lines: bool, branches: bool, methods: bool, eval: bool) => nil
- * Coverage.setup(oneshot_lines: true) => nil
+ * Coverage.setup -> nil
+ * Coverage.setup(type) -> nil
+ * Coverage.setup(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false) -> nil
*
- * Set up the coverage measurement.
+ * Performs setup for coverage measurement, but does not start coverage measurement.
+ * To start coverage measurement, use Coverage.resume.
*
- * Note that this method does not start the measurement itself.
- * Use Coverage.resume to start the measurement.
+ * To perform both setup and start coverage measurement, Coverage.start can be used.
*
- * You may want to use Coverage.start to setup and then start the measurement.
+ * With argument +type+ given and +type+ is symbol +:all+, enables all types of coverage
+ * (lines, branches, methods, and eval).
+ *
+ * Keyword arguments or hash +type+ can be given with each of the following keys:
+ *
+ * - +lines+: Enables line coverage that records the number of times each line was executed.
+ * If +lines+ is enabled, +oneshot_lines+ cannot be enabled.
+ * See {Lines Coverage}[rdoc-ref:Coverage@Lines+Coverage].
+ * - +branches+: Enables branch coverage that records the number of times each
+ * branch in each conditional was executed. See {Branches Coverage}[rdoc-ref:Coverage@Branch+Coverage].
+ * - +methods+: Enables method coverage that records the number of times each method was exectued.
+ * See {Methods Coverage}[rdoc-ref:Coverage@Methods+Coverage].
+ * - +eval+: Enables coverage for evaluations (e.g. Kernel#eval, Module#class_eval).
+ * See {Eval Coverage}[rdoc-ref:Coverage@Eval+Coverage].
*/
static VALUE
rb_coverage_setup(int argc, VALUE *argv, VALUE klass)
@@ -337,7 +349,7 @@ coverage_peek_result_i(st_data_t key, st_data_t val, st_data_t h)
* Coverage.peek_result => hash
*
* Returns a hash that contains filename as key and coverage array as value.
- * This is the same as `Coverage.result(stop: false, clear: false)`.
+ * This is the same as <tt>Coverage.result(stop: false, clear: false)</tt>.
*
* {
* "file.rb" => [1, 2, nil],
@@ -352,7 +364,6 @@ rb_coverage_peek_result(VALUE klass)
if (!RTEST(coverages)) {
rb_raise(rb_eRuntimeError, "coverage measurement is not enabled");
}
- OBJ_WB_UNPROTECT(coverages);
rb_hash_foreach(coverages, coverage_peek_result_i, ncoverages);
@@ -468,7 +479,7 @@ rb_coverage_running(VALUE klass)
return current_state == RUNNING ? Qtrue : Qfalse;
}
-/* Coverage provides coverage measurement feature for Ruby.
+/* \Coverage provides coverage measurement feature for Ruby.
* This feature is experimental, so these APIs may be changed in future.
*
* Caveat: Currently, only process-global coverage measurement is supported.
@@ -504,7 +515,7 @@ rb_coverage_running(VALUE klass)
* require "foo.rb"
* p Coverage.result #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}
*
- * == Lines Coverage
+ * == Lines \Coverage
*
* If a coverage mode is not explicitly specified when starting coverage, lines
* coverage is what will run. It reports the number of line executions for each
@@ -524,7 +535,7 @@ rb_coverage_running(VALUE klass)
* A +nil+ value means coverage is disabled for this line (lines like +else+
* and +end+).
*
- * == Oneshot Lines Coverage
+ * == Oneshot Lines \Coverage
*
* Oneshot lines coverage tracks and reports on the executed lines while
* coverage is running. It will not report how many times a line was executed,
@@ -538,7 +549,7 @@ rb_coverage_running(VALUE klass)
* The value of the oneshot lines coverage result is an array containing the
* line numbers that were executed.
*
- * == Branches Coverage
+ * == Branches \Coverage
*
* Branches coverage reports how many times each branch within each conditional
* was executed.
@@ -563,7 +574,7 @@ rb_coverage_running(VALUE klass)
* 5. The ending line number it appears on in the file.
* 6. The ending column number it appears on in the file.
*
- * == Methods Coverage
+ * == Methods \Coverage
*
* Methods coverage reports how many times each method was executed.
*
@@ -601,7 +612,63 @@ rb_coverage_running(VALUE klass)
* 5. The ending line number the method appears on in the file.
* 6. The ending column number the method appears on in the file.
*
- * == All Coverage Modes
+ * == Eval \Coverage
+ *
+ * Eval coverage can be combined with the coverage types above to track
+ * coverage for eval.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY, nil, "eval 1")
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result # => {"eval 1" => {lines: [1, 1, 10, nil]}}
+ *
+ * Note that the eval must have a filename assigned, otherwise coverage
+ * will not be measured.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result # => {"(eval)" => {lines: [nil, nil, nil, nil]}}
+ *
+ * Also note that if a line number is assigned to the eval and it is not 1,
+ * then the resulting coverage will be padded with +nil+ if the line number is
+ * greater than 1, and truncated if the line number is less than 1.
+ *
+ * require "coverage"
+ * Coverage.start(eval: true, lines: true)
+ *
+ * eval(<<~RUBY, nil, "eval 1", 3)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * eval(<<~RUBY, nil, "eval 2", -1)
+ * ary = []
+ * 10.times do |i|
+ * ary << "hello" * i
+ * end
+ * RUBY
+ *
+ * Coverage.result
+ * # => {"eval 1" => {lines: [nil, nil, 1, 1, 10, nil]}, "eval 2" => {lines: [10, nil]}}
+ *
+ * == All \Coverage Modes
*
* You can also run all modes of coverage simultaneously with this shortcut.
* Note that running all coverage modes does not run both lines and oneshot
diff --git a/ext/coverage/depend b/ext/coverage/depend
index 1be81c5e9a..fb7f9a95af 100644
--- a/ext/coverage/depend
+++ b/ext/coverage/depend
@@ -140,6 +140,7 @@ coverage.o: $(hdrdir)/ruby/internal/intern/re.h
coverage.o: $(hdrdir)/ruby/internal/intern/ruby.h
coverage.o: $(hdrdir)/ruby/internal/intern/select.h
coverage.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+coverage.o: $(hdrdir)/ruby/internal/intern/set.h
coverage.o: $(hdrdir)/ruby/internal/intern/signal.h
coverage.o: $(hdrdir)/ruby/internal/intern/sprintf.h
coverage.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -182,12 +183,14 @@ coverage.o: $(top_srcdir)/id_table.h
coverage.o: $(top_srcdir)/internal.h
coverage.o: $(top_srcdir)/internal/array.h
coverage.o: $(top_srcdir)/internal/basic_operators.h
+coverage.o: $(top_srcdir)/internal/box.h
coverage.o: $(top_srcdir)/internal/compilers.h
coverage.o: $(top_srcdir)/internal/gc.h
coverage.o: $(top_srcdir)/internal/hash.h
coverage.o: $(top_srcdir)/internal/imemo.h
coverage.o: $(top_srcdir)/internal/sanitizers.h
coverage.o: $(top_srcdir)/internal/serial.h
+coverage.o: $(top_srcdir)/internal/set_table.h
coverage.o: $(top_srcdir)/internal/static_assert.h
coverage.o: $(top_srcdir)/internal/thread.h
coverage.o: $(top_srcdir)/internal/variable.h
diff --git a/ext/coverage/lib/coverage.rb b/ext/coverage/lib/coverage.rb
index f1923ef366..4bd20e22cb 100644
--- a/ext/coverage/lib/coverage.rb
+++ b/ext/coverage/lib/coverage.rb
@@ -1,6 +1,11 @@
require "coverage.so"
module Coverage
+ # call-seq:
+ # line_stub(file) -> array
+ #
+ # A simple helper function that creates the "stub" of line coverage
+ # from a given source code.
def self.line_stub(file)
lines = File.foreach(file).map { nil }
iseqs = [RubyVM::InstructionSequence.compile_file(file)]
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index b80d948b00..9755fb819e 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -452,11 +452,43 @@ do {\
static int c_valid_civil_p(int, int, int, double,
int *, int *, int *, int *);
+/* Check if using pure Gregorian calendar (sg == -Infinity) */
+#define c_gregorian_only_p(sg) (isinf(sg) && (sg) < 0)
+
+/*
+ * Fast path macros for pure Gregorian calendar.
+ * Sets *rjd to the JD value, *ns to 1 (new style), and returns.
+ */
+#define GREGORIAN_JD_FAST_PATH_RET(sg, jd_expr, rjd, ns) \
+ if (c_gregorian_only_p(sg)) { \
+ *(rjd) = (jd_expr); \
+ *(ns) = 1; \
+ return 1; \
+ }
+
+#define GREGORIAN_JD_FAST_PATH(sg, jd_expr, rjd, ns) \
+ if (c_gregorian_only_p(sg)) { \
+ *(rjd) = (jd_expr); \
+ *(ns) = 1; \
+ return; \
+ }
+
+/* Forward declarations for Neri-Schneider optimized functions */
+static int c_gregorian_civil_to_jd(int y, int m, int d);
+static void c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd);
+static int c_gregorian_fdoy(int y);
+static int c_gregorian_ldoy(int y);
+static int c_gregorian_ldom_jd(int y, int m);
+static int ns_jd_in_range(int jd);
+
static int
c_find_fdoy(int y, double sg, int *rjd, int *ns)
{
int d, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_fdoy(y), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (d = 1; d < 31; d++)
if (c_valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns))
return 1;
@@ -468,6 +500,9 @@ c_find_ldoy(int y, double sg, int *rjd, int *ns)
{
int i, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldoy(y), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (i = 0; i < 30; i++)
if (c_valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns))
return 1;
@@ -493,6 +528,9 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
{
int i, rm, rd;
+ GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldom_jd(y, m), rjd, ns);
+
+ /* Keep existing loop for Julian/reform period */
for (i = 0; i < 30; i++)
if (c_valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns))
return 1;
@@ -502,55 +540,69 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
static void
c_civil_to_jd(int y, int m, int d, double sg, int *rjd, int *ns)
{
- double a, b, jd;
+ int jd;
+
+ GREGORIAN_JD_FAST_PATH(sg, c_gregorian_civil_to_jd(y, m, d), rjd, ns);
+
+ /* Calculate Gregorian JD using optimized algorithm */
+ jd = c_gregorian_civil_to_jd(y, m, d);
- if (m <= 2) {
- y -= 1;
- m += 12;
- }
- a = floor(y / 100.0);
- b = 2 - a + floor(a / 4.0);
- jd = floor(365.25 * (y + 4716)) +
- floor(30.6001 * (m + 1)) +
- d + b - 1524;
if (jd < sg) {
- jd -= b;
+ /* Before Gregorian switchover - use Julian calendar */
+ int y2 = y, m2 = m;
+ if (m2 <= 2) {
+ y2 -= 1;
+ m2 += 12;
+ }
+ jd = (int)(floor(365.25 * (y2 + 4716)) +
+ floor(30.6001 * (m2 + 1)) +
+ d - 1524);
*ns = 0;
}
- else
+ else {
*ns = 1;
+ }
- *rjd = (int)jd;
+ *rjd = jd;
}
static void
c_jd_to_civil(int jd, double sg, int *ry, int *rm, int *rdom)
{
- double x, a, b, c, d, e, y, m, dom;
-
- if (jd < sg)
- a = jd;
- else {
- x = floor((jd - 1867216.25) / 36524.25);
- a = jd + 1 + x - floor(x / 4.0);
- }
- b = a + 1524;
- c = floor((b - 122.1) / 365.25);
- d = floor(365.25 * c);
- e = floor((b - d) / 30.6001);
- dom = b - d - floor(30.6001 * e);
- if (e <= 13) {
- m = e - 1;
- y = c - 4716;
- }
- else {
- m = e - 13;
- y = c - 4715;
+ /* Fast path: pure Gregorian or date after switchover, within safe range */
+ if ((c_gregorian_only_p(sg) || jd >= sg) && ns_jd_in_range(jd)) {
+ c_gregorian_jd_to_civil(jd, ry, rm, rdom);
+ return;
}
- *ry = (int)y;
- *rm = (int)m;
- *rdom = (int)dom;
+ /* Original algorithm for Julian calendar or extreme dates */
+ {
+ double x, a, b, c, d, e, y, m, dom;
+
+ if (jd < sg)
+ a = jd;
+ else {
+ x = floor((jd - 1867216.25) / 36524.25);
+ a = jd + 1 + x - floor(x / 4.0);
+ }
+ b = a + 1524;
+ c = floor((b - 122.1) / 365.25);
+ d = floor(365.25 * c);
+ e = floor((b - d) / 30.6001);
+ dom = b - d - floor(30.6001 * e);
+ if (e <= 13) {
+ m = e - 1;
+ y = c - 4716;
+ }
+ else {
+ m = e - 13;
+ y = c - 4715;
+ }
+
+ *ry = (int)y;
+ *rm = (int)m;
+ *rdom = (int)dom;
+ }
}
static void
@@ -725,6 +777,147 @@ c_gregorian_last_day_of_month(int y, int m)
return monthtab[c_gregorian_leap_p(y) ? 1 : 0][m];
}
+/*
+ * Neri-Schneider algorithm for optimized Gregorian date conversion.
+ * Reference: Neri & Schneider, "Euclidean Affine Functions and Applications
+ * to Calendar Algorithms", Software: Practice and Experience, 2023.
+ * https://arxiv.org/abs/2102.06959
+ *
+ * This algorithm provides ~2-3x speedup over traditional floating-point
+ * implementations by using pure integer arithmetic with multiplication
+ * and bit-shifts instead of expensive division operations.
+ */
+
+/* JDN of March 1, Year 0 in proleptic Gregorian calendar */
+#define NS_EPOCH 1721120
+
+/* Days in a 4-year cycle (3 normal years + 1 leap year) */
+#define NS_DAYS_IN_4_YEARS 1461
+
+/* Days in a 400-year Gregorian cycle (97 leap years in 400 years) */
+#define NS_DAYS_IN_400_YEARS 146097
+
+/* Years per century */
+#define NS_YEARS_PER_CENTURY 100
+
+/*
+ * Multiplier for extracting year within century using fixed-point arithmetic.
+ * This is ceil(2^32 / NS_DAYS_IN_4_YEARS) for the Euclidean affine function.
+ */
+#define NS_YEAR_MULTIPLIER 2939745
+
+/*
+ * Coefficients for month calculation from day-of-year.
+ * Maps day-of-year to month using: month = (NS_MONTH_COEFF * doy + NS_MONTH_OFFSET) >> 16
+ */
+#define NS_MONTH_COEFF 2141
+#define NS_MONTH_OFFSET 197913
+
+/*
+ * Coefficients for civil date to JDN month contribution.
+ * Maps month to accumulated days: days = (NS_CIVIL_MONTH_COEFF * m - NS_CIVIL_MONTH_OFFSET) / 32
+ */
+#define NS_CIVIL_MONTH_COEFF 979
+#define NS_CIVIL_MONTH_OFFSET 2919
+#define NS_CIVIL_MONTH_DIVISOR 32
+
+/* Days from March 1 to December 31 (for Jan/Feb year adjustment) */
+#define NS_DAYS_BEFORE_NEW_YEAR 306
+
+/*
+ * Safe bounds for Neri-Schneider algorithm to avoid integer overflow.
+ * These correspond to approximately years -1,000,000 to +1,000,000.
+ */
+#define NS_JD_MIN -364000000
+#define NS_JD_MAX 538000000
+
+inline static int
+ns_jd_in_range(int jd)
+{
+ return jd >= NS_JD_MIN && jd <= NS_JD_MAX;
+}
+
+/* Optimized: Gregorian date -> Julian Day Number */
+static int
+c_gregorian_civil_to_jd(int y, int m, int d)
+{
+ /* Shift epoch to March 1 of year 0 (Jan/Feb belong to previous year) */
+ int j = (m < 3) ? 1 : 0;
+ int y0 = y - j;
+ int m0 = j ? m + 12 : m;
+ int d0 = d - 1;
+
+ /* Calculate year contribution with leap year correction */
+ int q1 = DIV(y0, NS_YEARS_PER_CENTURY);
+ int yc = DIV(NS_DAYS_IN_4_YEARS * y0, 4) - q1 + DIV(q1, 4);
+
+ /* Calculate month contribution using integer arithmetic */
+ int mc = (NS_CIVIL_MONTH_COEFF * m0 - NS_CIVIL_MONTH_OFFSET) / NS_CIVIL_MONTH_DIVISOR;
+
+ /* Combine and add epoch offset to get JDN */
+ return yc + mc + d0 + NS_EPOCH;
+}
+
+/* Optimized: Julian Day Number -> Gregorian date */
+static void
+c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd)
+{
+ int r0, n1, q1, r1, n2, q2, r2, n3, q3, r3, y0, j;
+ uint64_t u2;
+
+ /* Convert JDN to rata die (March 1, Year 0 epoch) */
+ r0 = jd - NS_EPOCH;
+
+ /* Extract century and day within 400-year cycle */
+ /* Use Euclidean (floor) division for negative values */
+ n1 = 4 * r0 + 3;
+ q1 = DIV(n1, NS_DAYS_IN_400_YEARS);
+ r1 = MOD(n1, NS_DAYS_IN_400_YEARS) / 4;
+
+ /* Calculate year within century and day of year */
+ n2 = 4 * r1 + 3;
+ /* Use 64-bit arithmetic to avoid overflow */
+ u2 = (uint64_t)NS_YEAR_MULTIPLIER * (uint64_t)n2;
+ q2 = (int)(u2 >> 32);
+ r2 = (int)((uint32_t)u2 / NS_YEAR_MULTIPLIER / 4);
+
+ /* Calculate month and day using integer arithmetic */
+ n3 = NS_MONTH_COEFF * r2 + NS_MONTH_OFFSET;
+ q3 = n3 >> 16;
+ r3 = (n3 & 0xFFFF) / NS_MONTH_COEFF;
+
+ /* Combine century and year */
+ y0 = NS_YEARS_PER_CENTURY * q1 + q2;
+
+ /* Adjust for January/February (shift from fiscal year) */
+ j = (r2 >= NS_DAYS_BEFORE_NEW_YEAR) ? 1 : 0;
+
+ *ry = y0 + j;
+ *rm = j ? q3 - 12 : q3;
+ *rd = r3 + 1;
+}
+
+/* O(1) first day of year for Gregorian calendar */
+inline static int
+c_gregorian_fdoy(int y)
+{
+ return c_gregorian_civil_to_jd(y, 1, 1);
+}
+
+/* O(1) last day of year for Gregorian calendar */
+inline static int
+c_gregorian_ldoy(int y)
+{
+ return c_gregorian_civil_to_jd(y, 12, 31);
+}
+
+/* O(1) last day of month (JDN) for Gregorian calendar */
+inline static int
+c_gregorian_ldom_jd(int y, int m)
+{
+ return c_gregorian_civil_to_jd(y, m, c_gregorian_last_day_of_month(y, m));
+}
+
static int
c_valid_julian_p(int y, int m, int d, int *rm, int *rd)
{
@@ -1599,7 +1792,7 @@ m_ajd(union DateData *x)
if (simple_dat_p(x)) {
r = m_real_jd(x);
- if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2)) {
+ if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2) && FIX2LONG(r) >= (FIXNUM_MIN + 1) / 2) {
long ir = FIX2LONG(r);
ir = ir * 2 - 1;
return rb_rational_new2(LONG2FIX(ir), INT2FIX(2));
@@ -2498,7 +2691,7 @@ date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass)
*
* Date.valid_jd?(2451944) # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd.
*/
@@ -2592,7 +2785,7 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
* Date.valid_date?(2001, 2, 29) # => false
* Date.valid_date?(2001, 2, -1) # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new.
*/
@@ -2680,7 +2873,7 @@ date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
* Date.valid_ordinal?(2001, 34) # => true
* Date.valid_ordinal?(2001, 366) # => false
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.ordinal.
*/
@@ -2770,7 +2963,7 @@ date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass)
*
* See Date.commercial.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.commercial.
*/
@@ -3350,7 +3543,7 @@ static VALUE d_lite_plus(VALUE, VALUE);
*
* Date.jd(Date::ITALY - 1).julian? # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.new.
*/
@@ -3415,7 +3608,7 @@ date_s_jd(int argc, VALUE *argv, VALUE klass)
*
* Raises an exception if +yday+ is zero or out of range.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new.
*/
@@ -3492,7 +3685,7 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
* where +n+ is the number of days in the month;
* when the argument is negative, counts backward from the end of the month.
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd.
*/
@@ -3598,7 +3791,7 @@ date_initialize(int argc, VALUE *argv, VALUE self)
* Date.commercial(2020, 1, 1).to_s # => "2019-12-30"
Date.commercial(2020, 1, 7).to_s # => "2020-01-05"
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* Related: Date.jd, Date.new, Date.ordinal.
*/
@@ -3783,7 +3976,7 @@ static void set_sg(union DateData *, double);
*
* Date.today.to_s # => "2022-07-06"
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -3878,7 +4071,6 @@ static VALUE
rt_complete_frags(VALUE klass, VALUE hash)
{
static VALUE tab = Qnil;
- int g;
long e;
VALUE k, a, d;
@@ -3975,9 +4167,13 @@ rt_complete_frags(VALUE klass, VALUE hash)
rb_gc_register_mark_object(tab);
}
+ k = a = Qnil;
+
{
- long i, eno = 0, idx = 0;
+ long i, eno = 0;
+ VALUE t = Qnil;
+ e = 0;
for (i = 0; i < RARRAY_LEN(tab); i++) {
VALUE x, a;
@@ -3992,23 +4188,20 @@ rt_complete_frags(VALUE klass, VALUE hash)
n++;
if (n > eno) {
eno = n;
- idx = i;
+ t = x;
}
}
}
- if (eno == 0)
- g = 0;
- else {
- g = 1;
- k = RARRAY_AREF(RARRAY_AREF(tab, idx), 0);
- a = RARRAY_AREF(RARRAY_AREF(tab, idx), 1);
- e = eno;
+ if (eno > 0) {
+ k = RARRAY_AREF(t, 0);
+ a = RARRAY_AREF(t, 1);
}
+ e = eno;
}
d = Qnil;
- if (g && !NIL_P(k) && (RARRAY_LEN(a) - e)) {
+ if (!NIL_P(k) && (RARRAY_LEN(a) > e)) {
if (k == sym("ordinal")) {
if (NIL_P(ref_hash("year"))) {
if (NIL_P(d))
@@ -4095,7 +4288,7 @@ rt_complete_frags(VALUE klass, VALUE hash)
}
}
- if (g && k == sym("time")) {
+ if (k == sym("time")) {
if (f_le_p(klass, cDateTime)) {
if (NIL_P(d))
d = date_s_today(0, (VALUE *)0, cDate);
@@ -4383,7 +4576,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
* Date._strptime('2001-02-03', '%Y-%m-%d') # => {:year=>2001, :mon=>2, :mday=>3}
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
* (Unlike Date.strftime, does not support flags and width.)
*
* See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html].
@@ -4412,10 +4605,10 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass)
* Date.strptime('sat3feb01', '%a%d%b%y') # => #<Date: 2001-02-03>
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
* (Unlike Date.strftime, does not support flags and width.)
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
* See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html].
*
@@ -4464,11 +4657,10 @@ get_limit(VALUE opt)
#define rb_category_warn(category, fmt) rb_warn(fmt)
#endif
-static void
+static VALUE
check_limit(VALUE str, VALUE opt)
{
size_t slen, limit;
- if (NIL_P(str)) return;
StringValue(str);
slen = RSTRING_LEN(str);
limit = get_limit(opt);
@@ -4476,6 +4668,7 @@ check_limit(VALUE str, VALUE opt)
rb_raise(rb_eArgError,
"string length (%"PRI_SIZE_PREFIX"u) exceeds the limit %"PRI_SIZE_PREFIX"u", slen, limit);
}
+ return str;
}
static VALUE
@@ -4484,8 +4677,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
VALUE vstr, vcomp, hash, opt;
argc = rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt);
- check_limit(vstr, opt);
- StringValue(vstr);
+ vstr = check_limit(vstr, opt);
if (!rb_enc_str_asciicompat_p(vstr))
rb_raise(rb_eArgError,
"string should have ASCII compatible encoding");
@@ -4505,7 +4697,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
* This method recognizes many forms in +string+,
* but it is not a validator.
* For formats, see
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
*
* If +string+ does not specify a valid date,
* the result is unpredictable;
@@ -4540,7 +4732,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
* This method recognizes many forms in +string+,
* but it is not a validator.
* For formats, see
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
* If +string+ does not specify a valid date,
* the result is unpredictable;
* consider using Date._strptime instead.
@@ -4560,7 +4752,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._parse (returns a hash).
@@ -4604,7 +4796,7 @@ VALUE date__jisx0301(VALUE);
* Date._iso8601(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should contain
- * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
+ * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
*
* d = Date.new(2001, 2, 3)
* s = d.iso8601 # => "2001-02-03"
@@ -4620,7 +4812,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__iso8601(str);
}
@@ -4631,7 +4823,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should contain
- * an {ISO 8601 formatted date}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
+ * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]:
*
* d = Date.new(2001, 2, 3)
* s = d.iso8601 # => "2001-02-03"
@@ -4639,7 +4831,7 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._iso8601 (returns a hash).
@@ -4673,7 +4865,7 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass)
* Date._rfc3339(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]:
+ * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
@@ -4690,7 +4882,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__rfc3339(str);
}
@@ -4701,7 +4893,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {RFC 3339 format}[rdoc-ref:strftime_formatting.rdoc@RFC+3339+Format]:
+ * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
@@ -4709,7 +4901,7 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._rfc3339 (returns a hash).
@@ -4759,7 +4951,7 @@ date_s__xmlschema(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__xmlschema(str);
}
@@ -4777,7 +4969,7 @@ date_s__xmlschema(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._xmlschema (returns a hash).
@@ -4811,7 +5003,7 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
* Date._rfc2822(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]:
+ * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
@@ -4828,7 +5020,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__rfc2822(str);
}
@@ -4839,7 +5031,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {RFC 2822 date format}[rdoc-ref:strftime_formatting.rdoc@RFC+2822+Format]:
+ * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
@@ -4847,7 +5039,7 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._rfc2822 (returns a hash).
@@ -4881,7 +5073,7 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
* Date._httpdate(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]:
+ * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
@@ -4896,7 +5088,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__httpdate(str);
}
@@ -4907,7 +5099,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
*
* Returns a new \Date object with values parsed from +string+,
* which should be a valid
- * {HTTP date format}[rdoc-ref:strftime_formatting.rdoc@HTTP+Format]:
+ * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]:
*
* d = Date.new(2001, 2, 3)
s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
@@ -4915,7 +5107,7 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._httpdate (returns a hash).
@@ -4949,7 +5141,7 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass)
* Date._jisx0301(string, limit: 128) -> hash
*
* Returns a hash of values parsed from +string+, which should be a valid
- * {JIS X 0301 date format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]:
+ * {JIS X 0301 date format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.jisx0301 # => "H13.02.03"
@@ -4965,7 +5157,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
VALUE str, opt;
rb_scan_args(argc, argv, "1:", &str, &opt);
- check_limit(str, opt);
+ if (!NIL_P(str)) str = check_limit(str, opt);
return date__jisx0301(str);
}
@@ -4975,7 +5167,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
* Date.jisx0301(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date
*
* Returns a new \Date object with values parsed from +string+,
- * which should be a valid {JIS X 0301 format}[rdoc-ref:strftime_formatting.rdoc@JIS+X+0301+Format]:
+ * which should be a valid {JIS X 0301 format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]:
*
* d = Date.new(2001, 2, 3)
* s = d.jisx0301 # => "H13.02.03"
@@ -4987,7 +5179,7 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass)
*
* See:
*
- * - Argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
* Related: Date._jisx0301 (returns a hash).
@@ -5745,7 +5937,7 @@ d_lite_leap_p(VALUE self)
* Date.new(2001, 2, 3, Date::GREGORIAN).start # => -Infinity
* Date.new(2001, 2, 3, Date::JULIAN).start # => Infinity
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -5820,7 +6012,7 @@ dup_obj_with_new_start(VALUE obj, double sg)
* d1 = d0.new_start(Date::JULIAN)
* d1.julian? # => true
*
- * See argument {start}[rdoc-ref:date/calendars.rdoc@Argument+start].
+ * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start].
*
*/
static VALUE
@@ -6936,13 +7128,24 @@ d_lite_eql_p(VALUE self, VALUE other)
static VALUE
d_lite_hash(VALUE self)
{
- st_index_t v, h[4];
+ st_index_t v, h[5];
+ VALUE nth;
get_d1(self);
- h[0] = m_nth(dat);
- h[1] = m_jd(dat);
- h[2] = m_df(dat);
- h[3] = m_sf(dat);
+ nth = m_nth(dat);
+
+ if (FIXNUM_P(nth)) {
+ h[0] = 0;
+ h[1] = (st_index_t)nth;
+ } else {
+ h[0] = 1;
+ h[1] = (st_index_t)FIX2LONG(rb_hash(nth));
+ }
+
+ h[2] = m_jd(dat);
+ h[3] = m_df(dat);
+ h[4] = m_sf(dat);
+
v = rb_memhash(h, sizeof(h));
return ST2FIX(v);
}
@@ -6957,7 +7160,7 @@ static VALUE strftimev(const char *, VALUE,
* to_s -> string
*
* Returns a string representation of the date in +self+
- * in {ISO 8601 extended date format}[rdoc-ref:strftime_formatting.rdoc@ISO+8601+Format+Specifications]
+ * in {ISO 8601 extended date format}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]
* (<tt>'%Y-%m-%d'</tt>):
*
* Date.new(2001, 2, 3).to_s # => "2001-02-03"
@@ -7238,7 +7441,7 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self,
* Date.new(2001, 2, 3).strftime # => "2001-02-03"
*
* For other formats, see
- * {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc].
+ * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc].
*
*/
static VALUE
@@ -7270,7 +7473,7 @@ strftimev(const char *fmt, VALUE self,
* asctime -> string
*
* Equivalent to #strftime with argument <tt>'%a %b %e %T %Y'</tt>
- * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
+ * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
* <tt>'%c'</tt>):
*
* Date.new(2001, 2, 3).asctime # => "Sat Feb 3 00:00:00 2001"
@@ -7289,7 +7492,7 @@ d_lite_asctime(VALUE self)
* iso8601 -> string
*
* Equivalent to #strftime with argument <tt>'%Y-%m-%d'</tt>
- * (or its {shorthand form}[rdoc-ref:strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
+ * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers]
* <tt>'%F'</tt>);
*
* Date.new(2001, 2, 3).iso8601 # => "2001-02-03"
@@ -7306,7 +7509,7 @@ d_lite_iso8601(VALUE self)
* rfc3339 -> string
*
* Equivalent to #strftime with argument <tt>'%FT%T%:z'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).rfc3339 # => "2001-02-03T00:00:00+00:00"
*
@@ -7322,7 +7525,7 @@ d_lite_rfc3339(VALUE self)
* rfc2822 -> string
*
* Equivalent to #strftime with argument <tt>'%a, %-d %b %Y %T %z'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
*
@@ -7338,7 +7541,7 @@ d_lite_rfc2822(VALUE self)
* httpdate -> string
*
* Equivalent to #strftime with argument <tt>'%a, %d %b %Y %T GMT'</tt>;
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
* Date.new(2001, 2, 3).httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
*
@@ -7517,10 +7720,7 @@ d_lite_marshal_dump_old(VALUE self)
m_of_in_day(dat),
DBL2NUM(m_sg(dat)));
- if (FL_TEST(self, FL_EXIVAR)) {
- rb_copy_generic_ivar(a, self);
- FL_SET(a, FL_EXIVAR);
- }
+ rb_copy_generic_ivar(a, self);
return a;
}
@@ -7542,10 +7742,8 @@ d_lite_marshal_dump(VALUE self)
INT2FIX(m_of(dat)),
DBL2NUM(m_sg(dat)));
- if (FL_TEST(self, FL_EXIVAR)) {
- rb_copy_generic_ivar(a, self);
- FL_SET(a, FL_EXIVAR);
- }
+
+ rb_copy_generic_ivar(a, self);
return a;
}
@@ -7618,10 +7816,7 @@ d_lite_marshal_load(VALUE self, VALUE a)
HAVE_JD | HAVE_DF);
}
- if (FL_TEST(a, FL_EXIVAR)) {
- rb_copy_generic_ivar(self, a);
- FL_SET(self, FL_EXIVAR);
- }
+ rb_copy_generic_ivar(self, a);
return self;
}
@@ -8715,7 +8910,7 @@ dt_lite_to_s(VALUE self)
* DateTime.now.strftime # => "2022-07-01T11:03:19-05:00"
*
* For other formats,
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]:
*
*/
static VALUE
@@ -9494,6 +9689,7 @@ Init_date_core(void)
sym_zone = ID2SYM(rb_intern_const("zone"));
half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2));
+ rb_gc_register_mark_object(half_days_in_day);
#if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS *
@@ -9505,8 +9701,6 @@ Init_date_core(void)
day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS),
INT2FIX(SECOND_IN_NANOSECONDS));
#endif
-
- rb_gc_register_mark_object(half_days_in_day);
rb_gc_register_mark_object(day_in_nanoseconds);
positive_inf = +INFINITY;
@@ -9522,7 +9716,7 @@ Init_date_core(void)
*
* - You need both dates and times; \Date handles only dates.
* - You need only Gregorian dates (and not Julian dates);
- * see {Julian and Gregorian Calendars}[rdoc-ref:date/calendars.rdoc].
+ * see {Julian and Gregorian Calendars}[rdoc-ref:language/calendars.rdoc].
*
* A \Date object, once created, is immutable, and cannot be modified.
*
@@ -9569,7 +9763,7 @@ Init_date_core(void)
* Date.strptime('fri31dec99', '%a%d%b%y') # => #<Date: 1999-12-31>
*
* See also the specialized methods in
- * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc@Specialized+Format+Strings]
+ * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings]
*
* == Argument +limit+
*
diff --git a/ext/date/depend b/ext/date/depend
index d07f10a593..4fb78149a1 100644
--- a/ext/date/depend
+++ b/ext/date/depend
@@ -138,6 +138,7 @@ date_core.o: $(hdrdir)/ruby/internal/intern/re.h
date_core.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_core.o: $(hdrdir)/ruby/internal/intern/select.h
date_core.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_core.o: $(hdrdir)/ruby/internal/intern/set.h
date_core.o: $(hdrdir)/ruby/internal/intern/signal.h
date_core.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_core.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -313,6 +314,7 @@ date_parse.o: $(hdrdir)/ruby/internal/intern/re.h
date_parse.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_parse.o: $(hdrdir)/ruby/internal/intern/select.h
date_parse.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_parse.o: $(hdrdir)/ruby/internal/intern/set.h
date_parse.o: $(hdrdir)/ruby/internal/intern/signal.h
date_parse.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_parse.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -478,6 +480,7 @@ date_strftime.o: $(hdrdir)/ruby/internal/intern/re.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/select.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_strftime.o: $(hdrdir)/ruby/internal/intern/set.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/signal.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -650,6 +653,7 @@ date_strptime.o: $(hdrdir)/ruby/internal/intern/re.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/ruby.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/select.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+date_strptime.o: $(hdrdir)/ruby/internal/intern/set.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/signal.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/sprintf.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb
index aa630eb6d1..0cb763017f 100644
--- a/ext/date/lib/date.rb
+++ b/ext/date/lib/date.rb
@@ -4,7 +4,7 @@
require 'date_core'
class Date
- VERSION = "3.4.1" # :nodoc:
+ VERSION = "3.5.1" # :nodoc:
# call-seq:
# infinite? -> false
diff --git a/ext/digest/bubblebabble/depend b/ext/digest/bubblebabble/depend
index 0da9c223ee..02d88e960c 100644
--- a/ext/digest/bubblebabble/depend
+++ b/ext/digest/bubblebabble/depend
@@ -128,6 +128,7 @@ bubblebabble.o: $(hdrdir)/ruby/internal/intern/re.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/ruby.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/select.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bubblebabble.o: $(hdrdir)/ruby/internal/intern/set.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/signal.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/sprintf.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/defs.h b/ext/digest/defs.h
index 77a134f364..9b11f4eca9 100644
--- a/ext/digest/defs.h
+++ b/ext/digest/defs.h
@@ -16,4 +16,26 @@
# define __END_DECLS
#endif
+#define RB_DIGEST_DIAGNOSTIC(compiler, op, flag) _Pragma(STRINGIZE(compiler diagnostic op flag))
+#ifdef RBIMPL_WARNING_IGNORED
+# define RB_DIGEST_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
+# define RB_DIGEST_WARNING_PUSH() RBIMPL_WARNING_PUSH()
+# define RB_DIGEST_WARNING_POP() RBIMPL_WARNING_POP()
+#elif defined(__clang__)
+# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(clang, ignored, #flag)
+# define RB_DIGEST_WARNING_PUSH() _Pragma("clang diagnostic push")
+# define RB_DIGEST_WARNING_POP() _Pragma("clang diagnostic pop")
+#else /* __GNUC__ */
+# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(GCC, ignored, #flag)
+# define RB_DIGEST_WARNING_PUSH() _Pragma("GCC diagnostic push")
+# define RB_DIGEST_WARNING_POP() _Pragma("GCC diagnostic pop")
+#endif
+#ifdef RBIMPL_HAS_WARNING
+# define RB_DIGEST_HAS_WARNING(_) RBIMPL_HAS_WARNING(_)
+#elif defined(__has_warning)
+# define RB_DIGEST_HAS_WARNING(_) __has_warning(_)
+#else
+# define RB_DIGEST_HAS_WARNING(_) 0
+#endif
+
#endif /* DEFS_H */
diff --git a/ext/digest/depend b/ext/digest/depend
index cb9e8d4813..3eabb1d1d6 100644
--- a/ext/digest/depend
+++ b/ext/digest/depend
@@ -128,6 +128,7 @@ digest.o: $(hdrdir)/ruby/internal/intern/re.h
digest.o: $(hdrdir)/ruby/internal/intern/ruby.h
digest.o: $(hdrdir)/ruby/internal/intern/select.h
digest.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+digest.o: $(hdrdir)/ruby/internal/intern/set.h
digest.o: $(hdrdir)/ruby/internal/intern/signal.h
digest.o: $(hdrdir)/ruby/internal/intern/sprintf.h
digest.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/digest_conf.rb b/ext/digest/digest_conf.rb
index 36a7d75289..099d20fcbe 100644
--- a/ext/digest/digest_conf.rb
+++ b/ext/digest/digest_conf.rb
@@ -2,14 +2,16 @@
def digest_conf(name)
unless with_config("bundled-#{name}")
- cc = with_config("common-digest")
- if cc != false or /\b#{name}\b/ =~ cc
- if File.exist?("#$srcdir/#{name}cc.h") and
- have_header("CommonCrypto/CommonDigest.h")
- $defs << "-D#{name.upcase}_USE_COMMONDIGEST"
- $headers << "#{name}cc.h"
- return :commondigest
- end
+ case cc = with_config("common-digest", true)
+ when true, false
+ else
+ cc = cc.split(/[\s,]++/).any? {|pat| File.fnmatch?(pat, name)}
+ end
+ if cc and File.exist?("#$srcdir/#{name}cc.h") and
+ have_header("CommonCrypto/CommonDigest.h")
+ $defs << "-D#{name.upcase}_USE_COMMONDIGEST"
+ $headers << "#{name}cc.h"
+ return :commondigest
end
end
$objs << "#{name}.#{$OBJEXT}"
diff --git a/ext/digest/lib/digest/version.rb b/ext/digest/lib/digest/version.rb
index 854106165c..a56e80c54e 100644
--- a/ext/digest/lib/digest/version.rb
+++ b/ext/digest/lib/digest/version.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module Digest
- VERSION = "3.2.0"
+ # The version string
+ VERSION = "3.2.1"
end
diff --git a/ext/digest/md5/depend b/ext/digest/md5/depend
index e71915e5b4..d1c25c28c8 100644
--- a/ext/digest/md5/depend
+++ b/ext/digest/md5/depend
@@ -131,6 +131,7 @@ md5.o: $(hdrdir)/ruby/internal/intern/re.h
md5.o: $(hdrdir)/ruby/internal/intern/ruby.h
md5.o: $(hdrdir)/ruby/internal/intern/select.h
md5.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+md5.o: $(hdrdir)/ruby/internal/intern/set.h
md5.o: $(hdrdir)/ruby/internal/intern/signal.h
md5.o: $(hdrdir)/ruby/internal/intern/sprintf.h
md5.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ md5init.o: $(hdrdir)/ruby/internal/intern/re.h
md5init.o: $(hdrdir)/ruby/internal/intern/ruby.h
md5init.o: $(hdrdir)/ruby/internal/intern/select.h
md5init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+md5init.o: $(hdrdir)/ruby/internal/intern/set.h
md5init.o: $(hdrdir)/ruby/internal/intern/signal.h
md5init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
md5init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/md5/md5cc.h b/ext/digest/md5/md5cc.h
index 657f573f85..a002c17604 100644
--- a/ext/digest/md5/md5cc.h
+++ b/ext/digest/md5/md5cc.h
@@ -2,14 +2,6 @@
#include <CommonCrypto/CommonDigest.h>
#ifdef __GNUC__
-# define RB_DIGEST_DIAGNOSTIC(compiler, op, flag) _Pragma(STRINGIZE(compiler diagnostic op flag))
-# ifdef RBIMPL_WARNING_IGNORED
-# define RB_DIGEST_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
-# elif defined(__clang__)
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(clang, ignored, #flag)
-# else /* __GNUC__ */
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(GCC, ignored, #flag)
-# endif
RB_DIGEST_WARNING_IGNORED(-Wdeprecated-declarations)
/* Suppress deprecation warnings of MD5 from Xcode 11.1 */
/* Although we know MD5 is deprecated too, provide just for backward
diff --git a/ext/digest/md5/md5init.c b/ext/digest/md5/md5init.c
index b81fd94864..c919060587 100644
--- a/ext/digest/md5/md5init.c
+++ b/ext/digest/md5/md5init.c
@@ -3,6 +3,7 @@
#include <ruby/ruby.h>
#include "../digest.h"
+#include "../defs.h"
#if defined(MD5_USE_COMMONDIGEST)
#include "md5cc.h"
#else
diff --git a/ext/digest/rmd160/depend b/ext/digest/rmd160/depend
index 09558ad92b..aec484f7b3 100644
--- a/ext/digest/rmd160/depend
+++ b/ext/digest/rmd160/depend
@@ -131,6 +131,7 @@ rmd160.o: $(hdrdir)/ruby/internal/intern/re.h
rmd160.o: $(hdrdir)/ruby/internal/intern/ruby.h
rmd160.o: $(hdrdir)/ruby/internal/intern/select.h
rmd160.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rmd160.o: $(hdrdir)/ruby/internal/intern/set.h
rmd160.o: $(hdrdir)/ruby/internal/intern/signal.h
rmd160.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rmd160.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ rmd160init.o: $(hdrdir)/ruby/internal/intern/re.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/ruby.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/select.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+rmd160init.o: $(hdrdir)/ruby/internal/intern/set.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/signal.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/sha1/depend b/ext/digest/sha1/depend
index 827b8a0852..e6bd9d8f73 100644
--- a/ext/digest/sha1/depend
+++ b/ext/digest/sha1/depend
@@ -131,6 +131,7 @@ sha1.o: $(hdrdir)/ruby/internal/intern/re.h
sha1.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha1.o: $(hdrdir)/ruby/internal/intern/select.h
sha1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha1.o: $(hdrdir)/ruby/internal/intern/set.h
sha1.o: $(hdrdir)/ruby/internal/intern/signal.h
sha1.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha1.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ sha1init.o: $(hdrdir)/ruby/internal/intern/re.h
sha1init.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha1init.o: $(hdrdir)/ruby/internal/intern/select.h
sha1init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha1init.o: $(hdrdir)/ruby/internal/intern/set.h
sha1init.o: $(hdrdir)/ruby/internal/intern/signal.h
sha1init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha1init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/digest/sha1/sha1.c b/ext/digest/sha1/sha1.c
index 5311227549..ce200270b7 100644
--- a/ext/digest/sha1/sha1.c
+++ b/ext/digest/sha1/sha1.c
@@ -232,8 +232,14 @@ void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len)
if ((j + len) > 63) {
(void)memcpy(&context->buffer[j], data, (i = 64-j));
SHA1_Transform(context->state, context->buffer);
- for ( ; i + 63 < len; i += 64)
+ for ( ; i + 63 < len; i += 64) {
+ RB_DIGEST_WARNING_PUSH();
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 11
+ RB_DIGEST_WARNING_IGNORED(-Wstringop-overread);
+#endif
SHA1_Transform(context->state, &data[i]);
+ RB_DIGEST_WARNING_POP();
+ }
j = 0;
} else {
i = 0;
diff --git a/ext/digest/sha2/depend b/ext/digest/sha2/depend
index af1600d346..2b74776b3e 100644
--- a/ext/digest/sha2/depend
+++ b/ext/digest/sha2/depend
@@ -131,6 +131,7 @@ sha2.o: $(hdrdir)/ruby/internal/intern/re.h
sha2.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha2.o: $(hdrdir)/ruby/internal/intern/select.h
sha2.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha2.o: $(hdrdir)/ruby/internal/intern/set.h
sha2.o: $(hdrdir)/ruby/internal/intern/signal.h
sha2.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha2.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -293,6 +294,7 @@ sha2init.o: $(hdrdir)/ruby/internal/intern/re.h
sha2init.o: $(hdrdir)/ruby/internal/intern/ruby.h
sha2init.o: $(hdrdir)/ruby/internal/intern/select.h
sha2init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sha2init.o: $(hdrdir)/ruby/internal/intern/set.h
sha2init.o: $(hdrdir)/ruby/internal/intern/signal.h
sha2init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sha2init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/erb/escape/escape.c b/ext/erb/escape/escape.c
index 67b2d1ef34..1794fc30eb 100644
--- a/ext/erb/escape/escape.c
+++ b/ext/erb/escape/escape.c
@@ -39,35 +39,50 @@ static VALUE
optimized_escape_html(VALUE str)
{
VALUE vbuf;
- char *buf = ALLOCV_N(char, vbuf, escaped_length(str));
+ char *buf = NULL;
const char *cstr = RSTRING_PTR(str);
const char *end = cstr + RSTRING_LEN(str);
- char *dest = buf;
+ const char *segment_start = cstr;
+ char *dest = NULL;
while (cstr < end) {
const unsigned char c = *cstr++;
uint8_t len = html_escape_table[c].len;
if (len) {
+ size_t segment_len = cstr - segment_start - 1;
+ if (!buf) {
+ buf = ALLOCV_N(char, vbuf, escaped_length(str));
+ dest = buf;
+ }
+ if (segment_len) {
+ memcpy(dest, segment_start, segment_len);
+ dest += segment_len;
+ }
+ segment_start = cstr;
memcpy(dest, html_escape_table[c].str, len);
dest += len;
}
- else {
- *dest++ = c;
- }
}
-
VALUE escaped = str;
- if (RSTRING_LEN(str) < (dest - buf)) {
+ if (buf) {
+ size_t segment_len = cstr - segment_start;
+ if (segment_len) {
+ memcpy(dest, segment_start, segment_len);
+ dest += segment_len;
+ }
escaped = rb_str_new(buf, dest - buf);
preserve_original_state(str, escaped);
+ ALLOCV_END(vbuf);
}
- ALLOCV_END(vbuf);
return escaped;
}
-// ERB::Util.html_escape is different from CGI.escapeHTML in the following two parts:
-// * ERB::Util.html_escape converts an argument with #to_s first (only if it's not T_STRING)
-// * ERB::Util.html_escape does not allocate a new string when nothing needs to be escaped
+/*
+ * ERB::Util.html_escape is similar to CGI.escapeHTML but different in the following two parts:
+ *
+ * * ERB::Util.html_escape converts an argument with #to_s first (only if it's not T_STRING)
+ * * ERB::Util.html_escape does not allocate a new string when nothing needs to be escaped
+ */
static VALUE
erb_escape_html(VALUE self, VALUE str)
{
@@ -86,6 +101,10 @@ erb_escape_html(VALUE self, VALUE str)
void
Init_escape(void)
{
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+
rb_cERB = rb_define_class("ERB", rb_cObject);
rb_mEscape = rb_define_module_under(rb_cERB, "Escape");
rb_define_module_function(rb_mEscape, "html_escape", erb_escape_html, 1);
diff --git a/ext/erb/escape/extconf.rb b/ext/erb/escape/extconf.rb
index 783e8c1f55..b211a9783f 100644
--- a/ext/erb/escape/extconf.rb
+++ b/ext/erb/escape/extconf.rb
@@ -4,5 +4,6 @@ case RUBY_ENGINE
when 'jruby', 'truffleruby'
File.write('Makefile', dummy_makefile($srcdir).join)
else
+ have_func("rb_ext_ractor_safe", "ruby.h")
create_makefile 'erb/escape'
end
diff --git a/ext/etc/depend b/ext/etc/depend
index 675699b129..77fe56a6bf 100644
--- a/ext/etc/depend
+++ b/ext/etc/depend
@@ -143,6 +143,7 @@ etc.o: $(hdrdir)/ruby/internal/intern/re.h
etc.o: $(hdrdir)/ruby/internal/intern/ruby.h
etc.o: $(hdrdir)/ruby/internal/intern/select.h
etc.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+etc.o: $(hdrdir)/ruby/internal/intern/set.h
etc.o: $(hdrdir)/ruby/internal/intern/signal.h
etc.o: $(hdrdir)/ruby/internal/intern/sprintf.h
etc.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index e2d621547e..8d50a96a62 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -56,7 +56,7 @@ static VALUE sGroup;
#endif
RUBY_EXTERN char *getlogin(void);
-#define RUBY_ETC_VERSION "1.4.5"
+#define RUBY_ETC_VERSION "1.4.6"
#define SYMBOL_LIT(str) ID2SYM(rb_intern_const(str ""))
@@ -832,11 +832,7 @@ etc_uname(VALUE obj)
rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding()));
rb_hash_aset(result, SYMBOL_LIT("version"), version);
-# if defined _MSC_VER && _MSC_VER < 1300
-# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen)
-# else
# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen)
-# endif
GET_COMPUTER_NAME(NULL, &len);
buf = ALLOCV_N(WCHAR, vbuf, len);
if (GET_COMPUTER_NAME(buf, &len)) {
diff --git a/ext/etc/etc.gemspec b/ext/etc/etc.gemspec
index 3facc74866..0e9803dc62 100644
--- a/ext/etc/etc.gemspec
+++ b/ext/etc/etc.gemspec
@@ -40,5 +40,5 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]
spec.extensions = %w{ext/etc/extconf.rb}
- spec.required_ruby_version = ">= 2.6.0"
+ spec.required_ruby_version = ">= 2.7.0"
end
diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb
index 3d7cceae40..497303a4fa 100644
--- a/ext/etc/extconf.rb
+++ b/ext/etc/extconf.rb
@@ -60,7 +60,7 @@ end
# TODO: remove when dropping 2.7 support, as exported since 3.0
have_func('rb_deprecate_constant(Qnil, "None")')
-have_func("rb_io_descriptor")
+have_func("rb_io_descriptor", "ruby/io.h")
$distcleanfiles << "constdefs.h"
diff --git a/ext/extmk.rb b/ext/extmk.rb
index 39cbce1bc9..578e1cfa01 100755
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -43,6 +43,7 @@ require 'rbconfig'
$topdir = "."
$top_srcdir = srcdir
+$extmk = true
inplace = File.identical?($top_srcdir, $topdir)
$" << "mkmf.rb"
@@ -138,14 +139,6 @@ def extract_makefile(makefile, keep = true)
true
end
-def create_makefile(target, srcprefix = nil)
- if $static and target.include?("/")
- base = File.basename(target)
- $defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
- end
- super
-end
-
def extmake(target, basedir = 'ext', maybestatic = true)
FileUtils.mkpath target unless File.directory?(target)
begin
@@ -566,6 +559,7 @@ extend Module.new {
if $static and (target = args.first).include?("/")
base = File.basename(target)
$defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
+ $defs << "-DInitVM_#{base}=InitVM_#{target.tr('/', '_')}"
end
return super
end
@@ -598,6 +592,7 @@ gem = #{@gemname}
build_complete = $(TARGET_GEM_DIR)/gem.build_complete
install-so: build_complete
clean-so:: clean-build_complete
+$(build_complete) $(OBJS): $(TARGET_SO_DIR_TIMESTAMP)
build_complete: $(build_complete)
$(build_complete): $(TARGET_SO)
diff --git a/ext/fcntl/depend b/ext/fcntl/depend
index 5ed652563b..57ea0f2106 100644
--- a/ext/fcntl/depend
+++ b/ext/fcntl/depend
@@ -128,6 +128,7 @@ fcntl.o: $(hdrdir)/ruby/internal/intern/re.h
fcntl.o: $(hdrdir)/ruby/internal/intern/ruby.h
fcntl.o: $(hdrdir)/ruby/internal/intern/select.h
fcntl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+fcntl.o: $(hdrdir)/ruby/internal/intern/set.h
fcntl.o: $(hdrdir)/ruby/internal/intern/signal.h
fcntl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
fcntl.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
index 86bee5fb45..b987e237dd 100644
--- a/ext/fcntl/fcntl.c
+++ b/ext/fcntl/fcntl.c
@@ -65,7 +65,7 @@ pack up your own arguments to pass as args for locking functions, etc.
*
*/
-#define FCNTL_VERSION "1.2.0"
+#define FCNTL_VERSION "1.3.0"
void
Init_fcntl(void)
@@ -251,4 +251,50 @@ Init_fcntl(void)
*/
rb_define_const(mFcntl, "F_DUP2FD_CLOEXEC", INT2NUM(F_DUP2FD_CLOEXEC));
#endif
+
+#ifdef F_PREALLOCATE
+ /*
+ * macOS specific flag used for preallocating file space.
+ */
+ rb_define_const(mFcntl, "F_PREALLOCATE", INT2NUM(F_PREALLOCATE));
+#endif
+
+#ifdef F_ALLOCATECONTIG
+ /*
+ * macOS specific flag used with F_PREALLOCATE for allocating contiguous
+ * space.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATECONTIG", INT2NUM(F_ALLOCATECONTIG));
+#endif
+
+#ifdef F_ALLOCATEALL
+ /*
+ * macOS specific flag used with F_PREALLOCATE for allocating all contiguous
+ * space or no space.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATEALL", INT2NUM(F_ALLOCATEALL));
+#endif
+
+#ifdef F_ALLOCATEPERSIST
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate space that is not
+ * freed when close is called.
+ */
+ rb_define_const(mFcntl, "F_ALLOCATEPERSIST", INT2NUM(F_ALLOCATEPERSIST));
+#endif
+
+#ifdef F_PEOFPOSMODE
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate from the physical
+ * end of file
+ */
+ rb_define_const(mFcntl, "F_PEOFPOSMODE", INT2NUM(F_PEOFPOSMODE));
+#endif
+
+#ifdef F_VOLPOSMODE
+ /*
+ * macOS specific flag used with F_PREALLOCATE. Allocate from the volume offset.
+ */
+ rb_define_const(mFcntl, "F_VOLPOSMODE", INT2NUM(F_VOLPOSMODE));
+#endif
}
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 80c1cddd5a..7ddaf071a8 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -4,7 +4,7 @@
*/
static const char *const
-IO_CONSOLE_VERSION = "0.8.0";
+IO_CONSOLE_VERSION = "0.8.2";
#include "ruby.h"
#include "ruby/io.h"
@@ -840,6 +840,9 @@ console_winsize(VALUE io)
return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}
+static VALUE console_scroll(VALUE io, int line);
+static VALUE console_goto(VALUE io, VALUE y, VALUE x);
+
/*
* call-seq:
* io.winsize = [rows, columns]
@@ -856,6 +859,8 @@ console_set_winsize(VALUE io, VALUE size)
#if defined _WIN32
HANDLE wh;
int newrow, newcol;
+ COORD oldsize;
+ SMALL_RECT oldwindow;
BOOL ret;
#endif
VALUE row, col, xpixel, ypixel;
@@ -891,18 +896,62 @@ console_set_winsize(VALUE io, VALUE size)
if (!GetConsoleScreenBufferInfo(wh, &ws)) {
rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
}
+ oldsize = ws.dwSize;
+ oldwindow = ws.srWindow;
+ if (ws.srWindow.Right + 1 < newcol) {
+ ws.dwSize.X = newcol;
+ }
+ if (ws.dwSize.Y < newrow) {
+ ws.dwSize.Y = newrow;
+ }
+ /* expand screen buffer first if needed */
+ if (!SetConsoleScreenBufferSize(wh, ws.dwSize)) {
+ rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
+ }
+ /* refresh ws for new dwMaximumWindowSize */
+ if (!GetConsoleScreenBufferInfo(wh, &ws)) {
+ rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
+ }
+ /* check new size before modifying buffer content */
+ if (newrow <= 0 || newcol <= 0 ||
+ newrow > ws.dwMaximumWindowSize.Y ||
+ newcol > ws.dwMaximumWindowSize.X) {
+ SetConsoleScreenBufferSize(wh, oldsize);
+ /* remove scrollbar if possible */
+ SetConsoleWindowInfo(wh, TRUE, &oldwindow);
+ rb_raise(rb_eArgError, "out of range winsize: [%d, %d]", newrow, newcol);
+ }
+ /* shrink screen buffer width */
ws.dwSize.X = newcol;
- ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
+ /* shrink screen buffer height if window height were the same */
+ if (oldsize.Y == ws.srWindow.Bottom - ws.srWindow.Top + 1) {
+ ws.dwSize.Y = newrow;
+ }
ws.srWindow.Left = 0;
- ws.srWindow.Top = 0;
- ws.srWindow.Right = newcol-1;
- ws.srWindow.Bottom = newrow-1;
+ ws.srWindow.Right = newcol - 1;
+ ws.srWindow.Bottom = ws.srWindow.Top + newrow -1;
+ if (ws.dwCursorPosition.Y > ws.srWindow.Bottom) {
+ console_scroll(io, ws.dwCursorPosition.Y - ws.srWindow.Bottom);
+ ws.dwCursorPosition.Y = ws.srWindow.Bottom;
+ console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X));
+ }
+ if (ws.srWindow.Bottom > ws.dwSize.Y - 1) {
+ console_scroll(io, ws.srWindow.Bottom - (ws.dwSize.Y - 1));
+ ws.dwCursorPosition.Y -= ws.srWindow.Bottom - (ws.dwSize.Y - 1);
+ console_goto(io, INT2FIX(ws.dwCursorPosition.Y), INT2FIX(ws.dwCursorPosition.X));
+ ws.srWindow.Bottom = ws.dwSize.Y - 1;
+ }
+ ws.srWindow.Top = ws.srWindow.Bottom - (newrow - 1);
+ /* perform changes to winsize */
if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
- rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
+ int last_error = LAST_ERROR;
+ SetConsoleScreenBufferSize(wh, oldsize);
+ rb_syserr_fail(last_error, "SetConsoleWindowInfo");
}
- /* retry when shrinking buffer after shrunk window */
- if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
- rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
+ /* perform screen buffer shrinking if necessary */
+ if ((ws.dwSize.Y < oldsize.Y || ws.dwSize.X < oldsize.X) &&
+ !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
+ rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
}
/* remove scrollbar if possible */
if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
@@ -1221,7 +1270,7 @@ console_cursor_pos(VALUE io)
if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
rb_syserr_fail(LAST_ERROR, 0);
}
- return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
+ return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y - ws.srWindow.Top), UINT2NUM(ws.dwCursorPosition.X));
#else
static const struct query_args query = {"\033[6n", 0};
VALUE resp = console_vt_response(0, 0, io, &query);
@@ -1254,11 +1303,17 @@ static VALUE
console_goto(VALUE io, VALUE y, VALUE x)
{
#ifdef _WIN32
- COORD pos;
- int fd = GetWriteFD(io);
- pos.X = NUM2UINT(x);
- pos.Y = NUM2UINT(y);
- if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ pos->X = NUM2UINT(x);
+ pos->Y = ws.srWindow.Top + NUM2UINT(y);
+ if (!SetConsoleCursorPosition(h, *pos)) {
rb_syserr_fail(LAST_ERROR, 0);
}
#else
@@ -1651,8 +1706,6 @@ console_dev(int argc, VALUE *argv, VALUE klass)
VALUE con = 0;
VALUE sym = 0;
- rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
-
if (argc) {
Check_Type(sym = argv[0], T_SYMBOL);
}
diff --git a/ext/io/console/depend b/ext/io/console/depend
index e66b6f4f5d..150a138d4d 100644
--- a/ext/io/console/depend
+++ b/ext/io/console/depend
@@ -139,6 +139,7 @@ console.o: $(hdrdir)/ruby/internal/intern/re.h
console.o: $(hdrdir)/ruby/internal/intern/ruby.h
console.o: $(hdrdir)/ruby/internal/intern/select.h
console.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+console.o: $(hdrdir)/ruby/internal/intern/set.h
console.o: $(hdrdir)/ruby/internal/intern/signal.h
console.o: $(hdrdir)/ruby/internal/intern/sprintf.h
console.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb
index 4ad7ed6996..dd3d221ae5 100644
--- a/ext/io/console/extconf.rb
+++ b/ext/io/console/extconf.rb
@@ -10,11 +10,11 @@ have_func("rb_syserr_new_str(0, Qnil)") or
abort
have_func("rb_interned_str_cstr")
-have_func("rb_io_path")
-have_func("rb_io_descriptor")
-have_func("rb_io_get_write_io")
-have_func("rb_io_closed_p")
-have_func("rb_io_open_descriptor")
+have_func("rb_io_path", "ruby/io.h")
+have_func("rb_io_descriptor", "ruby/io.h")
+have_func("rb_io_get_write_io", "ruby/io.h")
+have_func("rb_io_closed_p", "ruby/io.h")
+have_func("rb_io_open_descriptor", "ruby/io.h")
have_func("rb_ractor_local_storage_value_newkey")
is_wasi = /wasi/ =~ MakeMakefile::RbConfig::CONFIG["platform"]
diff --git a/ext/io/nonblock/depend b/ext/io/nonblock/depend
index 20a96f1252..e78a05c316 100644
--- a/ext/io/nonblock/depend
+++ b/ext/io/nonblock/depend
@@ -138,6 +138,7 @@ nonblock.o: $(hdrdir)/ruby/internal/intern/re.h
nonblock.o: $(hdrdir)/ruby/internal/intern/ruby.h
nonblock.o: $(hdrdir)/ruby/internal/intern/select.h
nonblock.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+nonblock.o: $(hdrdir)/ruby/internal/intern/set.h
nonblock.o: $(hdrdir)/ruby/internal/intern/signal.h
nonblock.o: $(hdrdir)/ruby/internal/intern/sprintf.h
nonblock.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/io/nonblock/extconf.rb b/ext/io/nonblock/extconf.rb
index a1e6075c9b..505c9e6252 100644
--- a/ext/io/nonblock/extconf.rb
+++ b/ext/io/nonblock/extconf.rb
@@ -7,7 +7,7 @@ unless RUBY_ENGINE == 'ruby'
return
end
-have_func("rb_io_descriptor")
+have_func("rb_io_descriptor", "ruby/io.h")
hdr = %w"fcntl.h"
if have_macro("O_NONBLOCK", hdr) and
diff --git a/ext/io/nonblock/io-nonblock.gemspec b/ext/io/nonblock/io-nonblock.gemspec
index 2df8b8e3a6..4f5b8cef6f 100644
--- a/ext/io/nonblock/io-nonblock.gemspec
+++ b/ext/io/nonblock/io-nonblock.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "io-nonblock"
- spec.version = "0.3.1"
+ spec.version = "0.3.2"
spec.authors = ["Nobu Nakada"]
spec.email = ["nobu@ruby-lang.org"]
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
spec.description = %q{Enables non-blocking mode with IO class}
spec.homepage = "https://github.com/ruby/io-nonblock"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.0")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
diff --git a/ext/io/wait/depend b/ext/io/wait/depend
index 70317b1497..41d53c1400 100644
--- a/ext/io/wait/depend
+++ b/ext/io/wait/depend
@@ -1,5 +1,4 @@
# AUTOGENERATED DEPENDENCIES START
-# wait.o: $(hdrdir)/ruby/assert.h # not in 2.6
wait.o: $(RUBY_EXTCONF_H)
wait.o: $(arch_hdrdir)/ruby/config.h
wait.o: $(hdrdir)/ruby.h
@@ -139,6 +138,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/re.h
wait.o: $(hdrdir)/ruby/internal/intern/ruby.h
wait.o: $(hdrdir)/ruby/internal/intern/select.h
wait.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+wait.o: $(hdrdir)/ruby/internal/intern/set.h
wait.o: $(hdrdir)/ruby/internal/intern/signal.h
wait.o: $(hdrdir)/ruby/internal/intern/sprintf.h
wait.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb
index e63c046187..00c455a45c 100644
--- a/ext/io/wait/extconf.rb
+++ b/ext/io/wait/extconf.rb
@@ -1,25 +1,4 @@
# frozen_string_literal: false
require 'mkmf'
-if RUBY_VERSION < "2.6"
- File.write("Makefile", dummy_makefile($srcdir).join(""))
-else
- target = "io/wait"
- have_func("rb_io_wait")
- have_func("rb_io_descriptor")
- unless macro_defined?("DOSISH", "#include <ruby.h>")
- have_header(ioctl_h = "sys/ioctl.h") or ioctl_h = nil
- fionread = %w[sys/ioctl.h sys/filio.h sys/socket.h].find do |h|
- have_macro("FIONREAD", [h, ioctl_h].compact)
- end
- if fionread
- $defs << "-DFIONREAD_HEADER=\"<#{fionread}>\""
- create_makefile(target)
- end
- else
- if have_func("rb_w32_ioctlsocket", "ruby.h")
- have_func("rb_w32_is_socket", "ruby.h")
- create_makefile(target)
- end
- end
-end
+create_makefile("io/wait")
diff --git a/ext/io/wait/io-wait.gemspec b/ext/io/wait/io-wait.gemspec
index e850e10bf9..c1c6172589 100644
--- a/ext/io/wait/io-wait.gemspec
+++ b/ext/io/wait/io-wait.gemspec
@@ -1,4 +1,4 @@
-_VERSION = "0.3.1"
+_VERSION = "0.4.0"
Gem::Specification.new do |spec|
spec.name = "io-wait"
@@ -10,24 +10,25 @@ Gem::Specification.new do |spec|
spec.description = %q{Waits until IO is readable or writable without blocking.}
spec.homepage = "https://github.com/ruby/io-wait"
spec.licenses = ["Ruby", "BSD-2-Clause"]
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.2")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject do |f|
- File.identical?(f, __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)})
- end
- end
+ jruby = true if Gem::Platform.new('java') =~ spec.platform or RUBY_ENGINE == 'jruby'
+ dir, gemspec = File.split(__FILE__)
+ excludes = [
+ *%w[:^/.git* :^/Gemfile* :^/Rakefile* :^/bin/ :^/test/ :^/rakelib/ :^*.java],
+ *(jruby ? %w[:^/ext/io] : %w[:^/ext/java]),
+ ":(exclude,literal,top)#{gemspec}"
+ ]
+ files = IO.popen(%w[git ls-files -z --] + excludes, chdir: dir, &:read).split("\x0")
+
+ spec.files = files
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
- jruby = true if Gem::Platform.new('java') =~ spec.platform or RUBY_ENGINE == 'jruby'
- spec.files.delete_if do |f|
- f.end_with?(".java") or
- f.start_with?("ext/") && (jruby ^ f.start_with?("ext/java/"))
- end
if jruby
spec.platform = 'java'
spec.files << "lib/io/wait.jar"
diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c
index 8835670e59..f7575191fe 100644
--- a/ext/io/wait/wait.c
+++ b/ext/io/wait/wait.c
@@ -11,427 +11,13 @@
**********************************************************************/
-#include "ruby.h"
-#include "ruby/io.h"
-
-#include <sys/types.h>
-#if defined(HAVE_UNISTD_H) && (defined(__sun))
-#include <unistd.h>
-#endif
-#if defined(HAVE_SYS_IOCTL_H)
-#include <sys/ioctl.h>
-#endif
-#if defined(FIONREAD_HEADER)
-#include FIONREAD_HEADER
-#endif
-
-#ifdef HAVE_RB_W32_IOCTLSOCKET
-#define ioctl ioctlsocket
-#define ioctl_arg u_long
-#define ioctl_arg2num(i) ULONG2NUM(i)
-#else
-#define ioctl_arg int
-#define ioctl_arg2num(i) INT2NUM(i)
-#endif
-
-#ifdef HAVE_RB_W32_IS_SOCKET
-#define FIONREAD_POSSIBLE_P(fd) rb_w32_is_socket(fd)
-#else
-#define FIONREAD_POSSIBLE_P(fd) ((void)(fd),Qtrue)
-#endif
-
-#ifndef HAVE_RB_IO_WAIT
-static struct timeval *
-get_timeout(int argc, VALUE *argv, struct timeval *timerec)
-{
- VALUE timeout = Qnil;
- rb_check_arity(argc, 0, 1);
- if (!argc || NIL_P(timeout = argv[0])) {
- return NULL;
- }
- else {
- *timerec = rb_time_interval(timeout);
- return timerec;
- }
-}
-
-static int
-wait_for_single_fd(rb_io_t *fptr, int events, struct timeval *tv)
-{
- int i = rb_wait_for_single_fd(fptr->fd, events, tv);
- if (i < 0)
- rb_sys_fail(0);
- rb_io_check_closed(fptr);
- return (i & events);
-}
-#endif
-
-/*
- * call-seq:
- * io.nread -> int
- *
- * Returns number of bytes that can be read without blocking.
- * Returns zero if no information available.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_nread(VALUE io)
-{
- rb_io_t *fptr;
- int len;
- ioctl_arg n;
-
- GetOpenFile(io, fptr);
- rb_io_check_readable(fptr);
- len = rb_io_read_pending(fptr);
- if (len > 0) return INT2FIX(len);
-
-#ifdef HAVE_RB_IO_DESCRIPTOR
- int fd = rb_io_descriptor(io);
-#else
- int fd = fptr->fd;
-#endif
-
- if (!FIONREAD_POSSIBLE_P(fd)) return INT2FIX(0);
- if (ioctl(fd, FIONREAD, &n)) return INT2FIX(0);
- if (n > 0) return ioctl_arg2num(n);
- return INT2FIX(0);
-}
-
-#ifdef HAVE_RB_IO_WAIT
-static VALUE
-io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
-{
- VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
-
- if (!RB_TEST(result)) {
- return Qnil;
- }
-
- int mask = RB_NUM2INT(result);
-
- if (mask & event) {
- if (return_io)
- return io;
- else
- return result;
- }
- else {
- return Qfalse;
- }
-}
-#endif
-
-/*
- * call-seq:
- * io.ready? -> truthy or falsy
- *
- * Returns a truthy value if input available without blocking, or a
- * falsy value.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_ready_p(VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval tv = {0, 0};
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_readable(fptr);
- if (rb_io_read_pending(fptr)) return Qtrue;
-
-#ifndef HAVE_RB_IO_WAIT
- return wait_for_single_fd(fptr, RB_WAITFD_IN, &tv) ? Qtrue : Qfalse;
-#else
- return io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0), 1);
-#endif
-}
-
-/* Ruby 3.2+ can define these methods. This macro indicates that case. */
-#ifndef RUBY_IO_WAIT_METHODS
-
-/*
- * call-seq:
- * io.wait_readable -> truthy or falsy
- * io.wait_readable(timeout) -> truthy or falsy
- *
- * Waits until IO is readable and returns a truthy value, or a falsy
- * value when times out. Returns a truthy value immediately when
- * buffered data is available.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_wait_readable(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval timerec;
- struct timeval *tv;
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_readable(fptr);
-
-#ifndef HAVE_RB_IO_WAIT
- tv = get_timeout(argc, argv, &timerec);
-#endif
- if (rb_io_read_pending(fptr)) return Qtrue;
-
-#ifndef HAVE_RB_IO_WAIT
- if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
- return io;
- }
- return Qnil;
-#else
- rb_check_arity(argc, 0, 1);
- VALUE timeout = (argc == 1 ? argv[0] : Qnil);
-
- return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
-#endif
-}
+#include "ruby.h" /* abi_version */
/*
- * call-seq:
- * io.wait_writable -> truthy or falsy
- * io.wait_writable(timeout) -> truthy or falsy
- *
- * Waits until IO is writable and returns a truthy value or a falsy
- * value when times out.
- *
- * You must require 'io/wait' to use this method.
- */
-static VALUE
-io_wait_writable(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr;
-#ifndef HAVE_RB_IO_WAIT
- struct timeval timerec;
- struct timeval *tv;
-#endif
-
- GetOpenFile(io, fptr);
- rb_io_check_writable(fptr);
-
-#ifndef HAVE_RB_IO_WAIT
- tv = get_timeout(argc, argv, &timerec);
- if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
- return io;
- }
- return Qnil;
-#else
- rb_check_arity(argc, 0, 1);
- VALUE timeout = (argc == 1 ? argv[0] : Qnil);
-
- return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
-#endif
-}
-
-#ifdef HAVE_RB_IO_WAIT
-/*
- * call-seq:
- * io.wait_priority -> truthy or falsy
- * io.wait_priority(timeout) -> truthy or falsy
- *
- * Waits until IO is priority and returns a truthy value or a falsy
- * value when times out. Priority data is sent and received using
- * the Socket::MSG_OOB flag and is typically limited to streams.
- *
- * You must require 'io/wait' to use this method.
- */
-static VALUE
-io_wait_priority(int argc, VALUE *argv, VALUE io)
-{
- rb_io_t *fptr = NULL;
-
- RB_IO_POINTER(io, fptr);
- rb_io_check_readable(fptr);
-
- if (rb_io_read_pending(fptr)) return Qtrue;
-
- rb_check_arity(argc, 0, 1);
- VALUE timeout = argc == 1 ? argv[0] : Qnil;
-
- return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
-}
-#endif
-
-static int
-wait_mode_sym(VALUE mode)
-{
- if (mode == ID2SYM(rb_intern("r"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("read"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("readable"))) {
- return RB_WAITFD_IN;
- }
- if (mode == ID2SYM(rb_intern("w"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("write"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("writable"))) {
- return RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("rw"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("read_write"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- if (mode == ID2SYM(rb_intern("readable_writable"))) {
- return RB_WAITFD_IN|RB_WAITFD_OUT;
- }
- rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
- return 0;
-}
-
-#ifdef HAVE_RB_IO_WAIT
-static inline rb_io_event_t
-io_event_from_value(VALUE value)
-{
- int events = RB_NUM2INT(value);
-
- if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
-
- return events;
-}
-#endif
-
-/*
- * call-seq:
- * io.wait(events, timeout) -> event mask, false or nil
- * io.wait(timeout = nil, mode = :read) -> self, true, or false
- *
- * Waits until the IO becomes ready for the specified events and returns the
- * subset of events that become ready, or a falsy value when times out.
- *
- * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
- * +IO::PRIORITY+.
- *
- * Returns a truthy value immediately when buffered data is available.
- *
- * Optional parameter +mode+ is one of +:read+, +:write+, or
- * +:read_write+.
- *
- * You must require 'io/wait' to use this method.
- */
-
-static VALUE
-io_wait(int argc, VALUE *argv, VALUE io)
-{
-#ifndef HAVE_RB_IO_WAIT
- rb_io_t *fptr;
- struct timeval timerec;
- struct timeval *tv = NULL;
- int event = 0;
- int i;
-
- GetOpenFile(io, fptr);
- for (i = 0; i < argc; ++i) {
- if (SYMBOL_P(argv[i])) {
- event |= wait_mode_sym(argv[i]);
- }
- else {
- *(tv = &timerec) = rb_time_interval(argv[i]);
- }
- }
- /* rb_time_interval() and might_mode() might convert the argument */
- rb_io_check_closed(fptr);
- if (!event) event = RB_WAITFD_IN;
- if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
- return Qtrue;
- if (wait_for_single_fd(fptr, event, tv))
- return io;
- return Qnil;
-#else
- VALUE timeout = Qundef;
- rb_io_event_t events = 0;
- int i, return_io = 0;
-
- /* The documented signature for this method is actually incorrect.
- * A single timeout is allowed in any position, and multiple symbols can be given.
- * Whether this is intentional or not, I don't know, and as such I consider this to
- * be a legacy/slow path. */
- if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
- /* We'd prefer to return the actual mask, but this form would return the io itself: */
- return_io = 1;
-
- /* Slow/messy path: */
- for (i = 0; i < argc; i += 1) {
- if (RB_SYMBOL_P(argv[i])) {
- events |= wait_mode_sym(argv[i]);
- }
- else if (timeout == Qundef) {
- rb_time_interval(timeout = argv[i]);
- }
- else {
- rb_raise(rb_eArgError, "timeout given more than once");
- }
- }
-
- if (timeout == Qundef) timeout = Qnil;
-
- if (events == 0) {
- events = RUBY_IO_READABLE;
- }
- }
- else /* argc == 2 and neither are symbols */ {
- /* This is the fast path: */
- events = io_event_from_value(argv[0]);
- timeout = argv[1];
- }
-
- if (events & RUBY_IO_READABLE) {
- rb_io_t *fptr = NULL;
- RB_IO_POINTER(io, fptr);
-
- if (rb_io_read_pending(fptr)) {
- /* This was the original behaviour: */
- if (return_io) return Qtrue;
- /* New behaviour always returns an event mask: */
- else return RB_INT2NUM(RUBY_IO_READABLE);
- }
- }
-
- return io_wait_event(io, events, timeout, return_io);
-#endif
-}
-
-#endif /* RUBY_IO_WAIT_METHODS */
-
-/*
- * IO wait methods
+ * IO wait methods are built in ruby now, just for backward compatibility.
*/
void
Init_wait(void)
{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- RB_EXT_RACTOR_SAFE(true);
-#endif
-
- rb_define_method(rb_cIO, "nread", io_nread, 0);
- rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
-
-#ifndef RUBY_IO_WAIT_METHODS
- rb_define_method(rb_cIO, "wait", io_wait, -1);
-
- rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
- rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
-#ifdef HAVE_RB_IO_WAIT
- rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
-#endif
-#endif
}
diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h
index b8a4e983d6..752d153b31 100644
--- a/ext/json/fbuffer/fbuffer.h
+++ b/ext/json/fbuffer/fbuffer.h
@@ -1,41 +1,9 @@
#ifndef _FBUFFER_H_
#define _FBUFFER_H_
-#include "ruby.h"
-#include "ruby/encoding.h"
+#include "../json.h"
#include "../vendor/jeaiii-ltoa.h"
-/* shims */
-/* This is the fallback definition from Ruby 3.4 */
-
-#ifndef RBIMPL_STDBOOL_H
-#if defined(__cplusplus)
-# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
-# include <cstdbool>
-# endif
-#elif defined(HAVE_STDBOOL_H)
-# include <stdbool.h>
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
-#endif
-#endif
-
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(expr) expr
-#endif
-
-#ifndef RB_LIKELY
-#define RB_LIKELY(expr) expr
-#endif
-
-#ifndef MAYBE_UNUSED
-# define MAYBE_UNUSED(x) x
-#endif
-
enum fbuffer_type {
FBUFFER_HEAP_ALLOCATED = 0,
FBUFFER_STACK_ALLOCATED = 1,
@@ -46,6 +14,9 @@ typedef struct FBufferStruct {
unsigned long initial_length;
unsigned long len;
unsigned long capa;
+#if JSON_DEBUG
+ unsigned long requested;
+#endif
char *ptr;
VALUE io;
} FBuffer;
@@ -74,6 +45,20 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
fb->ptr = stack_buffer;
fb->capa = stack_buffer_size;
}
+#if JSON_DEBUG
+ fb->requested = 0;
+#endif
+}
+
+static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
+{
+#if JSON_DEBUG
+ if (consumed > fb->requested) {
+ rb_bug("fbuffer: Out of bound write");
+ }
+ fb->requested = 0;
+#endif
+ fb->len += consumed;
}
static void fbuffer_free(FBuffer *fb)
@@ -137,25 +122,41 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
{
+#if JSON_DEBUG
+ fb->requested = requested;
+#endif
+
if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
fbuffer_do_inc_capa(fb, requested);
}
}
-static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
+static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, unsigned long len)
+{
+ MEMCPY(fb->ptr + fb->len, newstr, char, len);
+ fbuffer_consumed(fb, len);
+}
+
+static inline void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
{
if (len > 0) {
fbuffer_inc_capa(fb, len);
- MEMCPY(fb->ptr + fb->len, newstr, char, len);
- fb->len += len;
+ fbuffer_append_reserved(fb, newstr, len);
}
}
/* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
{
+#if JSON_DEBUG
+ if (fb->requested < 1) {
+ rb_bug("fbuffer: unreserved write");
+ }
+ fb->requested--;
+#endif
+
fb->ptr[fb->len] = chr;
- fb->len += 1;
+ fb->len++;
}
static void fbuffer_append_str(FBuffer *fb, VALUE str)
@@ -163,16 +164,29 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
const char *newstr = StringValuePtr(str);
unsigned long len = RSTRING_LEN(str);
- RB_GC_GUARD(str);
-
fbuffer_append(fb, newstr, len);
}
+static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
+{
+ const char *newstr = StringValuePtr(str);
+ unsigned long len = RSTRING_LEN(str);
+
+ fbuffer_inc_capa(fb, repeat * len);
+ while (repeat) {
+#if JSON_DEBUG
+ fb->requested = len;
+#endif
+ fbuffer_append_reserved(fb, newstr, len);
+ repeat--;
+ }
+}
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
{
fbuffer_inc_capa(fb, 1);
*(fb->ptr + fb->len) = newchr;
- fb->len++;
+ fbuffer_consumed(fb, 1);
}
static inline char *fbuffer_cursor(FBuffer *fb)
@@ -182,7 +196,7 @@ static inline char *fbuffer_cursor(FBuffer *fb)
static inline void fbuffer_advance_to(FBuffer *fb, char *end)
{
- fb->len = end - fb->ptr;
+ fbuffer_consumed(fb, (end - fb->ptr) - fb->len);
}
/*
@@ -223,14 +237,11 @@ static VALUE fbuffer_finalize(FBuffer *fb)
{
if (fb->io) {
fbuffer_flush(fb);
- fbuffer_free(fb);
rb_io_flush(fb->io);
return fb->io;
} else {
- VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
- fbuffer_free(fb);
- return result;
+ return rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
}
}
-#endif
+#endif // _FBUFFER_H_
diff --git a/ext/json/generator/depend b/ext/json/generator/depend
index d9160673a2..3ba4acfdd2 100644
--- a/ext/json/generator/depend
+++ b/ext/json/generator/depend
@@ -142,6 +142,7 @@ generator.o: $(hdrdir)/ruby/internal/intern/re.h
generator.o: $(hdrdir)/ruby/internal/intern/ruby.h
generator.o: $(hdrdir)/ruby/internal/intern/select.h
generator.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+generator.o: $(hdrdir)/ruby/internal/intern/set.h
generator.o: $(hdrdir)/ruby/internal/intern/signal.h
generator.o: $(hdrdir)/ruby/internal/intern/sprintf.h
generator.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -177,6 +178,8 @@ generator.o: $(hdrdir)/ruby/ruby.h
generator.o: $(hdrdir)/ruby/st.h
generator.o: $(hdrdir)/ruby/subst.h
generator.o: $(srcdir)/../fbuffer/fbuffer.h
+generator.o: $(srcdir)/../json.h
+generator.o: $(srcdir)/../simd/simd.h
generator.o: $(srcdir)/../vendor/fpconv.c
generator.o: $(srcdir)/../vendor/jeaiii-ltoa.h
generator.o: generator.c
diff --git a/ext/json/generator/extconf.rb b/ext/json/generator/extconf.rb
index 078068cf63..ee1bbeaba7 100644
--- a/ext/json/generator/extconf.rb
+++ b/ext/json/generator/extconf.rb
@@ -6,5 +6,11 @@ if RUBY_ENGINE == 'truffleruby'
else
append_cflags("-std=c99")
$defs << "-DJSON_GENERATOR"
+ $defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
+
+ if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
+ load __dir__ + "/../simd/conf.rb"
+ end
+
create_makefile 'json/ext/generator'
end
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index 428f5e21ff..dbba99c455 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -1,12 +1,20 @@
-#include "ruby.h"
+#include "../json.h"
#include "../fbuffer/fbuffer.h"
#include "../vendor/fpconv.c"
#include <math.h>
#include <ctype.h>
+#include "../simd/simd.h"
+
/* ruby api and some helpers */
+enum duplicate_key_action {
+ JSON_DEPRECATED = 0,
+ JSON_IGNORE,
+ JSON_RAISE,
+};
+
typedef struct JSON_Generator_StateStruct {
VALUE indent;
VALUE space;
@@ -19,20 +27,19 @@ typedef struct JSON_Generator_StateStruct {
long depth;
long buffer_initial_length;
+ enum duplicate_key_action on_duplicate_key;
+
+ bool as_json_single_arg;
bool allow_nan;
bool ascii_only;
bool script_safe;
bool strict;
} JSON_Generator_State;
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(cond) (cond)
-#endif
-
-static VALUE mJSON, cState, cFragment, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
+static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8;
-static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
-static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
+static ID i_to_s, i_to_json, i_new, i_encode;
+static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, sym_allow_duplicate_key,
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
@@ -45,7 +52,7 @@ static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_n
struct generate_json_data;
-typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
+typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
struct generate_json_data {
FBuffer *buffer;
@@ -53,44 +60,42 @@ struct generate_json_data {
JSON_Generator_State *state;
VALUE obj;
generator_func func;
+ long depth;
};
+static SIMD_Implementation simd_impl;
+
static VALUE cState_from_state_s(VALUE self, VALUE opts);
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
-static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
+static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
#ifdef RUBY_INTEGER_UNIFICATION
-static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
+static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
#endif
-static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
-static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
+static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
+static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
static int usascii_encindex, utf8_encindex, binary_encindex;
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
-static void raise_generator_error_str(VALUE invalid_object, VALUE str)
+NORETURN(static void) raise_generator_error_str(VALUE invalid_object, VALUE str)
{
+ rb_enc_associate_index(str, utf8_encindex);
VALUE exc = rb_exc_new_str(eGeneratorError, str);
rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
rb_exc_raise(exc);
}
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
#ifdef RBIMPL_ATTR_FORMAT
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
#endif
-static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
+NORETURN(static void) raise_generator_error(VALUE invalid_object, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
@@ -109,12 +114,34 @@ typedef struct _search_state {
const char *end;
const char *cursor;
FBuffer *buffer;
+
+#ifdef HAVE_SIMD
+ const char *chunk_base;
+ const char *chunk_end;
+ bool has_matches;
+
+#if defined(HAVE_SIMD_NEON)
+ uint64_t matches_mask;
+#elif defined(HAVE_SIMD_SSE2)
+ int matches_mask;
+#else
+#error "Unknown SIMD Implementation."
+#endif /* HAVE_SIMD_NEON */
+#endif /* HAVE_SIMD */
} search_state;
-static inline void search_flush(search_state *search)
-{
- fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor);
- search->cursor = search->ptr;
+ALWAYS_INLINE(static) void search_flush(search_state *search)
+{
+ // Do not remove this conditional without profiling, specifically escape-heavy text.
+ // escape_UTF8_char_basic will advance search->ptr and search->cursor (effectively a search_flush).
+ // For back-to-back characters that need to be escaped, specifically for the SIMD code paths, this method
+ // will be called just before calling escape_UTF8_char_basic. There will be no characters to append for the
+ // consecutive characters that need to be escaped. While the fbuffer_append is a no-op if
+ // nothing needs to be flushed, we can save a few memory references with this conditional.
+ if (search->ptr > search->cursor) {
+ fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor);
+ search->cursor = search->ptr;
+ }
}
static const unsigned char escape_table_basic[256] = {
@@ -144,7 +171,8 @@ static inline unsigned char search_escape_basic(search_state *search)
return 0;
}
-static inline void escape_UTF8_char_basic(search_state *search) {
+ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
+{
const unsigned char ch = (unsigned char)*search->ptr;
switch (ch) {
case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
@@ -184,14 +212,43 @@ static inline void escape_UTF8_char_basic(search_state *search) {
* Everything else (should be UTF-8) is just passed through and
* appended to the result.
*/
+
+
+#if defined(HAVE_SIMD_NEON)
+static inline unsigned char search_escape_basic_neon(search_state *search);
+#elif defined(HAVE_SIMD_SSE2)
+static inline unsigned char search_escape_basic_sse2(search_state *search);
+#endif
+
+static inline unsigned char search_escape_basic(search_state *search);
+
static inline void convert_UTF8_to_JSON(search_state *search)
{
+#ifdef HAVE_SIMD
+#if defined(HAVE_SIMD_NEON)
+ while (search_escape_basic_neon(search)) {
+ escape_UTF8_char_basic(search);
+ }
+#elif defined(HAVE_SIMD_SSE2)
+ if (simd_impl == SIMD_SSE2) {
+ while (search_escape_basic_sse2(search)) {
+ escape_UTF8_char_basic(search);
+ }
+ return;
+ }
while (search_escape_basic(search)) {
escape_UTF8_char_basic(search);
}
+#endif
+#else
+ while (search_escape_basic(search)) {
+ escape_UTF8_char_basic(search);
+ }
+#endif /* HAVE_SIMD */
}
-static inline void escape_UTF8_char(search_state *search, unsigned char ch_len) {
+static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
+{
const unsigned char ch = (unsigned char)*search->ptr;
switch (ch_len) {
case 1: {
@@ -227,6 +284,236 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
search->cursor = (search->ptr += ch_len);
}
+#ifdef HAVE_SIMD
+
+ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
+{
+ RBIMPL_ASSERT_OR_ASSUME(len < vec_len);
+
+ // Flush the buffer so everything up until the last 'len' characters are unflushed.
+ search_flush(search);
+
+ FBuffer *buf = search->buffer;
+ fbuffer_inc_capa(buf, vec_len);
+
+ char *s = (buf->ptr + buf->len);
+
+ // Pad the buffer with dummy characters that won't need escaping.
+ // This seem wasteful at first sight, but memset of vector length is very fast.
+ // This is a space as it can be directly represented as an immediate on AArch64.
+ memset(s, ' ', vec_len);
+
+ // Optimistically copy the remaining 'len' characters to the output FBuffer. If there are no characters
+ // to escape, then everything ends up in the correct spot. Otherwise it was convenient temporary storage.
+ if (vec_len == 16) {
+ RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD);
+ json_fast_memcpy16(s, search->ptr, len);
+ } else {
+ MEMCPY(s, search->ptr, char, len);
+ }
+
+ return s;
+}
+
+#ifdef HAVE_SIMD_NEON
+
+ALWAYS_INLINE(static) unsigned char neon_next_match(search_state *search)
+{
+ uint64_t mask = search->matches_mask;
+ uint32_t index = trailing_zeros64(mask) >> 2;
+
+ // It is assumed escape_UTF8_char_basic will only ever increase search->ptr by at most one character.
+ // If we want to use a similar approach for full escaping we'll need to ensure:
+ // search->chunk_base + index >= search->ptr
+ // However, since we know escape_UTF8_char_basic only increases search->ptr by one, if the next match
+ // is one byte after the previous match then:
+ // search->chunk_base + index == search->ptr
+ search->ptr = search->chunk_base + index;
+ mask &= mask - 1;
+ search->matches_mask = mask;
+ search_flush(search);
+ return 1;
+}
+
+static inline unsigned char search_escape_basic_neon(search_state *search)
+{
+ if (RB_UNLIKELY(search->has_matches)) {
+ // There are more matches if search->matches_mask > 0.
+ if (search->matches_mask > 0) {
+ return neon_next_match(search);
+ } else {
+ // neon_next_match will only advance search->ptr up to the last matching character.
+ // Skip over any characters in the last chunk that occur after the last match.
+ search->has_matches = false;
+ search->ptr = search->chunk_end;
+ }
+ }
+
+ /*
+ * The code below implements an SIMD-based algorithm to determine if N bytes at a time
+ * need to be escaped.
+ *
+ * Assume the ptr = "Te\sting!" (the double quotes are included in the string)
+ *
+ * The explanation will be limited to the first 8 bytes of the string for simplicity. However
+ * the vector insructions may work on larger vectors.
+ *
+ * First, we load three constants 'lower_bound', 'backslash' and 'dblquote" in vector registers.
+ *
+ * lower_bound: [20 20 20 20 20 20 20 20]
+ * backslash: [5C 5C 5C 5C 5C 5C 5C 5C]
+ * dblquote: [22 22 22 22 22 22 22 22]
+ *
+ * Next we load the first chunk of the ptr:
+ * [22 54 65 5C 73 74 69 6E] (" T e \ s t i n)
+ *
+ * First we check if any byte in chunk is less than 32 (0x20). This returns the following vector
+ * as no bytes are less than 32 (0x20):
+ * [0 0 0 0 0 0 0 0]
+ *
+ * Next, we check if any byte in chunk is equal to a backslash:
+ * [0 0 0 FF 0 0 0 0]
+ *
+ * Finally we check if any byte in chunk is equal to a double quote:
+ * [FF 0 0 0 0 0 0 0]
+ *
+ * Now we have three vectors where each byte indicates if the corresponding byte in chunk
+ * needs to be escaped. We combine these vectors with a series of logical OR instructions.
+ * This is the needs_escape vector and it is equal to:
+ * [FF 0 0 FF 0 0 0 0]
+ *
+ * Next we compute the bitwise AND between each byte and 0x1 and compute the horizontal sum of
+ * the values in the vector. This computes how many bytes need to be escaped within this chunk.
+ *
+ * Finally we compute a mask that indicates which bytes need to be escaped. If the mask is 0 then,
+ * no bytes need to be escaped and we can continue to the next chunk. If the mask is not 0 then we
+ * have at least one byte that needs to be escaped.
+ */
+
+ if (string_scan_simd_neon(&search->ptr, search->end, &search->matches_mask)) {
+ search->has_matches = true;
+ search->chunk_base = search->ptr;
+ search->chunk_end = search->ptr + sizeof(uint8x16_t);
+ return neon_next_match(search);
+ }
+
+ // There are fewer than 16 bytes left.
+ unsigned long remaining = (search->end - search->ptr);
+ if (remaining >= SIMD_MINIMUM_THRESHOLD) {
+ char *s = copy_remaining_bytes(search, sizeof(uint8x16_t), remaining);
+
+ uint64_t mask = compute_chunk_mask_neon(s);
+
+ if (!mask) {
+ // Nothing to escape, ensure search_flush doesn't do anything by setting
+ // search->cursor to search->ptr.
+ fbuffer_consumed(search->buffer, remaining);
+ search->ptr = search->end;
+ search->cursor = search->end;
+ return 0;
+ }
+
+ search->matches_mask = mask;
+ search->has_matches = true;
+ search->chunk_end = search->end;
+ search->chunk_base = search->ptr;
+ return neon_next_match(search);
+ }
+
+ if (search->ptr < search->end) {
+ return search_escape_basic(search);
+ }
+
+ search_flush(search);
+ return 0;
+}
+#endif /* HAVE_SIMD_NEON */
+
+#ifdef HAVE_SIMD_SSE2
+
+ALWAYS_INLINE(static) unsigned char sse2_next_match(search_state *search)
+{
+ int mask = search->matches_mask;
+ int index = trailing_zeros(mask);
+
+ // It is assumed escape_UTF8_char_basic will only ever increase search->ptr by at most one character.
+ // If we want to use a similar approach for full escaping we'll need to ensure:
+ // search->chunk_base + index >= search->ptr
+ // However, since we know escape_UTF8_char_basic only increases search->ptr by one, if the next match
+ // is one byte after the previous match then:
+ // search->chunk_base + index == search->ptr
+ search->ptr = search->chunk_base + index;
+ mask &= mask - 1;
+ search->matches_mask = mask;
+ search_flush(search);
+ return 1;
+}
+
+#if defined(__clang__) || defined(__GNUC__)
+#define TARGET_SSE2 __attribute__((target("sse2")))
+#else
+#define TARGET_SSE2
+#endif
+
+ALWAYS_INLINE(static) TARGET_SSE2 unsigned char search_escape_basic_sse2(search_state *search)
+{
+ if (RB_UNLIKELY(search->has_matches)) {
+ // There are more matches if search->matches_mask > 0.
+ if (search->matches_mask > 0) {
+ return sse2_next_match(search);
+ } else {
+ // sse2_next_match will only advance search->ptr up to the last matching character.
+ // Skip over any characters in the last chunk that occur after the last match.
+ search->has_matches = false;
+ if (RB_UNLIKELY(search->chunk_base + sizeof(__m128i) >= search->end)) {
+ search->ptr = search->end;
+ } else {
+ search->ptr = search->chunk_base + sizeof(__m128i);
+ }
+ }
+ }
+
+ if (string_scan_simd_sse2(&search->ptr, search->end, &search->matches_mask)) {
+ search->has_matches = true;
+ search->chunk_base = search->ptr;
+ search->chunk_end = search->ptr + sizeof(__m128i);
+ return sse2_next_match(search);
+ }
+
+ // There are fewer than 16 bytes left.
+ unsigned long remaining = (search->end - search->ptr);
+ if (remaining >= SIMD_MINIMUM_THRESHOLD) {
+ char *s = copy_remaining_bytes(search, sizeof(__m128i), remaining);
+
+ int needs_escape_mask = compute_chunk_mask_sse2(s);
+
+ if (needs_escape_mask == 0) {
+ // Nothing to escape, ensure search_flush doesn't do anything by setting
+ // search->cursor to search->ptr.
+ fbuffer_consumed(search->buffer, remaining);
+ search->ptr = search->end;
+ search->cursor = search->end;
+ return 0;
+ }
+
+ search->has_matches = true;
+ search->matches_mask = needs_escape_mask;
+ search->chunk_base = search->ptr;
+ return sse2_next_match(search);
+ }
+
+ if (search->ptr < search->end) {
+ return search_escape_basic(search);
+ }
+
+ search_flush(search);
+ return 0;
+}
+
+#endif /* HAVE_SIMD_SSE2 */
+
+#endif /* HAVE_SIMD */
+
static const unsigned char script_safe_escape_table[256] = {
// ASCII Control Characters
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -330,7 +617,8 @@ static inline unsigned char search_ascii_only_escape(search_state *search, const
return 0;
}
-static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len) {
+static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len)
+{
const unsigned char ch = (unsigned char)*search->ptr;
switch (ch_len) {
case 1: {
@@ -360,7 +648,7 @@ static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_
uint32_t wchar = 0;
- switch(ch_len) {
+ switch (ch_len) {
case 2:
wchar = ch & 0x1F;
break;
@@ -520,7 +808,8 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
* _state_ is a JSON::State object, that can also be used to configure the
* produced JSON string output further.
*/
-static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
+static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self)
+{
rb_check_arity(argc, 0, 1);
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
@@ -578,17 +867,6 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
}
/*
- * call-seq: String.included(modul)
- *
- * Extends _modul_ with the String::Extend module.
- */
-static VALUE mString_included_s(VALUE self, VALUE modul) {
- VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
- rb_call_super(1, &modul);
- return result;
-}
-
-/*
* call-seq: to_json(*)
*
* This string should be encoded with UTF-8 A call to this method
@@ -603,51 +881,6 @@ static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
}
/*
- * call-seq: to_json_raw_object()
- *
- * This method creates a raw object hash, that can be nested into
- * other data structures and will be generated as a raw string. This
- * method should be used, if you want to convert raw strings to JSON
- * instead of UTF-8 strings, e. g. binary data.
- */
-static VALUE mString_to_json_raw_object(VALUE self)
-{
- VALUE ary;
- VALUE result = rb_hash_new();
- rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
- ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
- rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
- return result;
-}
-
-/*
- * call-seq: to_json_raw(*args)
- *
- * This method creates a JSON text from the result of a call to
- * to_json_raw_object of this String.
- */
-static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)
-{
- VALUE obj = mString_to_json_raw_object(self);
- Check_Type(obj, T_HASH);
- return mHash_to_json(argc, argv, obj);
-}
-
-/*
- * call-seq: json_create(o)
- *
- * Raw Strings are JSON Objects (the raw bytes are stored in an array for the
- * key "raw"). The Ruby String can be created by this module method.
- */
-static VALUE mString_Extend_json_create(VALUE self, VALUE o)
-{
- VALUE ary;
- Check_Type(o, T_HASH);
- ary = rb_hash_aref(o, rb_str_new2("raw"));
- return rb_funcall(ary, i_pack, 1, rb_str_new2("C*"));
-}
-
-/*
* call-seq: to_json(*)
*
* Returns a JSON string for true: 'true'.
@@ -730,11 +963,6 @@ static size_t State_memsize(const void *ptr)
return sizeof(JSON_Generator_State);
}
-#ifndef HAVE_RB_EXT_RACTOR_SAFE
-# undef RUBY_TYPED_FROZEN_SHAREABLE
-# define RUBY_TYPED_FROZEN_SHAREABLE 0
-#endif
-
static const rb_data_type_t JSON_Generator_State_type = {
"JSON/Generator/State",
{
@@ -776,19 +1004,179 @@ static void vstate_spill(struct generate_json_data *data)
RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
}
-static inline VALUE vstate_get(struct generate_json_data *data)
+static inline VALUE json_call_to_json(struct generate_json_data *data, VALUE obj)
{
if (RB_UNLIKELY(!data->vstate)) {
vstate_spill(data);
}
- return data->vstate;
+ GET_STATE(data->vstate);
+ state->depth = data->depth;
+ VALUE tmp = rb_funcall(obj, i_to_json, 1, data->vstate);
+ // no need to restore state->depth, vstate is just a temporary State
+ return tmp;
+}
+
+static VALUE
+json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
+{
+ VALUE proc_args[2] = {object, is_key};
+ return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
+}
+
+static VALUE
+convert_string_subclass(VALUE key)
+{
+ VALUE key_to_s = rb_funcall(key, i_to_s, 0);
+
+ if (RB_UNLIKELY(!RB_TYPE_P(key_to_s, T_STRING))) {
+ VALUE cname = rb_obj_class(key);
+ rb_raise(rb_eTypeError,
+ "can't convert %"PRIsVALUE" to %s (%"PRIsVALUE"#%s gives %"PRIsVALUE")",
+ cname, "String", cname, "to_s", rb_obj_class(key_to_s));
+ }
+
+ return key_to_s;
+}
+
+static bool enc_utf8_compatible_p(int enc_idx)
+{
+ if (enc_idx == usascii_encindex) return true;
+ if (enc_idx == utf8_encindex) return true;
+ return false;
+}
+
+static VALUE encode_json_string_try(VALUE str)
+{
+ return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
+}
+
+static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
+{
+ raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
+ return Qundef;
+}
+
+static inline bool valid_json_string_p(VALUE str)
+{
+ int coderange = rb_enc_str_coderange(str);
+
+ if (RB_LIKELY(coderange == ENC_CODERANGE_7BIT)) {
+ return true;
+ }
+
+ if (RB_LIKELY(coderange == ENC_CODERANGE_VALID)) {
+ return enc_utf8_compatible_p(RB_ENCODING_GET_INLINED(str));
+ }
+
+ return false;
+}
+
+static inline VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
+{
+ if (RB_LIKELY(valid_json_string_p(str))) {
+ return str;
+ }
+
+ if (!as_json_called && data->state->strict && RTEST(data->state->as_json)) {
+ VALUE coerced_str = json_call_as_json(data->state, str, Qfalse);
+ if (coerced_str != str) {
+ if (RB_TYPE_P(coerced_str, T_STRING)) {
+ if (!valid_json_string_p(coerced_str)) {
+ raise_generator_error(str, "source sequence is illegal/malformed utf-8");
+ }
+ } else {
+ // as_json could return another type than T_STRING
+ if (is_key) {
+ raise_generator_error(coerced_str, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(coerced_str));
+ }
+ }
+
+ return coerced_str;
+ }
+ }
+
+ if (RB_ENCODING_GET_INLINED(str) == binary_encindex) {
+ VALUE utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
+ switch (rb_enc_str_coderange(utf8_string)) {
+ case ENC_CODERANGE_7BIT:
+ return utf8_string;
+ case ENC_CODERANGE_VALID:
+ // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
+ // TODO: Raise in 3.0.0
+ rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
+ return utf8_string;
+ break;
+ }
+ }
+
+ return rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
+}
+
+static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ fbuffer_append_char(buffer, '"');
+
+ long len;
+ search_state search;
+ search.buffer = buffer;
+ RSTRING_GETMEM(obj, search.ptr, len);
+ search.cursor = search.ptr;
+ search.end = search.ptr + len;
+
+#ifdef HAVE_SIMD
+ search.matches_mask = 0;
+ search.has_matches = false;
+ search.chunk_base = NULL;
+ search.chunk_end = NULL;
+#endif /* HAVE_SIMD */
+
+ switch (rb_enc_str_coderange(obj)) {
+ case ENC_CODERANGE_7BIT:
+ case ENC_CODERANGE_VALID:
+ if (RB_UNLIKELY(data->state->ascii_only)) {
+ convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
+ } else if (RB_UNLIKELY(data->state->script_safe)) {
+ convert_UTF8_to_script_safe_JSON(&search);
+ } else {
+ convert_UTF8_to_JSON(&search);
+ }
+ break;
+ default:
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
+ break;
+ }
+ fbuffer_append_char(buffer, '"');
+}
+
+static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
+{
+ obj = ensure_valid_encoding(data, obj, false, false);
+ raw_generate_json_string(buffer, data, obj);
}
struct hash_foreach_arg {
+ VALUE hash;
struct generate_json_data *data;
- int iter;
+ int first_key_type;
+ bool first;
+ bool mixed_keys_encountered;
};
+NOINLINE(static) void
+json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
+{
+ if (arg->mixed_keys_encountered) {
+ return;
+ }
+ arg->mixed_keys_encountered = true;
+
+ JSON_Generator_State *state = arg->data->state;
+ if (state->on_duplicate_key != JSON_IGNORE) {
+ VALUE do_raise = state->on_duplicate_key == JSON_RAISE ? Qtrue : Qfalse;
+ rb_funcall(mJSON, rb_intern("on_mixed_keys_hash"), 2, arg->hash, do_raise);
+ }
+}
+
static int
json_object_i(VALUE key, VALUE val, VALUE _arg)
{
@@ -798,272 +1186,220 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
FBuffer *buffer = data->buffer;
JSON_Generator_State *state = data->state;
- long depth = state->depth;
- int j;
+ long depth = data->depth;
+ int key_type = rb_type(key);
- if (arg->iter > 0) fbuffer_append_char(buffer, ',');
- if (RB_UNLIKELY(state->object_nl)) {
- fbuffer_append_str(buffer, state->object_nl);
+ if (arg->first) {
+ arg->first = false;
+ arg->first_key_type = key_type;
}
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ else {
+ fbuffer_append_char(buffer, ',');
+ }
+
+ if (RB_UNLIKELY(data->state->object_nl)) {
+ fbuffer_append_str(buffer, data->state->object_nl);
+ }
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
VALUE key_to_s;
- switch(rb_type(key)) {
+ bool as_json_called = false;
+
+ start:
+ switch (key_type) {
case T_STRING:
+ if (RB_UNLIKELY(arg->first_key_type != T_STRING)) {
+ json_inspect_hash_with_mixed_keys(arg);
+ }
+
if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
key_to_s = key;
} else {
- key_to_s = rb_funcall(key, i_to_s, 0);
+ key_to_s = convert_string_subclass(key);
}
break;
case T_SYMBOL:
+ if (RB_UNLIKELY(arg->first_key_type != T_SYMBOL)) {
+ json_inspect_hash_with_mixed_keys(arg);
+ }
+
key_to_s = rb_sym2str(key);
break;
default:
+ if (data->state->strict) {
+ if (RTEST(data->state->as_json) && !as_json_called) {
+ key = json_call_as_json(data->state, key, Qtrue);
+ key_type = rb_type(key);
+ as_json_called = true;
+ goto start;
+ } else {
+ raise_generator_error(key, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(key));
+ }
+ }
key_to_s = rb_convert_type(key, T_STRING, "String", "to_s");
break;
}
+ key_to_s = ensure_valid_encoding(data, key_to_s, as_json_called, true);
+
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
- generate_json_string(buffer, data, state, key_to_s);
+ raw_generate_json_string(buffer, data, key_to_s);
} else {
- generate_json(buffer, data, state, key_to_s);
+ generate_json(buffer, data, key_to_s);
}
- if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
+ if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, data->state->space_before);
fbuffer_append_char(buffer, ':');
- if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
- generate_json(buffer, data, state, val);
+ if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, data->state->space);
+ generate_json(buffer, data, val);
- arg->iter++;
return ST_CONTINUE;
}
-static inline long increase_depth(JSON_Generator_State *state)
+static inline long increase_depth(struct generate_json_data *data)
{
- long depth = ++state->depth;
+ JSON_Generator_State *state = data->state;
+ long depth = ++data->depth;
if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
- rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
+ rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --data->depth);
}
return depth;
}
-static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- int j;
- long depth = increase_depth(state);
+ long depth = increase_depth(data);
if (RHASH_SIZE(obj) == 0) {
fbuffer_append(buffer, "{}", 2);
- --state->depth;
+ --data->depth;
return;
}
fbuffer_append_char(buffer, '{');
struct hash_foreach_arg arg = {
+ .hash = obj,
.data = data,
- .iter = 0,
+ .first = true,
};
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
- depth = --state->depth;
- if (RB_UNLIKELY(state->object_nl)) {
- fbuffer_append_str(buffer, state->object_nl);
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ depth = --data->depth;
+ if (RB_UNLIKELY(data->state->object_nl)) {
+ fbuffer_append_str(buffer, data->state->object_nl);
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
}
fbuffer_append_char(buffer, '}');
}
-static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- int i, j;
- long depth = increase_depth(state);
+ long depth = increase_depth(data);
if (RARRAY_LEN(obj) == 0) {
fbuffer_append(buffer, "[]", 2);
- --state->depth;
+ --data->depth;
return;
}
fbuffer_append_char(buffer, '[');
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
- for(i = 0; i < RARRAY_LEN(obj); i++) {
+ if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
+ for (int i = 0; i < RARRAY_LEN(obj); i++) {
if (i > 0) {
fbuffer_append_char(buffer, ',');
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
+ if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
}
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
- generate_json(buffer, data, state, RARRAY_AREF(obj, i));
+ generate_json(buffer, data, RARRAY_AREF(obj, i));
}
- state->depth = --depth;
- if (RB_UNLIKELY(state->array_nl)) {
- fbuffer_append_str(buffer, state->array_nl);
- if (RB_UNLIKELY(state->indent)) {
- for (j = 0; j < depth; j++) {
- fbuffer_append_str(buffer, state->indent);
- }
+ data->depth = --depth;
+ if (RB_UNLIKELY(data->state->array_nl)) {
+ fbuffer_append_str(buffer, data->state->array_nl);
+ if (RB_UNLIKELY(data->state->indent)) {
+ fbuffer_append_str_repeat(buffer, data->state->indent, depth);
}
}
fbuffer_append_char(buffer, ']');
}
-static inline int enc_utf8_compatible_p(int enc_idx)
-{
- if (enc_idx == usascii_encindex) return 1;
- if (enc_idx == utf8_encindex) return 1;
- return 0;
-}
-
-static VALUE encode_json_string_try(VALUE str)
-{
- return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
-}
-
-static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
-{
- raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
- return Qundef;
-}
-
-static inline VALUE ensure_valid_encoding(VALUE str)
-{
- int encindex = RB_ENCODING_GET(str);
- VALUE utf8_string;
- if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
- if (encindex == binary_encindex) {
- utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
- switch (rb_enc_str_coderange(utf8_string)) {
- case ENC_CODERANGE_7BIT:
- return utf8_string;
- case ENC_CODERANGE_VALID:
- // For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
- // TODO: Raise in 3.0.0
- rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
- return utf8_string;
- break;
- }
- }
-
- str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
- }
- return str;
-}
-
-static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
-{
- obj = ensure_valid_encoding(obj);
-
- fbuffer_append_char(buffer, '"');
-
- long len;
- search_state search;
- search.buffer = buffer;
- RSTRING_GETMEM(obj, search.ptr, len);
- search.cursor = search.ptr;
- search.end = search.ptr + len;
-
- switch(rb_enc_str_coderange(obj)) {
- case ENC_CODERANGE_7BIT:
- case ENC_CODERANGE_VALID:
- if (RB_UNLIKELY(state->ascii_only)) {
- convert_UTF8_to_ASCII_only_JSON(&search, state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
- } else if (RB_UNLIKELY(state->script_safe)) {
- convert_UTF8_to_script_safe_JSON(&search);
- } else {
- convert_UTF8_to_JSON(&search);
- }
- break;
- default:
- raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
- break;
- }
- fbuffer_append_char(buffer, '"');
-}
-
-static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE tmp;
if (rb_respond_to(obj, i_to_json)) {
- tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
+ tmp = json_call_to_json(data, obj);
Check_Type(tmp, T_STRING);
fbuffer_append_str(buffer, tmp);
} else {
tmp = rb_funcall(obj, i_to_s, 0);
Check_Type(tmp, T_STRING);
- generate_json_string(buffer, data, state, tmp);
+ generate_json_string(buffer, data, tmp);
}
}
-static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
- if (state->strict) {
- generate_json_string(buffer, data, state, rb_sym2str(obj));
+ if (data->state->strict) {
+ generate_json_string(buffer, data, rb_sym2str(obj));
} else {
- generate_json_fallback(buffer, data, state, obj);
+ generate_json_fallback(buffer, data, obj);
}
}
-static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append(buffer, "null", 4);
}
-static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append(buffer, "false", 5);
}
-static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append(buffer, "true", 4);
}
-static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
fbuffer_append_long(buffer, FIX2LONG(obj));
}
-static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE tmp = rb_funcall(obj, i_to_s, 0);
fbuffer_append_str(buffer, tmp);
}
#ifdef RUBY_INTEGER_UNIFICATION
-static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
if (FIXNUM_P(obj))
- generate_json_fixnum(buffer, data, state, obj);
+ generate_json_fixnum(buffer, data, obj);
else
- generate_json_bignum(buffer, data, state, obj);
+ generate_json_bignum(buffer, data, obj);
}
#endif
-static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
double value = RFLOAT_VALUE(obj);
- char allow_nan = state->allow_nan;
+ char allow_nan = data->state->allow_nan;
if (isinf(value) || isnan(value)) {
/* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
if (!allow_nan) {
- if (state->strict && state->as_json) {
- VALUE casted_obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
+ if (data->state->strict && data->state->as_json) {
+ VALUE casted_obj = json_call_as_json(data->state, obj, Qfalse);
if (casted_obj != obj) {
- increase_depth(state);
- generate_json(buffer, data, state, casted_obj);
- state->depth--;
+ increase_depth(data);
+ generate_json(buffer, data, casted_obj);
+ data->depth--;
return;
}
}
@@ -1076,43 +1412,41 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
}
/* This implementation writes directly into the buffer. We reserve
- * the 24 characters that fpconv_dtoa states as its maximum, plus
- * 2 more characters for the potential ".0" suffix.
+ * the 32 characters that fpconv_dtoa states as its maximum.
*/
- fbuffer_inc_capa(buffer, 26);
+ fbuffer_inc_capa(buffer, 32);
char* d = buffer->ptr + buffer->len;
int len = fpconv_dtoa(value, d);
-
/* fpconv_dtoa converts a float to its shortest string representation,
* but it adds a ".0" if this is a plain integer.
*/
- buffer->len += len;
+ fbuffer_consumed(buffer, len);
}
-static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
VALUE fragment = RSTRUCT_GET(obj, 0);
Check_Type(fragment, T_STRING);
fbuffer_append_str(buffer, fragment);
}
-static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
+static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
{
bool as_json_called = false;
start:
if (obj == Qnil) {
- generate_json_null(buffer, data, state, obj);
+ generate_json_null(buffer, data, obj);
} else if (obj == Qfalse) {
- generate_json_false(buffer, data, state, obj);
+ generate_json_false(buffer, data, obj);
} else if (obj == Qtrue) {
- generate_json_true(buffer, data, state, obj);
+ generate_json_true(buffer, data, obj);
} else if (RB_SPECIAL_CONST_P(obj)) {
if (RB_FIXNUM_P(obj)) {
- generate_json_fixnum(buffer, data, state, obj);
+ generate_json_fixnum(buffer, data, obj);
} else if (RB_FLONUM_P(obj)) {
- generate_json_float(buffer, data, state, obj);
+ generate_json_float(buffer, data, obj);
} else if (RB_STATIC_SYM_P(obj)) {
- generate_json_symbol(buffer, data, state, obj);
+ generate_json_symbol(buffer, data, obj);
} else {
goto general;
}
@@ -1120,43 +1454,52 @@ start:
VALUE klass = RBASIC_CLASS(obj);
switch (RB_BUILTIN_TYPE(obj)) {
case T_BIGNUM:
- generate_json_bignum(buffer, data, state, obj);
+ generate_json_bignum(buffer, data, obj);
break;
case T_HASH:
if (klass != rb_cHash) goto general;
- generate_json_object(buffer, data, state, obj);
+ generate_json_object(buffer, data, obj);
break;
case T_ARRAY:
if (klass != rb_cArray) goto general;
- generate_json_array(buffer, data, state, obj);
+ generate_json_array(buffer, data, obj);
break;
case T_STRING:
if (klass != rb_cString) goto general;
- generate_json_string(buffer, data, state, obj);
+
+ if (RB_LIKELY(valid_json_string_p(obj))) {
+ raw_generate_json_string(buffer, data, obj);
+ } else if (as_json_called) {
+ raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
+ } else {
+ obj = ensure_valid_encoding(data, obj, false, false);
+ as_json_called = true;
+ goto start;
+ }
break;
case T_SYMBOL:
- generate_json_symbol(buffer, data, state, obj);
+ generate_json_symbol(buffer, data, obj);
break;
case T_FLOAT:
if (klass != rb_cFloat) goto general;
- generate_json_float(buffer, data, state, obj);
+ generate_json_float(buffer, data, obj);
break;
case T_STRUCT:
if (klass != cFragment) goto general;
- generate_json_fragment(buffer, data, state, obj);
+ generate_json_fragment(buffer, data, obj);
break;
default:
general:
- if (state->strict) {
- if (RTEST(state->as_json) && !as_json_called) {
- obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
+ if (data->state->strict) {
+ if (RTEST(data->state->as_json) && !as_json_called) {
+ obj = json_call_as_json(data->state, obj, Qfalse);
as_json_called = true;
goto start;
} else {
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
}
} else {
- generate_json_fallback(buffer, data, state, obj);
+ generate_json_fallback(buffer, data, obj);
}
}
}
@@ -1166,18 +1509,16 @@ static VALUE generate_json_try(VALUE d)
{
struct generate_json_data *data = (struct generate_json_data *)d;
- data->func(data->buffer, data, data->state, data->obj);
+ data->func(data->buffer, data, data->obj);
- return Qnil;
+ return fbuffer_finalize(data->buffer);
}
-static VALUE generate_json_rescue(VALUE d, VALUE exc)
+static VALUE generate_json_ensure(VALUE d)
{
struct generate_json_data *data = (struct generate_json_data *)d;
fbuffer_free(data->buffer);
- rb_exc_raise(exc);
-
return Qundef;
}
@@ -1193,14 +1534,13 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
struct generate_json_data data = {
.buffer = &buffer,
- .vstate = self,
+ .vstate = Qfalse, // don't use self as it may be frozen and its depth is mutated when calling to_json
.state = state,
+ .depth = state->depth,
.obj = obj,
.func = func
};
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
-
- return fbuffer_finalize(&buffer);
+ return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
}
/* call-seq:
@@ -1216,10 +1556,7 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
rb_check_arity(argc, 1, 2);
VALUE obj = argv[0];
VALUE io = argc > 1 ? argv[1] : Qnil;
- VALUE result = cState_partial_generate(self, obj, generate_json, io);
- GET_STATE(self);
- (void)state;
- return result;
+ return cState_partial_generate(self, obj, generate_json, io);
}
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
@@ -1300,6 +1637,7 @@ static VALUE string_config(VALUE config)
*/
static VALUE cState_indent_set(VALUE self, VALUE indent)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
return Qnil;
@@ -1325,6 +1663,7 @@ static VALUE cState_space(VALUE self)
*/
static VALUE cState_space_set(VALUE self, VALUE space)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->space, string_config(space));
return Qnil;
@@ -1348,6 +1687,7 @@ static VALUE cState_space_before(VALUE self)
*/
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
return Qnil;
@@ -1373,6 +1713,7 @@ static VALUE cState_object_nl(VALUE self)
*/
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
return Qnil;
@@ -1396,6 +1737,7 @@ static VALUE cState_array_nl(VALUE self)
*/
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
return Qnil;
@@ -1419,6 +1761,7 @@ static VALUE cState_as_json(VALUE self)
*/
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
{
+ rb_check_frozen(self);
GET_STATE(self);
RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
return Qnil;
@@ -1461,6 +1804,7 @@ static long long_config(VALUE num)
*/
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->max_nesting = long_config(depth);
return Qnil;
@@ -1486,6 +1830,7 @@ static VALUE cState_script_safe(VALUE self)
*/
static VALUE cState_script_safe_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->script_safe = RTEST(enable);
return Qnil;
@@ -1517,6 +1862,7 @@ static VALUE cState_strict(VALUE self)
*/
static VALUE cState_strict_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->strict = RTEST(enable);
return Qnil;
@@ -1541,6 +1887,7 @@ static VALUE cState_allow_nan_p(VALUE self)
*/
static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->allow_nan = RTEST(enable);
return Qnil;
@@ -1565,11 +1912,25 @@ static VALUE cState_ascii_only_p(VALUE self)
*/
static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->ascii_only = RTEST(enable);
return Qnil;
}
+static VALUE cState_allow_duplicate_key_p(VALUE self)
+{
+ GET_STATE(self);
+ switch (state->on_duplicate_key) {
+ case JSON_IGNORE:
+ return Qtrue;
+ case JSON_DEPRECATED:
+ return Qnil;
+ default:
+ return Qfalse;
+ }
+}
+
/*
* call-seq: depth
*
@@ -1589,6 +1950,7 @@ static VALUE cState_depth(VALUE self)
*/
static VALUE cState_depth_set(VALUE self, VALUE depth)
{
+ rb_check_frozen(self);
GET_STATE(self);
state->depth = long_config(depth);
return Qnil;
@@ -1622,20 +1984,36 @@ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_
*/
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
{
+ rb_check_frozen(self);
GET_STATE(self);
buffer_initial_length_set(state, buffer_initial_length);
return Qnil;
}
+struct configure_state_data {
+ JSON_Generator_State *state;
+ VALUE vstate; // Ruby object that owns the state, or Qfalse if stack-allocated
+};
+
+static inline void state_write_value(struct configure_state_data *data, VALUE *field, VALUE value)
+{
+ if (RTEST(data->vstate)) {
+ RB_OBJ_WRITE(data->vstate, field, value);
+ } else {
+ *field = value;
+ }
+}
+
static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
{
- JSON_Generator_State *state = (JSON_Generator_State *)_arg;
+ struct configure_state_data *data = (struct configure_state_data *)_arg;
+ JSON_Generator_State *state = data->state;
- if (key == sym_indent) { state->indent = string_config(val); }
- else if (key == sym_space) { state->space = string_config(val); }
- else if (key == sym_space_before) { state->space_before = string_config(val); }
- else if (key == sym_object_nl) { state->object_nl = string_config(val); }
- else if (key == sym_array_nl) { state->array_nl = string_config(val); }
+ if (key == sym_indent) { state_write_value(data, &state->indent, string_config(val)); }
+ else if (key == sym_space) { state_write_value(data, &state->space, string_config(val)); }
+ else if (key == sym_space_before) { state_write_value(data, &state->space_before, string_config(val)); }
+ else if (key == sym_object_nl) { state_write_value(data, &state->object_nl, string_config(val)); }
+ else if (key == sym_array_nl) { state_write_value(data, &state->array_nl, string_config(val)); }
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
@@ -1644,11 +2022,16 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
else if (key == sym_strict) { state->strict = RTEST(val); }
- else if (key == sym_as_json) { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; }
+ else if (key == sym_allow_duplicate_key) { state->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
+ else if (key == sym_as_json) {
+ VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
+ state->as_json_single_arg = proc && rb_proc_arity(proc) == 1;
+ state_write_value(data, &state->as_json, proc);
+ }
return ST_CONTINUE;
}
-static void configure_state(JSON_Generator_State *state, VALUE config)
+static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE config)
{
if (!RTEST(config)) return;
@@ -1656,15 +2039,21 @@ static void configure_state(JSON_Generator_State *state, VALUE config)
if (!RHASH_SIZE(config)) return;
+ struct configure_state_data data = {
+ .state = state,
+ .vstate = vstate
+ };
+
// We assume in most cases few keys are set so it's faster to go over
// the provided keys than to check all possible keys.
- rb_hash_foreach(config, configure_state_i, (VALUE)state);
+ rb_hash_foreach(config, configure_state_i, (VALUE)&data);
}
static VALUE cState_configure(VALUE self, VALUE opts)
{
+ rb_check_frozen(self);
GET_STATE(self);
- configure_state(state, opts);
+ configure_state(state, self, opts);
return self;
}
@@ -1672,7 +2061,7 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
{
JSON_Generator_State state = {0};
state_init(&state);
- configure_state(&state, opts);
+ configure_state(&state, Qfalse, opts);
char stack_buffer[FBUFFER_STACK_SIZE];
FBuffer buffer = {
@@ -1684,12 +2073,11 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
.buffer = &buffer,
.vstate = Qfalse,
.state = &state,
+ .depth = state.depth,
.obj = obj,
.func = generate_json,
};
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
-
- return fbuffer_finalize(&buffer);
+ return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
}
/*
@@ -1759,7 +2147,8 @@ void Init_generator(void)
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
rb_define_method(cState, "generate", cState_generate, -1);
- rb_define_alias(cState, "generate_new", "generate"); // :nodoc:
+
+ rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
@@ -1788,13 +2177,7 @@ void Init_generator(void)
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
- rb_define_singleton_method(mString, "included", mString_included_s, 1);
rb_define_method(mString, "to_json", mString_to_json, -1);
- rb_define_method(mString, "to_json_raw", mString_to_json_raw, -1);
- rb_define_method(mString, "to_json_raw_object", mString_to_json_raw_object, 0);
-
- mString_Extend = rb_define_module_under(mString, "Extend");
- rb_define_method(mString_Extend, "json_create", mString_Extend_json_create, 1);
VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
@@ -1811,10 +2194,6 @@ void Init_generator(void)
i_to_s = rb_intern("to_s");
i_to_json = rb_intern("to_json");
i_new = rb_intern("new");
- i_pack = rb_intern("pack");
- i_unpack = rb_intern("unpack");
- i_create_id = rb_intern("create_id");
- i_extend = rb_intern("extend");
i_encode = rb_intern("encode");
sym_indent = ID2SYM(rb_intern("indent"));
@@ -1831,10 +2210,13 @@ void Init_generator(void)
sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
sym_strict = ID2SYM(rb_intern("strict"));
sym_as_json = ID2SYM(rb_intern("as_json"));
+ sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
usascii_encindex = rb_usascii_encindex();
utf8_encindex = rb_utf8_encindex();
binary_encindex = rb_ascii8bit_encindex();
rb_require("json/ext/generator/state");
+
+ simd_impl = find_simd_implementation();
}
diff --git a/ext/json/json.gemspec b/ext/json/json.gemspec
index 943c78aab9..5575731025 100644
--- a/ext/json/json.gemspec
+++ b/ext/json/json.gemspec
@@ -44,15 +44,14 @@ spec = Gem::Specification.new do |s|
"LEGAL",
"README.md",
"json.gemspec",
- *Dir["lib/**/*.rb"],
- ]
+ ] + Dir.glob("lib/**/*.rb", base: File.expand_path("..", __FILE__))
if java_ext
s.platform = 'java'
s.files += Dir["lib/json/ext/**/*.jar"]
else
s.extensions = Dir["ext/json/**/extconf.rb"]
- s.files += Dir["ext/json/**/*.{c,h}"]
+ s.files += Dir["ext/json/**/*.{c,h,rb}"]
end
end
diff --git a/ext/json/json.h b/ext/json/json.h
new file mode 100644
index 0000000000..9379d7ae7f
--- /dev/null
+++ b/ext/json/json.h
@@ -0,0 +1,101 @@
+#ifndef _JSON_H_
+#define _JSON_H_
+
+#include "ruby.h"
+#include "ruby/encoding.h"
+#include <stdint.h>
+
+#ifndef RBIMPL_ASSERT_OR_ASSUME
+# define RBIMPL_ASSERT_OR_ASSUME(x)
+#endif
+
+#if defined(RUBY_DEBUG) && RUBY_DEBUG
+# define JSON_ASSERT RUBY_ASSERT
+#else
+# ifdef JSON_DEBUG
+# include <assert.h>
+# define JSON_ASSERT(x) assert(x)
+# else
+# define JSON_ASSERT(x)
+# endif
+#endif
+
+/* shims */
+
+#if SIZEOF_UINT64_T == SIZEOF_LONG_LONG
+# define INT64T2NUM(x) LL2NUM(x)
+# define UINT64T2NUM(x) ULL2NUM(x)
+#elif SIZEOF_UINT64_T == SIZEOF_LONG
+# define INT64T2NUM(x) LONG2NUM(x)
+# define UINT64T2NUM(x) ULONG2NUM(x)
+#else
+# error No uint64_t conversion
+#endif
+
+/* This is the fallback definition from Ruby 3.4 */
+#ifndef RBIMPL_STDBOOL_H
+#if defined(__cplusplus)
+# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
+# include <cstdbool>
+# endif
+#elif defined(HAVE_STDBOOL_H)
+# include <stdbool.h>
+#elif !defined(HAVE__BOOL)
+typedef unsigned char _Bool;
+# define bool _Bool
+# define true ((_Bool)+1)
+# define false ((_Bool)+0)
+# define __bool_true_false_are_defined
+#endif
+#endif
+
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+# undef RUBY_TYPED_FROZEN_SHAREABLE
+# define RUBY_TYPED_FROZEN_SHAREABLE 0
+#endif
+
+#ifndef NORETURN
+#define NORETURN(x) x
+#endif
+
+#ifndef NOINLINE
+#if defined(__has_attribute) && __has_attribute(noinline)
+#define NOINLINE(x) __attribute__((noinline)) x
+#else
+#define NOINLINE(x) x
+#endif
+#endif
+
+#ifndef ALWAYS_INLINE
+#if defined(__has_attribute) && __has_attribute(always_inline)
+#define ALWAYS_INLINE(x) inline __attribute__((always_inline)) x
+#else
+#define ALWAYS_INLINE(x) inline x
+#endif
+#endif
+
+#ifndef RB_UNLIKELY
+#define RB_UNLIKELY(expr) expr
+#endif
+
+#ifndef RB_LIKELY
+#define RB_LIKELY(expr) expr
+#endif
+
+#ifndef MAYBE_UNUSED
+# define MAYBE_UNUSED(x) x
+#endif
+
+#ifdef RUBY_DEBUG
+#ifndef JSON_DEBUG
+#define JSON_DEBUG RUBY_DEBUG
+#endif
+#endif
+
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && INTPTR_MAX == INT64_MAX
+#define JSON_CPU_LITTLE_ENDIAN_64BITS 1
+#else
+#define JSON_CPU_LITTLE_ENDIAN_64BITS 0
+#endif
+
+#endif // _JSON_H_
diff --git a/ext/json/lib/json.rb b/ext/json/lib/json.rb
index dfd9b7dfc2..2f6db44227 100644
--- a/ext/json/lib/json.rb
+++ b/ext/json/lib/json.rb
@@ -6,6 +6,15 @@ require 'json/common'
#
# \JSON is a lightweight data-interchange format.
#
+# \JSON is easy for us humans to read and write,
+# and equally simple for machines to read (parse) and write (generate).
+#
+# \JSON is language-independent, making it an ideal interchange format
+# for applications in differing programming languages
+# and on differing operating systems.
+#
+# == \JSON Values
+#
# A \JSON value is one of the following:
# - Double-quoted text: <tt>"foo"</tt>.
# - Number: +1+, +1.0+, +2.0e2+.
@@ -127,6 +136,24 @@ require 'json/common'
#
# ---
#
+# Option +allow_duplicate_key+ specifies whether duplicate keys in objects
+# should be ignored or cause an error to be raised:
+#
+# When not specified:
+# # The last value is used and a deprecation warning emitted.
+# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
+# # warning: detected duplicate keys in JSON object.
+# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
+#
+# When set to `+true+`
+# # The last value is used.
+# JSON.parse('{"a": 1, "a":2}') => {"a" => 2}
+#
+# When set to `+false+`, the future default:
+# JSON.parse('{"a": 1, "a":2}') => duplicate key at line 1 column 1 (JSON::ParserError)
+#
+# ---
+#
# Option +allow_nan+ (boolean) specifies whether to allow
# NaN, Infinity, and MinusInfinity in +source+;
# defaults to +false+.
@@ -143,8 +170,35 @@ require 'json/common'
# ruby = JSON.parse(source, {allow_nan: true})
# ruby # => [NaN, Infinity, -Infinity]
#
+# ---
+#
+# Option +allow_trailing_comma+ (boolean) specifies whether to allow
+# trailing commas in objects and arrays;
+# defaults to +false+.
+#
+# With the default, +false+:
+# JSON.parse('[1,]') # unexpected character: ']' at line 1 column 4 (JSON::ParserError)
+#
+# When enabled:
+# JSON.parse('[1,]', allow_trailing_comma: true) # => [1]
+#
+# ---
+#
+# Option +allow_control_characters+ (boolean) specifies whether to allow
+# unescaped ASCII control characters, such as newlines, in strings;
+# defaults to +false+.
+#
+# With the default, +false+:
+# JSON.parse(%{"Hello\nWorld"}) # invalid ASCII control character in string (JSON::ParserError)
+#
+# When enabled:
+# JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
+#
# ====== Output Options
#
+# Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
+# defaults to +false+.
+#
# Option +symbolize_names+ (boolean) specifies whether returned \Hash keys
# should be Symbols;
# defaults to +false+ (use Strings).
@@ -274,6 +328,25 @@ require 'json/common'
#
# ---
#
+# Option +allow_duplicate_key+ (boolean) specifies whether
+# hashes with duplicate keys should be allowed or produce an error.
+# defaults to emit a deprecation warning.
+#
+# With the default, (not set):
+# Warning[:deprecated] = true
+# JSON.generate({ foo: 1, "foo" => 2 })
+# # warning: detected duplicate key "foo" in {foo: 1, "foo" => 2}.
+# # This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`
+# # => '{"foo":1,"foo":2}'
+#
+# With <tt>false</tt>
+# JSON.generate({ foo: 1, "foo" => 2 }, allow_duplicate_key: false)
+# # detected duplicate key "foo" in {foo: 1, "foo" => 2} (JSON::GeneratorError)
+#
+# In version 3.0, <tt>false</tt> will become the default.
+#
+# ---
+#
# Option +max_nesting+ (\Integer) specifies the maximum nesting depth
# in +obj+; defaults to +100+.
#
@@ -351,6 +424,9 @@ require 'json/common'
#
# == \JSON Additions
#
+# Note that JSON Additions must only be used with trusted data, and is
+# deprecated.
+#
# When you "round trip" a non-\String object from Ruby to \JSON and back,
# you have a new \String, instead of the object you began with:
# ruby0 = Range.new(0, 2)
diff --git a/ext/json/lib/json/add/core.rb b/ext/json/lib/json/add/core.rb
index 485f097fff..61ff454212 100644
--- a/ext/json/lib/json/add/core.rb
+++ b/ext/json/lib/json/add/core.rb
@@ -7,6 +7,7 @@ require 'json/add/date_time'
require 'json/add/exception'
require 'json/add/range'
require 'json/add/regexp'
+require 'json/add/string'
require 'json/add/struct'
require 'json/add/symbol'
require 'json/add/time'
diff --git a/ext/json/lib/json/add/string.rb b/ext/json/lib/json/add/string.rb
new file mode 100644
index 0000000000..9c3bde27fb
--- /dev/null
+++ b/ext/json/lib/json/add/string.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
+ require 'json'
+end
+
+class String
+ # call-seq: json_create(o)
+ #
+ # Raw Strings are JSON Objects (the raw bytes are stored in an array for the
+ # key "raw"). The Ruby String can be created by this class method.
+ def self.json_create(object)
+ object["raw"].pack("C*")
+ end
+
+ # call-seq: to_json_raw_object()
+ #
+ # This method creates a raw object hash, that can be nested into
+ # other data structures and will be generated as a raw string. This
+ # method should be used, if you want to convert raw strings to JSON
+ # instead of UTF-8 strings, e. g. binary data.
+ def to_json_raw_object
+ {
+ JSON.create_id => self.class.name,
+ "raw" => unpack("C*"),
+ }
+ end
+
+ # call-seq: to_json_raw(*args)
+ #
+ # This method creates a JSON text from the result of a call to
+ # to_json_raw_object of this String.
+ def to_json_raw(...)
+ to_json_raw_object.to_json(...)
+ end
+end
diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb
index b5fbfcf05d..877b96814e 100644
--- a/ext/json/lib/json/common.rb
+++ b/ext/json/lib/json/common.rb
@@ -48,7 +48,7 @@ module JSON
end
end
- # TODO: exctract :create_additions support to another gem for version 3.0
+ # TODO: extract :create_additions support to another gem for version 3.0
def create_additions_proc(opts)
if opts[:symbolize_names]
raise ArgumentError, "options :symbolize_names and :create_additions cannot be used in conjunction"
@@ -71,9 +71,14 @@ module JSON
end
when object_class
if opts[:create_additions] != false
- if class_name = object[JSON.create_id]
- klass = JSON.deep_const_get(class_name)
- if (klass.respond_to?(:json_creatable?) && klass.json_creatable?) || klass.respond_to?(:json_create)
+ if class_path = object[JSON.create_id]
+ klass = begin
+ Object.const_get(class_path)
+ rescue NameError => e
+ raise ArgumentError, "can't get const #{class_path}: #{e}"
+ end
+
+ if klass.respond_to?(:json_creatable?) ? klass.json_creatable? : klass.respond_to?(:json_create)
create_additions_warning if create_additions.nil?
object = klass.json_create(object)
end
@@ -87,31 +92,32 @@ module JSON
opts
end
- GEM_ROOT = File.expand_path("../../../", __FILE__) + "/"
def create_additions_warning
- message = "JSON.load implicit support for `create_additions: true` is deprecated " \
+ JSON.deprecation_warning "JSON.load implicit support for `create_additions: true` is deprecated " \
"and will be removed in 3.0, use JSON.unsafe_load or explicitly " \
"pass `create_additions: true`"
+ end
+ end
+ end
- uplevel = 4
- caller_locations(uplevel, 10).each do |frame|
- if frame.path.nil? || frame.path.start_with?(GEM_ROOT) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
- uplevel += 1
- else
- break
- end
- end
-
- if RUBY_VERSION >= "3.0"
- warn(message, uplevel: uplevel - 1, category: :deprecated)
+ class << self
+ def deprecation_warning(message, uplevel = 3) # :nodoc:
+ gem_root = File.expand_path("..", __dir__) + "/"
+ caller_locations(uplevel, 10).each do |frame|
+ if frame.path.nil? || frame.path.start_with?(gem_root) || frame.path.end_with?("/truffle/cext_ruby.rb", ".c")
+ uplevel += 1
else
- warn(message, uplevel: uplevel - 1)
+ break
end
end
+
+ if RUBY_VERSION >= "3.0"
+ warn(message, uplevel: uplevel, category: :deprecated)
+ else
+ warn(message, uplevel: uplevel)
+ end
end
- end
- class << self
# :call-seq:
# JSON[object] -> new_array or new_string
#
@@ -146,16 +152,6 @@ module JSON
const_set :Parser, parser
end
- # Return the constant located at _path_. The format of _path_ has to be
- # either ::A::B::C or A::B::C. In any case, A has to be located at the top
- # level (absolute namespace path?). If there doesn't exist a constant at
- # the given path, an ArgumentError is raised.
- def deep_const_get(path) # :nodoc:
- Object.const_get(path)
- rescue NameError => e
- raise ArgumentError, "can't get const #{path}: #{e}"
- end
-
# Set the module _generator_ to be used by JSON.
def generator=(generator) # :nodoc:
old, $VERBOSE = $VERBOSE, nil
@@ -172,7 +168,7 @@ module JSON
end
end
self.state = generator::State
- const_set :State, self.state
+ const_set :State, state
ensure
$VERBOSE = old
end
@@ -185,6 +181,25 @@ module JSON
private
+ # Called from the extension when a hash has both string and symbol keys
+ def on_mixed_keys_hash(hash, do_raise)
+ set = {}
+ hash.each_key do |key|
+ key_str = key.to_s
+
+ if set[key_str]
+ message = "detected duplicate key #{key_str.inspect} in #{hash.inspect}"
+ if do_raise
+ raise GeneratorError, message
+ else
+ deprecation_warning("#{message}.\nThis will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`")
+ end
+ else
+ set[key_str] = true
+ end
+ end
+ end
+
def deprecated_singleton_attr_accessor(*attrs)
args = RUBY_VERSION >= "3.0" ? ", category: :deprecated" : ""
attrs.each do |attr|
@@ -230,16 +245,14 @@ module JSON
class JSONError < StandardError; end
# This exception is raised if a parser error occurs.
- class ParserError < JSONError; end
+ class ParserError < JSONError
+ attr_reader :line, :column
+ end
# This exception is raised if the nesting of parsed data structures is too
# deep.
class NestingError < ParserError; end
- # :stopdoc:
- class CircularDatastructure < NestingError; end
- # :startdoc:
-
# This exception is raised if a generator or unparser error occurs.
class GeneratorError < JSONError
attr_reader :invalid_object
@@ -270,7 +283,7 @@ module JSON
# to string interpolation.
#
# Note: no validation is performed on the provided string. It is the
- # responsability of the caller to ensure the string contains valid JSON.
+ # responsibility of the caller to ensure the string contains valid JSON.
Fragment = Struct.new(:json) do
def initialize(json)
unless string = String.try_convert(json)
@@ -392,7 +405,7 @@ module JSON
#
# Returns a \String containing the generated \JSON data.
#
- # See also JSON.fast_generate, JSON.pretty_generate.
+ # See also JSON.pretty_generate.
#
# Argument +obj+ is the Ruby object to be converted to \JSON.
#
@@ -492,7 +505,7 @@ module JSON
# }
#
def pretty_generate(obj, opts = nil)
- return state.generate(obj) if State === opts
+ return opts.generate(obj) if State === opts
options = PRETTY_GENERATE_OPTIONS
@@ -537,6 +550,7 @@ module JSON
:create_additions => nil,
}
# :call-seq:
+ # JSON.unsafe_load(source, options = {}) -> object
# JSON.unsafe_load(source, proc = nil, options = {}) -> object
#
# Returns the Ruby objects created by parsing the given +source+.
@@ -644,6 +658,7 @@ module JSON
# when Array
# obj.map! {|v| deserialize_obj v }
# end
+ # obj
# })
# pp ruby
# Output:
@@ -667,7 +682,12 @@ module JSON
#
def unsafe_load(source, proc = nil, options = nil)
opts = if options.nil?
- _unsafe_load_default_options
+ if proc && proc.is_a?(Hash)
+ options, proc = proc, nil
+ options
+ else
+ _unsafe_load_default_options
+ end
else
_unsafe_load_default_options.merge(options)
end
@@ -685,12 +705,17 @@ module JSON
if opts[:allow_blank] && (source.nil? || source.empty?)
source = 'null'
end
- result = parse(source, opts)
- recurse_proc(result, &proc) if proc
- result
+
+ if proc
+ opts = opts.dup
+ opts[:on_load] = proc.to_proc
+ end
+
+ parse(source, opts)
end
# :call-seq:
+ # JSON.load(source, options = {}) -> object
# JSON.load(source, proc = nil, options = {}) -> object
#
# Returns the Ruby objects created by parsing the given +source+.
@@ -804,6 +829,7 @@ module JSON
# when Array
# obj.map! {|v| deserialize_obj v }
# end
+ # obj
# })
# pp ruby
# Output:
@@ -826,8 +852,18 @@ module JSON
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
#
def load(source, proc = nil, options = nil)
+ if proc && options.nil? && proc.is_a?(Hash)
+ options = proc
+ proc = nil
+ end
+
opts = if options.nil?
- _load_default_options
+ if proc && proc.is_a?(Hash)
+ options, proc = proc, nil
+ options
+ else
+ _load_default_options
+ end
else
_load_default_options.merge(options)
end
@@ -923,6 +959,68 @@ module JSON
end
end
+ # :stopdoc:
+ # All these were meant to be deprecated circa 2009, but were just set as undocumented
+ # so usage still exist in the wild.
+ def unparse(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
+ end
+ generate(...)
+ end
+ module_function :unparse
+
+ def fast_unparse(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.fast_unparse is deprecated and will be removed in json 3.0.0, just use JSON.generate", uplevel: 1
+ end
+ generate(...)
+ end
+ module_function :fast_unparse
+
+ def pretty_unparse(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.pretty_unparse is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
+ end
+ pretty_generate(...)
+ end
+ module_function :fast_unparse
+
+ def restore(...)
+ if RUBY_VERSION >= "3.0"
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1, category: :deprecated
+ else
+ warn "JSON.restore is deprecated and will be removed in json 3.0.0, just use JSON.load", uplevel: 1
+ end
+ load(...)
+ end
+ module_function :restore
+
+ class << self
+ private
+
+ def const_missing(const_name)
+ case const_name
+ when :PRETTY_STATE_PROTOTYPE
+ if RUBY_VERSION >= "3.0"
+ warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1, category: :deprecated
+ else
+ warn "JSON::PRETTY_STATE_PROTOTYPE is deprecated and will be removed in json 3.0.0, just use JSON.pretty_generate", uplevel: 1
+ end
+ state.new(PRETTY_GENERATE_OPTIONS)
+ else
+ super
+ end
+ end
+ end
+ # :startdoc:
+
# JSON::Coder holds a parser and generator configuration.
#
# module MyApp
@@ -941,7 +1039,7 @@ module JSON
# See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
#
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
- # encoutered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
+ # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
# \JSON counterpart:
#
# module MyApp
@@ -967,7 +1065,7 @@ module JSON
options[:as_json] = as_json if as_json
@state = State.new(options).freeze
- @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options))
+ @parser_config = Ext::Parser::Config.new(ParserOptions.prepare(options)).freeze
end
# call-seq:
@@ -976,7 +1074,7 @@ module JSON
#
# Serialize the given object into a \JSON document.
def dump(object, io = nil)
- @state.generate_new(object, io)
+ @state.generate(object, io)
end
alias_method :generate, :dump
@@ -1012,7 +1110,7 @@ module ::Kernel
end
objs.each do |obj|
- puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
+ puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
end
nil
end
@@ -1027,7 +1125,7 @@ module ::Kernel
end
objs.each do |obj|
- puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
+ puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
end
nil
end
diff --git a/ext/json/lib/json/ext.rb b/ext/json/lib/json/ext.rb
index 1db5ea122c..5bacc5e371 100644
--- a/ext/json/lib/json/ext.rb
+++ b/ext/json/lib/json/ext.rb
@@ -34,12 +34,12 @@ module JSON
if RUBY_ENGINE == 'truffleruby'
require 'json/truffle_ruby/generator'
- JSON.generator = ::JSON::TruffleRuby::Generator
+ JSON.generator = JSON::TruffleRuby::Generator
else
require 'json/ext/generator'
JSON.generator = Generator
end
end
- JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
+ JSON_LOADED = true unless defined?(JSON::JSON_LOADED)
end
diff --git a/ext/json/lib/json/ext/generator/state.rb b/ext/json/lib/json/ext/generator/state.rb
index d40c3b5ec3..ce5c185cab 100644
--- a/ext/json/lib/json/ext/generator/state.rb
+++ b/ext/json/lib/json/ext/generator/state.rb
@@ -8,20 +8,8 @@ module JSON
#
# Instantiates a new State object, configured by _opts_.
#
- # _opts_ can have the following keys:
- #
- # * *indent*: a string used to indent levels (default: ''),
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
- # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
- # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
- # generated, otherwise an exception is thrown, if these values are
- # encountered. This options defaults to false.
- # * *ascii_only*: true if only ASCII characters should be generated. This
- # option defaults to false.
- # * *buffer_initial_length*: sets the initial length of the generator's
- # internal buffer.
+ # Argument +opts+, if given, contains a \Hash of options for the generation.
+ # See {Generating Options}[#module-JSON-label-Generating+Options].
def initialize(opts = nil)
if opts && !opts.empty?
configure(opts)
@@ -68,6 +56,11 @@ module JSON
buffer_initial_length: buffer_initial_length,
}
+ allow_duplicate_key = allow_duplicate_key?
+ unless allow_duplicate_key.nil?
+ result[:allow_duplicate_key] = allow_duplicate_key
+ end
+
instance_variables.each do |iv|
iv = iv.to_s[1..-1]
result[iv.to_sym] = self[iv]
@@ -82,6 +75,8 @@ module JSON
#
# Returns the value returned by method +name+.
def [](name)
+ ::JSON.deprecation_warning("JSON::State#[] is deprecated and will be removed in json 3.0.0")
+
if respond_to?(name)
__send__(name)
else
@@ -94,6 +89,8 @@ module JSON
#
# Sets the attribute name to value.
def []=(name, value)
+ ::JSON.deprecation_warning("JSON::State#[]= is deprecated and will be removed in json 3.0.0")
+
if respond_to?(name_writer = "#{name}=")
__send__ name_writer, value
else
diff --git a/ext/json/lib/json/generic_object.rb b/ext/json/lib/json/generic_object.rb
index ec5aa9dcb2..5c8ace354b 100644
--- a/ext/json/lib/json/generic_object.rb
+++ b/ext/json/lib/json/generic_object.rb
@@ -52,14 +52,6 @@ module JSON
table
end
- def [](name)
- __send__(name)
- end unless method_defined?(:[])
-
- def []=(name, value)
- __send__("#{name}=", value)
- end unless method_defined?(:[]=)
-
def |(other)
self.class[other.to_hash.merge(to_hash)]
end
diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb
index 9c21f18b35..631beba83e 100644
--- a/ext/json/lib/json/version.rb
+++ b/ext/json/lib/json/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module JSON
- VERSION = '2.10.2'
+ VERSION = '2.18.0'
end
diff --git a/ext/json/parser/depend b/ext/json/parser/depend
index 0c1becfb60..d4737b1dfb 100644
--- a/ext/json/parser/depend
+++ b/ext/json/parser/depend
@@ -141,6 +141,7 @@ parser.o: $(hdrdir)/ruby/internal/intern/re.h
parser.o: $(hdrdir)/ruby/internal/intern/ruby.h
parser.o: $(hdrdir)/ruby/internal/intern/select.h
parser.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+parser.o: $(hdrdir)/ruby/internal/intern/set.h
parser.o: $(hdrdir)/ruby/internal/intern/signal.h
parser.o: $(hdrdir)/ruby/internal/intern/sprintf.h
parser.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -174,5 +175,8 @@ parser.o: $(hdrdir)/ruby/ruby.h
parser.o: $(hdrdir)/ruby/st.h
parser.o: $(hdrdir)/ruby/subst.h
parser.o: $(srcdir)/../fbuffer/fbuffer.h
+parser.o: $(srcdir)/../json.h
+parser.o: $(srcdir)/../simd/simd.h
+parser.o: $(srcdir)/../vendor/ryu.h
parser.o: parser.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb
index 09c9637788..2440e66d8b 100644
--- a/ext/json/parser/extconf.rb
+++ b/ext/json/parser/extconf.rb
@@ -1,11 +1,16 @@
# frozen_string_literal: true
require 'mkmf'
-have_func("rb_enc_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
+$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
+have_func("rb_enc_interned_str", "ruby/encoding.h") # RUBY_VERSION >= 3.0
+have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
-have_func("strnlen", "string.h") # Missing on Solaris 10
append_cflags("-std=c99")
+if enable_config('parser-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
+ load __dir__ + "/../simd/conf.rb"
+end
+
create_makefile 'json/ext/parser'
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index f20769a365..f1ea1b6abb 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -1,48 +1,21 @@
-#include "ruby.h"
-#include "ruby/encoding.h"
-
-/* shims */
-/* This is the fallback definition from Ruby 3.4 */
-
-#ifndef RBIMPL_STDBOOL_H
-#if defined(__cplusplus)
-# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
-# include <cstdbool>
-# endif
-#elif defined(HAVE_STDBOOL_H)
-# include <stdbool.h>
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
-#endif
-#endif
-
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(expr) expr
-#endif
-
-#ifndef RB_LIKELY
-#define RB_LIKELY(expr) expr
-#endif
+#include "../json.h"
+#include "../vendor/ryu.h"
+#include "../simd/simd.h"
static VALUE mJSON, eNestingError, Encoding_UTF_8;
static VALUE CNaN, CInfinity, CMinusInfinity;
-static ID i_chr, i_aset, i_aref,
- i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
+static ID i_new, i_try_convert, i_uminus, i_encode;
-static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
- sym_decimal_class, sym_on_load;
+static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters, sym_symbolize_names, sym_freeze,
+ sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
static int binary_encindex;
static int utf8_encindex;
#ifndef HAVE_RB_HASH_BULK_INSERT
// For TruffleRuby
-void
+static void
rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
{
long index = 0;
@@ -59,6 +32,12 @@ rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
#define rb_hash_new_capa(n) rb_hash_new()
#endif
+#ifndef HAVE_RB_STR_TO_INTERNED_STR
+static VALUE rb_str_to_interned_str(VALUE str)
+{
+ return rb_funcall(rb_str_freeze(str), i_uminus, 0);
+}
+#endif
/* name cache */
@@ -104,116 +83,104 @@ static void rvalue_cache_insert_at(rvalue_cache *cache, int index, VALUE rstring
cache->entries[index] = rstring;
}
-static inline int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
+#define rstring_cache_memcmp memcmp
+
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+#if __has_builtin(__builtin_bswap64)
+#undef rstring_cache_memcmp
+ALWAYS_INLINE(static) int rstring_cache_memcmp(const char *str, const char *rptr, const long length)
{
- long rstring_length = RSTRING_LEN(rstring);
- if (length == rstring_length) {
- return memcmp(str, RSTRING_PTR(rstring), length);
- } else {
- return (int)(length - rstring_length);
+ // The libc memcmp has numerous complex optimizations, but in this particular case,
+ // we know the string is small (JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH), so being able to
+ // inline a simpler memcmp outperforms calling the libc version.
+ long i = 0;
+
+ for (; i + 8 <= length; i += 8) {
+ uint64_t a, b;
+ memcpy(&a, str + i, 8);
+ memcpy(&b, rptr + i, 8);
+ if (a != b) {
+ a = __builtin_bswap64(a);
+ b = __builtin_bswap64(b);
+ return (a < b) ? -1 : 1;
+ }
+ }
+
+ for (; i < length; i++) {
+ if (str[i] != rptr[i]) {
+ return (str[i] < rptr[i]) ? -1 : 1;
+ }
}
+
+ return 0;
}
+#endif
+#endif
-static VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length)
+ALWAYS_INLINE(static) int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
{
- if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
- // Common names aren't likely to be very long. So we just don't
- // cache names above an arbitrary threshold.
- return Qfalse;
- }
+ const char *rstring_ptr;
+ long rstring_length;
- if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) {
- // Simple heuristic, if the first character isn't a letter,
- // we're much less likely to see this string again.
- // We mostly want to cache strings that are likely to be repeated.
- return Qfalse;
+ RSTRING_GETMEM(rstring, rstring_ptr, rstring_length);
+
+ if (length == rstring_length) {
+ return rstring_cache_memcmp(str, rstring_ptr, length);
+ } else {
+ return (int)(length - rstring_length);
}
+}
+ALWAYS_INLINE(static) VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length)
+{
int low = 0;
int high = cache->length - 1;
- int mid = 0;
- int last_cmp = 0;
while (low <= high) {
- mid = (high + low) >> 1;
+ int mid = (high + low) >> 1;
VALUE entry = cache->entries[mid];
- last_cmp = rstring_cache_cmp(str, length, entry);
+ int cmp = rstring_cache_cmp(str, length, entry);
- if (last_cmp == 0) {
+ if (cmp == 0) {
return entry;
- } else if (last_cmp > 0) {
+ } else if (cmp > 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rstring = build_interned_string(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
- if (last_cmp > 0) {
- mid += 1;
- }
-
- rvalue_cache_insert_at(cache, mid, rstring);
+ rvalue_cache_insert_at(cache, low, rstring);
}
return rstring;
}
static VALUE rsymbol_cache_fetch(rvalue_cache *cache, const char *str, const long length)
{
- if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
- // Common names aren't likely to be very long. So we just don't
- // cache names above an arbitrary threshold.
- return Qfalse;
- }
-
- if (RB_UNLIKELY(!isalpha((unsigned char)str[0]))) {
- // Simple heuristic, if the first character isn't a letter,
- // we're much less likely to see this string again.
- // We mostly want to cache strings that are likely to be repeated.
- return Qfalse;
- }
-
int low = 0;
int high = cache->length - 1;
- int mid = 0;
- int last_cmp = 0;
while (low <= high) {
- mid = (high + low) >> 1;
+ int mid = (high + low) >> 1;
VALUE entry = cache->entries[mid];
- last_cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
+ int cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
- if (last_cmp == 0) {
+ if (cmp == 0) {
return entry;
- } else if (last_cmp > 0) {
+ } else if (cmp > 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rsymbol = build_symbol(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
- if (last_cmp > 0) {
- mid += 1;
- }
-
- rvalue_cache_insert_at(cache, mid, rsymbol);
+ rvalue_cache_insert_at(cache, low, rsymbol);
}
return rsymbol;
}
@@ -328,82 +295,6 @@ static void rvalue_stack_eagerly_release(VALUE handle)
}
}
-
-#ifndef HAVE_STRNLEN
-static size_t strnlen(const char *s, size_t maxlen)
-{
- char *p;
- return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen);
-}
-#endif
-
-#define PARSE_ERROR_FRAGMENT_LEN 32
-#ifdef RBIMPL_ATTR_NORETURN
-RBIMPL_ATTR_NORETURN()
-#endif
-static void raise_parse_error(const char *format, const char *start)
-{
- unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
-
- size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
- const char *ptr = start;
-
- if (len == PARSE_ERROR_FRAGMENT_LEN) {
- MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
-
- while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
- len--;
- }
-
- if (buffer[len - 1] >= 0xC0) { // multibyte character start
- len--;
- }
-
- buffer[len] = '\0';
- ptr = (const char *)buffer;
- }
-
- rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
-}
-
-/* unicode */
-
-static const signed char digit_values[256] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
- -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1
-};
-
-static uint32_t unescape_unicode(const unsigned char *p)
-{
- signed char b;
- uint32_t result = 0;
- b = digit_values[p[0]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[1]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[2]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[3]];
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
- result = (result << 4) | (unsigned char)b;
- return result;
-}
-
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
{
int len = 1;
@@ -430,20 +321,28 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
return len;
}
+enum duplicate_key_action {
+ JSON_DEPRECATED = 0,
+ JSON_IGNORE,
+ JSON_RAISE,
+};
+
typedef struct JSON_ParserStruct {
VALUE on_load_proc;
VALUE decimal_class;
ID decimal_method_id;
+ enum duplicate_key_action on_duplicate_key;
int max_nesting;
bool allow_nan;
bool allow_trailing_comma;
- bool parsing_name;
+ bool allow_control_characters;
bool symbolize_names;
bool freeze;
} JSON_ParserConfig;
typedef struct JSON_ParserStateStruct {
VALUE stack_handle;
+ const char *start;
const char *cursor;
const char *end;
rvalue_stack *stack;
@@ -452,68 +351,234 @@ typedef struct JSON_ParserStateStruct {
int current_nesting;
} JSON_ParserState;
+static inline size_t rest(JSON_ParserState *state) {
+ return state->end - state->cursor;
+}
+
+static inline bool eos(JSON_ParserState *state) {
+ return state->cursor >= state->end;
+}
+
+static inline char peek(JSON_ParserState *state)
+{
+ if (RB_UNLIKELY(eos(state))) {
+ return 0;
+ }
+ return *state->cursor;
+}
+
+static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out)
+{
+ const char *cursor = state->cursor;
+ long column = 0;
+ long line = 1;
+
+ while (cursor >= state->start) {
+ if (*cursor-- == '\n') {
+ break;
+ }
+ column++;
+ }
+
+ while (cursor >= state->start) {
+ if (*cursor-- == '\n') {
+ line++;
+ }
+ }
+ *line_out = line;
+ *column_out = column;
+}
+
+static void emit_parse_warning(const char *message, JSON_ParserState *state)
+{
+ long line, column;
+ cursor_position(state, &line, &column);
+
+ VALUE warning = rb_sprintf("%s at line %ld column %ld", message, line, column);
+ rb_funcall(mJSON, rb_intern("deprecation_warning"), 1, warning);
+}
+
+#define PARSE_ERROR_FRAGMENT_LEN 32
+
+#ifdef RBIMPL_ATTR_NORETURN
+RBIMPL_ATTR_NORETURN()
+#endif
+static void raise_parse_error(const char *format, JSON_ParserState *state)
+{
+ unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
+ long line, column;
+ cursor_position(state, &line, &column);
+
+ const char *ptr = "EOF";
+ if (state->cursor && state->cursor < state->end) {
+ ptr = state->cursor;
+ size_t len = 0;
+ while (len < PARSE_ERROR_FRAGMENT_LEN) {
+ char ch = ptr[len];
+ if (!ch || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r') {
+ break;
+ }
+ len++;
+ }
+
+ if (len) {
+ buffer[0] = '\'';
+ MEMCPY(buffer + 1, ptr, char, len);
+
+ while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
+ len--;
+ }
+
+ if (buffer[len] >= 0xC0) { // multibyte character start
+ len--;
+ }
+
+ buffer[len + 1] = '\'';
+ buffer[len + 2] = '\0';
+ ptr = (const char *)buffer;
+ }
+ }
+
+ VALUE msg = rb_sprintf(format, ptr);
+ VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
+ RB_GC_GUARD(msg);
+
+ VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
+ rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
+ rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
+ rb_exc_raise(exc);
+}
+
+#ifdef RBIMPL_ATTR_NORETURN
+RBIMPL_ATTR_NORETURN()
+#endif
+static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
+{
+ state->cursor = at;
+ raise_parse_error(format, state);
+}
+
+/* unicode */
+
+static const signed char digit_values[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
+ -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1
+};
+
+static uint32_t unescape_unicode(JSON_ParserState *state, const char *sp, const char *spe)
+{
+ if (RB_UNLIKELY(sp > spe - 4)) {
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, sp - 2);
+ }
+
+ const unsigned char *p = (const unsigned char *)sp;
+
+ const signed char b0 = digit_values[p[0]];
+ const signed char b1 = digit_values[p[1]];
+ const signed char b2 = digit_values[p[2]];
+ const signed char b3 = digit_values[p[3]];
+
+ if (RB_UNLIKELY((signed char)(b0 | b1 | b2 | b3) < 0)) {
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, sp - 2);
+ }
+
+ return ((uint32_t)b0 << 12) | ((uint32_t)b1 << 8) | ((uint32_t)b2 << 4) | (uint32_t)b3;
+}
+
#define GET_PARSER_CONFIG \
JSON_ParserConfig *config; \
TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
static const rb_data_type_t JSON_ParserConfig_type;
-static const bool whitespace[256] = {
- [' '] = 1,
- ['\t'] = 1,
- ['\n'] = 1,
- ['\r'] = 1,
- ['/'] = 1,
-};
-
static void
json_eat_comments(JSON_ParserState *state)
{
- if (state->cursor + 1 < state->end) {
- switch(state->cursor[1]) {
- case '/': {
- state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
- if (!state->cursor) {
- state->cursor = state->end;
- } else {
- state->cursor++;
- }
- break;
+ const char *start = state->cursor;
+ state->cursor++;
+
+ switch (peek(state)) {
+ case '/': {
+ state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
+ if (!state->cursor) {
+ state->cursor = state->end;
+ } else {
+ state->cursor++;
}
- case '*': {
- state->cursor += 2;
- while (true) {
- state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
- if (!state->cursor) {
- state->cursor = state->end;
- raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
- } else {
- state->cursor++;
- if (state->cursor < state->end && *state->cursor == '/') {
- state->cursor++;
- break;
- }
- }
+ break;
+ }
+ case '*': {
+ state->cursor++;
+
+ while (true) {
+ const char *next_match = memchr(state->cursor, '*', state->end - state->cursor);
+ if (!next_match) {
+ raise_parse_error_at("unterminated comment, expected closing '*/'", state, start);
+ }
+
+ state->cursor = next_match + 1;
+ if (peek(state) == '/') {
+ state->cursor++;
+ break;
}
- break;
}
- default:
- raise_parse_error("unexpected token at '%s'", state->cursor);
- break;
+ break;
}
- } else {
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ default:
+ raise_parse_error_at("unexpected token %s", state, start);
+ break;
}
}
-static inline void
+ALWAYS_INLINE(static) void
json_eat_whitespace(JSON_ParserState *state)
{
- while (state->cursor < state->end && RB_UNLIKELY(whitespace[(unsigned char)*state->cursor])) {
- if (RB_LIKELY(*state->cursor != '/')) {
- state->cursor++;
- } else {
- json_eat_comments(state);
+ while (true) {
+ switch (peek(state)) {
+ case ' ':
+ state->cursor++;
+ break;
+ case '\n':
+ state->cursor++;
+
+ // Heuristic: if we see a newline, there is likely consecutive spaces after it.
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+ while (rest(state) > 8) {
+ uint64_t chunk;
+ memcpy(&chunk, state->cursor, sizeof(uint64_t));
+ if (chunk == 0x2020202020202020) {
+ state->cursor += 8;
+ continue;
+ }
+
+ uint32_t consecutive_spaces = trailing_zeros64(chunk ^ 0x2020202020202020) / CHAR_BIT;
+ state->cursor += consecutive_spaces;
+ break;
+ }
+#endif
+ break;
+ case '\t':
+ case '\r':
+ state->cursor++;
+ break;
+ case '/':
+ json_eat_comments(state);
+ break;
+
+ default:
+ return;
}
}
}
@@ -544,11 +609,22 @@ static inline VALUE build_string(const char *start, const char *end, bool intern
return result;
}
-static inline VALUE json_string_fastpath(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize)
+static inline bool json_string_cacheable_p(const char *string, size_t length)
+{
+ // We mostly want to cache strings that are likely to be repeated.
+ // Simple heuristics:
+ // - Common names aren't likely to be very long. So we just don't cache names above an arbitrary threshold.
+ // - If the first character isn't a letter, we're much less likely to see this string again.
+ return length <= JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH && rb_isalpha(string[0]);
+}
+
+static inline VALUE json_string_fastpath(JSON_ParserState *state, JSON_ParserConfig *config, const char *string, const char *stringEnd, bool is_name)
{
+ bool intern = is_name || config->freeze;
+ bool symbolize = is_name && config->symbolize_names;
size_t bufferSize = stringEnd - string;
- if (is_name && state->in_array) {
+ if (is_name && state->in_array && RB_LIKELY(json_string_cacheable_p(string, bufferSize))) {
VALUE cached_key;
if (RB_UNLIKELY(symbolize)) {
cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
@@ -564,104 +640,125 @@ static inline VALUE json_string_fastpath(JSON_ParserState *state, const char *st
return build_string(string, stringEnd, intern, symbolize);
}
-static VALUE json_string_unescape(JSON_ParserState *state, const char *string, const char *stringEnd, bool is_name, bool intern, bool symbolize)
-{
- size_t bufferSize = stringEnd - string;
- const char *p = string, *pe = string, *unescape, *bufferStart;
- char *buffer;
- int unescape_len;
- char buf[4];
+#define JSON_MAX_UNESCAPE_POSITIONS 16
+typedef struct _json_unescape_positions {
+ long size;
+ const char **positions;
+ unsigned long additional_backslashes;
+} JSON_UnescapePositions;
- if (is_name && state->in_array) {
- VALUE cached_key;
- if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
- } else {
- cached_key = rstring_cache_fetch(&state->name_cache, string, bufferSize);
+static inline const char *json_next_backslash(const char *pe, const char *stringEnd, JSON_UnescapePositions *positions)
+{
+ while (positions->size) {
+ positions->size--;
+ const char *next_position = positions->positions[0];
+ positions->positions++;
+ if (next_position >= pe) {
+ return next_position;
}
+ }
- if (RB_LIKELY(cached_key)) {
- return cached_key;
- }
+ if (positions->additional_backslashes) {
+ positions->additional_backslashes--;
+ return memchr(pe, '\\', stringEnd - pe);
}
+ return NULL;
+}
+
+NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_ParserConfig *config, const char *string, const char *stringEnd, bool is_name, JSON_UnescapePositions *positions)
+{
+ bool intern = is_name || config->freeze;
+ bool symbolize = is_name && config->symbolize_names;
+ size_t bufferSize = stringEnd - string;
+ const char *p = string, *pe = string, *bufferStart;
+ char *buffer;
+
VALUE result = rb_str_buf_new(bufferSize);
rb_enc_associate_index(result, utf8_encindex);
buffer = RSTRING_PTR(result);
bufferStart = buffer;
- while (pe < stringEnd && (pe = memchr(pe, '\\', stringEnd - pe))) {
- unescape = (char *) "?";
- unescape_len = 1;
+#define APPEND_CHAR(chr) *buffer++ = chr; p = ++pe;
+
+ while (pe < stringEnd && (pe = json_next_backslash(pe, stringEnd, positions))) {
if (pe > p) {
MEMCPY(buffer, p, char, pe - p);
buffer += pe - p;
}
switch (*++pe) {
+ case '"':
+ case '/':
+ p = pe; // nothing to unescape just need to skip the backslash
+ break;
+ case '\\':
+ APPEND_CHAR('\\');
+ break;
case 'n':
- unescape = (char *) "\n";
+ APPEND_CHAR('\n');
break;
case 'r':
- unescape = (char *) "\r";
+ APPEND_CHAR('\r');
break;
case 't':
- unescape = (char *) "\t";
- break;
- case '"':
- unescape = (char *) "\"";
- break;
- case '\\':
- unescape = (char *) "\\";
+ APPEND_CHAR('\t');
break;
case 'b':
- unescape = (char *) "\b";
+ APPEND_CHAR('\b');
break;
case 'f':
- unescape = (char *) "\f";
+ APPEND_CHAR('\f');
break;
- case 'u':
- if (pe > stringEnd - 5) {
- raise_parse_error("incomplete unicode character escape sequence at '%s'", p);
- } else {
- uint32_t ch = unescape_unicode((unsigned char *) ++pe);
- pe += 3;
- /* To handle values above U+FFFF, we take a sequence of
- * \uXXXX escapes in the U+D800..U+DBFF then
- * U+DC00..U+DFFF ranges, take the low 10 bits from each
- * to make a 20-bit number, then add 0x10000 to get the
- * final codepoint.
- *
- * See Unicode 15: 3.8 "Surrogates", 5.3 "Handling
- * Surrogate Pairs in UTF-16", and 23.6 "Surrogates
- * Area".
- */
- if ((ch & 0xFC00) == 0xD800) {
- pe++;
- if (pe > stringEnd - 6) {
- raise_parse_error("incomplete surrogate pair at '%s'", p);
- }
- if (pe[0] == '\\' && pe[1] == 'u') {
- uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
- ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
- | (sur & 0x3FF));
- pe += 5;
- } else {
- unescape = (char *) "?";
- break;
+ case 'u': {
+ uint32_t ch = unescape_unicode(state, ++pe, stringEnd);
+ pe += 3;
+ /* To handle values above U+FFFF, we take a sequence of
+ * \uXXXX escapes in the U+D800..U+DBFF then
+ * U+DC00..U+DFFF ranges, take the low 10 bits from each
+ * to make a 20-bit number, then add 0x10000 to get the
+ * final codepoint.
+ *
+ * See Unicode 15: 3.8 "Surrogates", 5.3 "Handling
+ * Surrogate Pairs in UTF-16", and 23.6 "Surrogates
+ * Area".
+ */
+ if ((ch & 0xFC00) == 0xD800) {
+ pe++;
+ if (RB_LIKELY((pe <= stringEnd - 6) && memcmp(pe, "\\u", 2) == 0)) {
+ uint32_t sur = unescape_unicode(state, pe + 2, stringEnd);
+
+ if (RB_UNLIKELY((sur & 0xFC00) != 0xDC00)) {
+ raise_parse_error_at("invalid surrogate pair at %s", state, p);
}
+
+ ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16) | (sur & 0x3FF));
+ pe += 5;
+ } else {
+ raise_parse_error_at("incomplete surrogate pair at %s", state, p);
+ break;
}
- unescape_len = convert_UTF32_to_UTF8(buf, ch);
- unescape = buf;
}
+
+ int unescape_len = convert_UTF32_to_UTF8(buffer, ch);
+ buffer += unescape_len;
+ p = ++pe;
break;
+ }
default:
- p = pe;
- continue;
+ if ((unsigned char)*pe < 0x20) {
+ if (!config->allow_control_characters) {
+ if (*pe == '\n') {
+ raise_parse_error_at("Invalid unescaped newline character (\\n) in string: %s", state, pe - 1);
+ }
+ raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
+ }
+ } else {
+ raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
+ }
+ break;
}
- MEMCPY(buffer, unescape, char, unescape_len);
- buffer += unescape_len;
- p = ++pe;
}
+#undef APPEND_CHAR
if (stringEnd > p) {
MEMCPY(buffer, p, char, stringEnd - p);
@@ -672,33 +769,13 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
if (symbolize) {
result = rb_str_intern(result);
} else if (intern) {
- result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
+ result = rb_str_to_interned_str(result);
}
return result;
}
#define MAX_FAST_INTEGER_SIZE 18
-static inline VALUE fast_decode_integer(const char *p, const char *pe)
-{
- bool negative = false;
- if (*p == '-') {
- negative = true;
- p++;
- }
-
- long long memo = 0;
- while (p < pe) {
- memo *= 10;
- memo += *p - '0';
- p++;
- }
-
- if (negative) {
- memo = -memo;
- }
- return LL2NUM(memo);
-}
static VALUE json_decode_large_integer(const char *start, long len)
{
@@ -712,17 +789,27 @@ static VALUE json_decode_large_integer(const char *start, long len)
}
static inline VALUE
-json_decode_integer(const char *start, const char *end)
+json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
{
- long len = end - start;
- if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
- return fast_decode_integer(start, end);
+ if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
+ if (negative) {
+ return INT64T2NUM(-((int64_t)mantissa));
}
- return json_decode_large_integer(start, len);
+ return UINT64T2NUM(mantissa);
+ }
+
+ return json_decode_large_integer(start, end - start);
}
static VALUE json_decode_large_float(const char *start, long len)
{
+ if (RB_LIKELY(len < 64)) {
+ char buffer[64];
+ MEMCPY(buffer, start, char, len);
+ buffer[len] = '\0';
+ return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
+ }
+
VALUE buffer_v;
char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
MEMCPY(buffer, start, char, len);
@@ -732,21 +819,24 @@ static VALUE json_decode_large_float(const char *start, long len)
return number;
}
-static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, const char *end)
+/* Ruby JSON optimized float decoder using vendored Ryu algorithm
+ * Accepts pre-extracted mantissa and exponent from first-pass validation
+ */
+static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int32_t exponent, bool negative,
+ const char *start, const char *end)
{
- long len = end - start;
-
if (RB_UNLIKELY(config->decimal_class)) {
- VALUE text = rb_str_new(start, len);
+ VALUE text = rb_str_new(start, end - start);
return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text);
- } else if (RB_LIKELY(len < 64)) {
- char buffer[64];
- MEMCPY(buffer, start, char, len);
- buffer[len] = '\0';
- return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
- } else {
- return json_decode_large_float(start, len);
}
+
+ // Fall back to rb_cstr_to_dbl for potential subnormals (rare edge case)
+ // Ryu has rounding issues with subnormals around 1e-310 (< 2.225e-308)
+ if (RB_UNLIKELY(mantissa_digits > 17 || mantissa_digits + exponent < -307)) {
+ return json_decode_large_float(start, end - start);
+ }
+
+ return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, exponent, negative));
}
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
@@ -761,32 +851,75 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
return array;
}
-static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count)
+static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
{
- VALUE object = rb_hash_new_capa(count);
- rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
+ VALUE set = rb_hash_new_capa(count / 2);
+ for (size_t index = 0; index < count; index += 2) {
+ size_t before = RHASH_SIZE(set);
+ VALUE key = pairs[index];
+ rb_hash_aset(set, key, Qtrue);
+ if (RHASH_SIZE(set) == before) {
+ if (RB_SYMBOL_P(key)) {
+ return rb_sym2str(key);
+ }
+ return key;
+ }
+ }
+ return Qfalse;
+}
- rvalue_stack_pop(state->stack, count);
+static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
+{
+ VALUE message = rb_sprintf(
+ "detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
+ rb_inspect(duplicate_key)
+ );
- if (config->freeze) {
- RB_OBJ_FREEZE(object);
- }
+ emit_parse_warning(RSTRING_PTR(message), state);
+ RB_GC_GUARD(message);
+}
- return object;
+#ifdef RBIMPL_ATTR_NORETURN
+RBIMPL_ATTR_NORETURN()
+#endif
+static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
+{
+ VALUE message = rb_sprintf(
+ "duplicate key %"PRIsVALUE,
+ rb_inspect(duplicate_key)
+ );
+
+ raise_parse_error(RSTRING_PTR(message), state);
+ RB_GC_GUARD(message);
}
-static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
+static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
{
- VALUE string;
- bool intern = is_name || config->freeze;
- bool symbolize = is_name && config->symbolize_names;
- if (escaped) {
- string = json_string_unescape(state, start, end, is_name, intern, symbolize);
- } else {
- string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
+ size_t entries_count = count / 2;
+ VALUE object = rb_hash_new_capa(entries_count);
+ const VALUE *pairs = rvalue_stack_peek(state->stack, count);
+ rb_hash_bulk_insert(count, pairs, object);
+
+ if (RB_UNLIKELY(RHASH_SIZE(object) < entries_count)) {
+ switch (config->on_duplicate_key) {
+ case JSON_IGNORE:
+ break;
+ case JSON_DEPRECATED:
+ emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
+ break;
+ case JSON_RAISE:
+ raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
+ break;
+ }
+ }
+
+ rvalue_stack_pop(state->stack, count);
+
+ if (config->freeze) {
+ RB_OBJ_FREEZE(object);
}
- return string;
+ return object;
}
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
@@ -798,7 +931,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
return value;
}
-static const bool string_scan[256] = {
+static const bool string_scan_table[256] = {
// ASCII Control Characters
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -811,157 +944,308 @@ static const bool string_scan[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
+#ifdef HAVE_SIMD
+static SIMD_Implementation simd_impl = SIMD_NONE;
+#endif /* HAVE_SIMD */
+
+ALWAYS_INLINE(static) bool string_scan(JSON_ParserState *state)
{
- state->cursor++;
- const char *start = state->cursor;
- bool escaped = false;
+#ifdef HAVE_SIMD
+#if defined(HAVE_SIMD_NEON)
- while (state->cursor < state->end) {
- if (RB_UNLIKELY(string_scan[(unsigned char)*state->cursor])) {
- switch (*state->cursor) {
- case '"': {
- VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
- state->cursor++;
- return json_push_value(state, config, string);
- }
- case '\\': {
- state->cursor++;
- escaped = true;
- if ((unsigned char)*state->cursor < 0x20) {
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
- }
- break;
+ uint64_t mask = 0;
+ if (string_scan_simd_neon(&state->cursor, state->end, &mask)) {
+ state->cursor += trailing_zeros64(mask) >> 2;
+ return true;
+ }
+
+#elif defined(HAVE_SIMD_SSE2)
+ if (simd_impl == SIMD_SSE2) {
+ int mask = 0;
+ if (string_scan_simd_sse2(&state->cursor, state->end, &mask)) {
+ state->cursor += trailing_zeros(mask);
+ return true;
+ }
+ }
+#endif /* HAVE_SIMD_NEON or HAVE_SIMD_SSE2 */
+#endif /* HAVE_SIMD */
+
+ while (!eos(state)) {
+ if (RB_UNLIKELY(string_scan_table[(unsigned char)*state->cursor])) {
+ return true;
+ }
+ state->cursor++;
+ }
+ return false;
+}
+
+static VALUE json_parse_escaped_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name, const char *start)
+{
+ const char *backslashes[JSON_MAX_UNESCAPE_POSITIONS];
+ JSON_UnescapePositions positions = {
+ .size = 0,
+ .positions = backslashes,
+ .additional_backslashes = 0,
+ };
+
+ do {
+ switch (*state->cursor) {
+ case '"': {
+ VALUE string = json_string_unescape(state, config, start, state->cursor, is_name, &positions);
+ state->cursor++;
+ return json_push_value(state, config, string);
+ }
+ case '\\': {
+ if (RB_LIKELY(positions.size < JSON_MAX_UNESCAPE_POSITIONS)) {
+ backslashes[positions.size] = state->cursor;
+ positions.size++;
+ } else {
+ positions.additional_backslashes++;
}
- default:
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
- break;
+ state->cursor++;
+ break;
}
+ default:
+ if (!config->allow_control_characters) {
+ raise_parse_error("invalid ASCII control character in string: %s", state);
+ }
+ break;
}
state->cursor++;
- }
+ } while (string_scan(state));
- raise_parse_error("unexpected end of input, expected closing \"", state->cursor);
+ raise_parse_error("unexpected end of input, expected closing \"", state);
return Qfalse;
}
+ALWAYS_INLINE(static) VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
+{
+ state->cursor++;
+ const char *start = state->cursor;
+
+ if (RB_UNLIKELY(!string_scan(state))) {
+ raise_parse_error("unexpected end of input, expected closing \"", state);
+ }
+
+ if (RB_LIKELY(*state->cursor == '"')) {
+ VALUE string = json_string_fastpath(state, config, start, state->cursor, is_name);
+ state->cursor++;
+ return json_push_value(state, config, string);
+ }
+ return json_parse_escaped_string(state, config, is_name, start);
+}
+
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+// From: https://lemire.me/blog/2022/01/21/swar-explained-parsing-eight-digits/
+// Additional References:
+// https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
+// http://0x80.pl/notesen/2014-10-12-parsing-decimal-numbers-part-1-swar.html
+static inline uint64_t decode_8digits_unrolled(uint64_t val) {
+ const uint64_t mask = 0x000000FF000000FF;
+ const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
+ const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
+ val -= 0x3030303030303030;
+ val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
+ val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
+ return val;
+}
+
+static inline uint64_t decode_4digits_unrolled(uint32_t val) {
+ const uint32_t mask = 0x000000FF;
+ const uint32_t mul1 = 100;
+ val -= 0x30303030;
+ val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
+ val = ((val & mask) * mul1) + (((val >> 16) & mask));
+ return val;
+}
+#endif
+
+static inline int json_parse_digits(JSON_ParserState *state, uint64_t *accumulator)
+{
+ const char *start = state->cursor;
+
+#if JSON_CPU_LITTLE_ENDIAN_64BITS
+ while (rest(state) >= sizeof(uint64_t)) {
+ uint64_t next_8bytes;
+ memcpy(&next_8bytes, state->cursor, sizeof(uint64_t));
+
+ // From: https://github.com/simdjson/simdjson/blob/32b301893c13d058095a07d9868edaaa42ee07aa/include/simdjson/generic/numberparsing.h#L333
+ // Branchless version of: http://0x80.pl/articles/swar-digits-validate.html
+ uint64_t match = (next_8bytes & 0xF0F0F0F0F0F0F0F0) | (((next_8bytes + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4);
+
+ if (match == 0x3333333333333333) { // 8 consecutive digits
+ *accumulator = (*accumulator * 100000000) + decode_8digits_unrolled(next_8bytes);
+ state->cursor += 8;
+ continue;
+ }
+
+ uint32_t consecutive_digits = trailing_zeros64(match ^ 0x3333333333333333) / CHAR_BIT;
+
+ if (consecutive_digits >= 4) {
+ *accumulator = (*accumulator * 10000) + decode_4digits_unrolled((uint32_t)next_8bytes);
+ state->cursor += 4;
+ consecutive_digits -= 4;
+ }
+
+ while (consecutive_digits) {
+ *accumulator = *accumulator * 10 + (*state->cursor - '0');
+ consecutive_digits--;
+ state->cursor++;
+ }
+
+ return (int)(state->cursor - start);
+ }
+#endif
+
+ char next_char;
+ while (rb_isdigit(next_char = peek(state))) {
+ *accumulator = *accumulator * 10 + (next_char - '0');
+ state->cursor++;
+ }
+ return (int)(state->cursor - start);
+}
+
+static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig *config, bool negative, const char *start)
+{
+ bool integer = true;
+ const char first_digit = *state->cursor;
+
+ // Variables for Ryu optimization - extract digits during parsing
+ int32_t exponent = 0;
+ int decimal_point_pos = -1;
+ uint64_t mantissa = 0;
+
+ // Parse integer part and extract mantissa digits
+ int mantissa_digits = json_parse_digits(state, &mantissa);
+
+ if (RB_UNLIKELY((first_digit == '0' && mantissa_digits > 1) || (negative && mantissa_digits == 0))) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+
+ // Parse fractional part
+ if (peek(state) == '.') {
+ integer = false;
+ decimal_point_pos = mantissa_digits; // Remember position of decimal point
+ state->cursor++;
+
+ int fractional_digits = json_parse_digits(state, &mantissa);
+ mantissa_digits += fractional_digits;
+
+ if (RB_UNLIKELY(!fractional_digits)) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+ }
+
+ // Parse exponent
+ if (rb_tolower(peek(state)) == 'e') {
+ integer = false;
+ state->cursor++;
+
+ bool negative_exponent = false;
+ const char next_char = peek(state);
+ if (next_char == '-' || next_char == '+') {
+ negative_exponent = next_char == '-';
+ state->cursor++;
+ }
+
+ uint64_t abs_exponent = 0;
+ int exponent_digits = json_parse_digits(state, &abs_exponent);
+
+ if (RB_UNLIKELY(!exponent_digits)) {
+ raise_parse_error_at("invalid number: %s", state, start);
+ }
+
+ exponent = negative_exponent ? -((int32_t)abs_exponent) : ((int32_t)abs_exponent);
+ }
+
+ if (integer) {
+ return json_decode_integer(mantissa, mantissa_digits, negative, start, state->cursor);
+ }
+
+ // Adjust exponent based on decimal point position
+ if (decimal_point_pos >= 0) {
+ exponent -= (mantissa_digits - decimal_point_pos);
+ }
+
+ return json_decode_float(config, mantissa, mantissa_digits, exponent, negative, start, state->cursor);
+}
+
+static inline VALUE json_parse_positive_number(JSON_ParserState *state, JSON_ParserConfig *config)
+{
+ return json_parse_number(state, config, false, state->cursor);
+}
+
+static inline VALUE json_parse_negative_number(JSON_ParserState *state, JSON_ParserConfig *config)
+{
+ const char *start = state->cursor;
+ state->cursor++;
+ return json_parse_number(state, config, true, start);
+}
+
static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
{
json_eat_whitespace(state);
- if (state->cursor >= state->end) {
- raise_parse_error("unexpected end of input", state->cursor);
- }
- switch (*state->cursor) {
+ switch (peek(state)) {
case 'n':
- if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
+ if (rest(state) >= 4 && (memcmp(state->cursor, "null", 4) == 0)) {
state->cursor += 4;
return json_push_value(state, config, Qnil);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 't':
- if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
+ if (rest(state) >= 4 && (memcmp(state->cursor, "true", 4) == 0)) {
state->cursor += 4;
return json_push_value(state, config, Qtrue);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 'f':
// Note: memcmp with a small power of two compile to an integer comparison
- if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
+ if (rest(state) >= 5 && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
state->cursor += 5;
return json_push_value(state, config, Qfalse);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 'N':
// Note: memcmp with a small power of two compile to an integer comparison
- if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
+ if (config->allow_nan && rest(state) >= 3 && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
state->cursor += 3;
return json_push_value(state, config, CNaN);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
case 'I':
- if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
+ if (config->allow_nan && rest(state) >= 8 && (memcmp(state->cursor, "Infinity", 8) == 0)) {
state->cursor += 8;
return json_push_value(state, config, CInfinity);
}
- raise_parse_error("unexpected token at '%s'", state->cursor);
+ raise_parse_error("unexpected token %s", state);
break;
- case '-':
+ case '-': {
// Note: memcmp with a small power of two compile to an integer comparison
- if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
+ if (rest(state) >= 9 && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
if (config->allow_nan) {
state->cursor += 9;
return json_push_value(state, config, CMinusInfinity);
} else {
- raise_parse_error("unexpected token at '%s'", state->cursor);
- }
- }
- // Fallthrough
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
- bool integer = true;
-
- // /\A-?(0|[1-9]\d*)(\.\d+)?([Ee][-+]?\d+)?/
- const char *start = state->cursor;
- state->cursor++;
-
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
- }
-
- long integer_length = state->cursor - start;
-
- if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
- raise_parse_error("invalid number: %s", start);
- } else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
- raise_parse_error("invalid number: %s", start);
- } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
- raise_parse_error("invalid number: %s", start);
- }
-
- if ((state->cursor < state->end) && (*state->cursor == '.')) {
- integer = false;
- state->cursor++;
-
- if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
- raise_parse_error("invalid number: %s", state->cursor);
+ raise_parse_error("unexpected token %s", state);
}
-
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
- }
- }
-
- if ((state->cursor < state->end) && ((*state->cursor == 'e') || (*state->cursor == 'E'))) {
- integer = false;
- state->cursor++;
- if ((state->cursor < state->end) && ((*state->cursor == '+') || (*state->cursor == '-'))) {
- state->cursor++;
- }
-
- if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
- raise_parse_error("invalid number: %s", state->cursor);
- }
-
- while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
- state->cursor++;
- }
- }
-
- if (integer) {
- return json_push_value(state, config, json_decode_integer(start, state->cursor));
}
- return json_push_value(state, config, json_decode_float(config, start, state->cursor));
+ return json_push_value(state, config, json_parse_negative_number(state, config));
+ break;
}
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
+ return json_push_value(state, config, json_parse_positive_number(state, config));
+ break;
case '"': {
// %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
return json_parse_string(state, config, false);
@@ -972,7 +1256,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
json_eat_whitespace(state);
long stack_head = state->stack->head;
- if ((state->cursor < state->end) && (*state->cursor == ']')) {
+ if (peek(state) == ']') {
state->cursor++;
return json_push_value(state, config, json_decode_array(state, config, 0));
} else {
@@ -987,38 +1271,40 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
while (true) {
json_eat_whitespace(state);
- if (state->cursor < state->end) {
- if (*state->cursor == ']') {
- state->cursor++;
- long count = state->stack->head - stack_head;
- state->current_nesting--;
- state->in_array--;
- return json_push_value(state, config, json_decode_array(state, config, count));
- }
+ const char next_char = peek(state);
- if (*state->cursor == ',') {
- state->cursor++;
- if (config->allow_trailing_comma) {
- json_eat_whitespace(state);
- if ((state->cursor < state->end) && (*state->cursor == ']')) {
- continue;
- }
+ if (RB_LIKELY(next_char == ',')) {
+ state->cursor++;
+ if (config->allow_trailing_comma) {
+ json_eat_whitespace(state);
+ if (peek(state) == ']') {
+ continue;
}
- json_parse_any(state, config);
- continue;
}
+ json_parse_any(state, config);
+ continue;
}
- raise_parse_error("expected ',' or ']' after array value", state->cursor);
+ if (next_char == ']') {
+ state->cursor++;
+ long count = state->stack->head - stack_head;
+ state->current_nesting--;
+ state->in_array--;
+ return json_push_value(state, config, json_decode_array(state, config, count));
+ }
+
+ raise_parse_error("expected ',' or ']' after array value", state);
}
break;
}
case '{': {
+ const char *object_start_cursor = state->cursor;
+
state->cursor++;
json_eat_whitespace(state);
long stack_head = state->stack->head;
- if ((state->cursor < state->end) && (*state->cursor == '}')) {
+ if (peek(state) == '}') {
state->cursor++;
return json_push_value(state, config, json_decode_object(state, config, 0));
} else {
@@ -1027,14 +1313,14 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
rb_raise(eNestingError, "nesting of %d is too deep", state->current_nesting);
}
- if (*state->cursor != '"') {
- raise_parse_error("expected object key, got '%s", state->cursor);
+ if (peek(state) != '"') {
+ raise_parse_error("expected object key, got %s", state);
}
json_parse_string(state, config, true);
json_eat_whitespace(state);
- if ((state->cursor >= state->end) || (*state->cursor != ':')) {
- raise_parse_error("expected ':' after object key", state->cursor);
+ if (peek(state) != ':') {
+ raise_parse_error("expected ':' after object key", state);
}
state->cursor++;
@@ -1044,59 +1330,70 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
while (true) {
json_eat_whitespace(state);
- if (state->cursor < state->end) {
- if (*state->cursor == '}') {
- state->cursor++;
- state->current_nesting--;
- long count = state->stack->head - stack_head;
- return json_push_value(state, config, json_decode_object(state, config, count));
- }
+ const char next_char = peek(state);
+ if (next_char == '}') {
+ state->cursor++;
+ state->current_nesting--;
+ size_t count = state->stack->head - stack_head;
- if (*state->cursor == ',') {
- state->cursor++;
- json_eat_whitespace(state);
+ // Temporary rewind cursor in case an error is raised
+ const char *final_cursor = state->cursor;
+ state->cursor = object_start_cursor;
+ VALUE object = json_decode_object(state, config, count);
+ state->cursor = final_cursor;
- if (config->allow_trailing_comma) {
- if ((state->cursor < state->end) && (*state->cursor == '}')) {
- continue;
- }
- }
+ return json_push_value(state, config, object);
+ }
- if (*state->cursor != '"') {
- raise_parse_error("expected object key, got: '%s'", state->cursor);
- }
- json_parse_string(state, config, true);
+ if (next_char == ',') {
+ state->cursor++;
+ json_eat_whitespace(state);
- json_eat_whitespace(state);
- if ((state->cursor >= state->end) || (*state->cursor != ':')) {
- raise_parse_error("expected ':' after object key, got: '%s", state->cursor);
+ if (config->allow_trailing_comma) {
+ if (peek(state) == '}') {
+ continue;
}
- state->cursor++;
+ }
- json_parse_any(state, config);
+ if (RB_UNLIKELY(peek(state) != '"')) {
+ raise_parse_error("expected object key, got: %s", state);
+ }
+ json_parse_string(state, config, true);
- continue;
+ json_eat_whitespace(state);
+ if (RB_UNLIKELY(peek(state) != ':')) {
+ raise_parse_error("expected ':' after object key, got: %s", state);
}
+ state->cursor++;
+
+ json_parse_any(state, config);
+
+ continue;
}
- raise_parse_error("expected ',' or '}' after object value, got: '%s'", state->cursor);
+ raise_parse_error("expected ',' or '}' after object value, got: %s", state);
}
break;
}
+ case 0:
+ raise_parse_error("unexpected end of input", state);
+ break;
+
default:
- raise_parse_error("unexpected character: '%s'", state->cursor);
+ raise_parse_error("unexpected character: %s", state);
break;
}
- raise_parse_error("unreacheable: '%s'", state->cursor);
+ raise_parse_error("unreachable: %s", state);
+ return Qundef;
}
static void json_ensure_eof(JSON_ParserState *state)
{
json_eat_whitespace(state);
- if (state->cursor != state->end) {
- raise_parse_error("unexpected token at end of stream '%s'", state->cursor);
+ if (!eos(state)) {
+ raise_parse_error("unexpected token at end of stream %s", state);
}
}
@@ -1132,13 +1429,15 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
{
JSON_ParserConfig *config = (JSON_ParserConfig *)data;
- if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
- else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
- else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
- else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
- else if (key == sym_freeze) { config->freeze = RTEST(val); }
- else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
- else if (key == sym_decimal_class) {
+ if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
+ else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
+ else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
+ else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
+ else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
+ else if (key == sym_freeze) { config->freeze = RTEST(val); }
+ else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
+ else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
+ else if (key == sym_decimal_class) {
if (RTEST(val)) {
if (rb_respond_to(val, i_try_convert)) {
config->decimal_class = val;
@@ -1211,6 +1510,7 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
*/
static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
{
+ rb_check_frozen(self);
GET_PARSER_CONFIG;
parser_config_init(config, opts);
@@ -1232,9 +1532,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
.capa = RVALUE_STACK_INITIAL_CAPA,
};
+ long len;
+ const char *start;
+ RSTRING_GETMEM(Vsource, start, len);
+
JSON_ParserState _state = {
- .cursor = RSTRING_PTR(Vsource),
- .end = RSTRING_END(Vsource),
+ .start = start,
+ .cursor = start,
+ .end = start + len,
.stack = &stack,
};
JSON_ParserState *state = &_state;
@@ -1301,7 +1606,7 @@ static const rb_data_type_t JSON_ParserConfig_type = {
JSON_ParserConfig_memsize,
},
0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
};
static VALUE cJSON_parser_s_allocate(VALUE klass)
@@ -1345,15 +1650,13 @@ void Init_parser(void)
sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
+ sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
sym_freeze = ID2SYM(rb_intern("freeze"));
sym_on_load = ID2SYM(rb_intern("on_load"));
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
+ sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
- i_chr = rb_intern("chr");
- i_aset = rb_intern("[]=");
- i_aref = rb_intern("[]");
- i_leftshift = rb_intern("<<");
i_new = rb_intern("new");
i_try_convert = rb_intern("try_convert");
i_uminus = rb_intern("-@");
@@ -1362,4 +1665,8 @@ void Init_parser(void)
binary_encindex = rb_ascii8bit_encindex();
utf8_encindex = rb_utf8_encindex();
enc_utf8 = rb_utf8_encoding();
+
+#ifdef HAVE_SIMD
+ simd_impl = find_simd_implementation();
+#endif
}
diff --git a/ext/json/simd/conf.rb b/ext/json/simd/conf.rb
new file mode 100644
index 0000000000..76f774bc97
--- /dev/null
+++ b/ext/json/simd/conf.rb
@@ -0,0 +1,24 @@
+case RbConfig::CONFIG['host_cpu']
+when /^(arm|aarch64)/
+ # Try to compile a small program using NEON instructions
+ header, type, init, extra = 'arm_neon.h', 'uint8x16_t', 'vdupq_n_u8(32)', nil
+when /^(x86_64|x64)/
+ header, type, init, extra = 'x86intrin.h', '__m128i', '_mm_set1_epi8(32)', 'if (__builtin_cpu_supports("sse2")) { printf("OK"); }'
+end
+if header
+ if have_header(header) && try_compile(<<~SRC, '-Werror=implicit-function-declaration')
+ #{cpp_include(header)}
+ int main(int argc, char **argv) {
+ #{type} test = #{init};
+ #{extra}
+ if (argc > 100000) printf("%p", &test);
+ return 0;
+ }
+ SRC
+ $defs.push("-DJSON_ENABLE_SIMD")
+ else
+ puts "Disable SIMD"
+ end
+end
+
+have_header('cpuid.h')
diff --git a/ext/json/simd/simd.h b/ext/json/simd/simd.h
new file mode 100644
index 0000000000..3bb86acdec
--- /dev/null
+++ b/ext/json/simd/simd.h
@@ -0,0 +1,218 @@
+#include "../json.h"
+
+typedef enum {
+ SIMD_NONE,
+ SIMD_NEON,
+ SIMD_SSE2
+} SIMD_Implementation;
+
+#ifndef __has_builtin // Optional of course.
+ #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifdef __clang__
+# if __has_builtin(__builtin_ctzll)
+# define HAVE_BUILTIN_CTZLL 1
+# else
+# define HAVE_BUILTIN_CTZLL 0
+# endif
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+# define HAVE_BUILTIN_CTZLL 1
+#else
+# define HAVE_BUILTIN_CTZLL 0
+#endif
+
+static inline uint32_t trailing_zeros64(uint64_t input)
+{
+ JSON_ASSERT(input > 0); // __builtin_ctz(0) is undefined behavior
+
+#if HAVE_BUILTIN_CTZLL
+ return __builtin_ctzll(input);
+#else
+ uint32_t trailing_zeros = 0;
+ uint64_t temp = input;
+ while ((temp & 1) == 0 && temp > 0) {
+ trailing_zeros++;
+ temp >>= 1;
+ }
+ return trailing_zeros;
+#endif
+}
+
+static inline int trailing_zeros(int input)
+{
+ JSON_ASSERT(input > 0); // __builtin_ctz(0) is undefined behavior
+
+#if HAVE_BUILTIN_CTZLL
+ return __builtin_ctz(input);
+#else
+ int trailing_zeros = 0;
+ int temp = input;
+ while ((temp & 1) == 0 && temp > 0) {
+ trailing_zeros++;
+ temp >>= 1;
+ }
+ return trailing_zeros;
+#endif
+}
+
+#ifdef JSON_ENABLE_SIMD
+
+#define SIMD_MINIMUM_THRESHOLD 4
+
+ALWAYS_INLINE(static) void json_fast_memcpy16(char *dst, const char *src, size_t len)
+{
+ RBIMPL_ASSERT_OR_ASSUME(len < 16);
+ RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD); // 4
+#if defined(__has_builtin) && __has_builtin(__builtin_memcpy)
+ // If __builtin_memcpy is available, use it to copy between SIMD_MINIMUM_THRESHOLD (4) and vec_len-1 (15) bytes.
+ // These copies overlap. The first copy will copy the first 8 (or 4) bytes. The second copy will copy
+ // the last 8 (or 4) bytes but overlap with the first copy. The overlapping bytes will be in the correct
+ // position in both copies.
+
+ // Please do not attempt to replace __builtin_memcpy with memcpy without profiling and/or looking at the
+ // generated assembly. On clang-specifically (tested on Apple clang version 17.0.0 (clang-1700.0.13.3)),
+ // when using memcpy, the compiler will notice the only difference is a 4 or 8 and generate a conditional
+ // select instruction instead of direct loads and stores with a branch. This ends up slower than the branch
+ // plus two loads and stores generated when using __builtin_memcpy.
+ if (len >= 8) {
+ __builtin_memcpy(dst, src, 8);
+ __builtin_memcpy(dst + len - 8, src + len - 8, 8);
+ } else {
+ __builtin_memcpy(dst, src, 4);
+ __builtin_memcpy(dst + len - 4, src + len - 4, 4);
+ }
+#else
+ MEMCPY(dst, src, char, len);
+#endif
+}
+
+#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
+#include <arm_neon.h>
+
+#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
+static inline SIMD_Implementation find_simd_implementation(void)
+{
+ return SIMD_NEON;
+}
+
+#define HAVE_SIMD 1
+#define HAVE_SIMD_NEON 1
+
+// See: https://community.arm.com/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon
+ALWAYS_INLINE(static) uint64_t neon_match_mask(uint8x16_t matches)
+{
+ const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(matches), 4);
+ const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
+ return mask & 0x8888888888888888ull;
+}
+
+ALWAYS_INLINE(static) uint64_t compute_chunk_mask_neon(const char *ptr)
+{
+ uint8x16_t chunk = vld1q_u8((const unsigned char *)ptr);
+
+ // Trick: c < 32 || c == 34 can be factored as c ^ 2 < 33
+ // https://lemire.me/blog/2025/04/13/detect-control-characters-quotes-and-backslashes-efficiently-using-swar/
+ const uint8x16_t too_low_or_dbl_quote = vcltq_u8(veorq_u8(chunk, vdupq_n_u8(2)), vdupq_n_u8(33));
+
+ uint8x16_t has_backslash = vceqq_u8(chunk, vdupq_n_u8('\\'));
+ uint8x16_t needs_escape = vorrq_u8(too_low_or_dbl_quote, has_backslash);
+ return neon_match_mask(needs_escape);
+}
+
+ALWAYS_INLINE(static) int string_scan_simd_neon(const char **ptr, const char *end, uint64_t *mask)
+{
+ while (*ptr + sizeof(uint8x16_t) <= end) {
+ uint64_t chunk_mask = compute_chunk_mask_neon(*ptr);
+ if (chunk_mask) {
+ *mask = chunk_mask;
+ return 1;
+ }
+ *ptr += sizeof(uint8x16_t);
+ }
+ return 0;
+}
+
+static inline uint8x16x4_t load_uint8x16_4(const unsigned char *table)
+{
+ uint8x16x4_t tab;
+ tab.val[0] = vld1q_u8(table);
+ tab.val[1] = vld1q_u8(table+16);
+ tab.val[2] = vld1q_u8(table+32);
+ tab.val[3] = vld1q_u8(table+48);
+ return tab;
+}
+
+#endif /* ARM Neon Support.*/
+
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
+
+#ifdef HAVE_X86INTRIN_H
+#include <x86intrin.h>
+
+#define HAVE_SIMD 1
+#define HAVE_SIMD_SSE2 1
+
+#ifdef HAVE_CPUID_H
+#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
+
+#if defined(__clang__) || defined(__GNUC__)
+#define TARGET_SSE2 __attribute__((target("sse2")))
+#else
+#define TARGET_SSE2
+#endif
+
+#define _mm_cmpge_epu8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a)
+#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a)
+#define _mm_cmpgt_epu8(a, b) _mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1))
+#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a)
+
+ALWAYS_INLINE(static) TARGET_SSE2 int compute_chunk_mask_sse2(const char *ptr)
+{
+ __m128i chunk = _mm_loadu_si128((__m128i const*)ptr);
+ // Trick: c < 32 || c == 34 can be factored as c ^ 2 < 33
+ // https://lemire.me/blog/2025/04/13/detect-control-characters-quotes-and-backslashes-efficiently-using-swar/
+ __m128i too_low_or_dbl_quote = _mm_cmplt_epu8(_mm_xor_si128(chunk, _mm_set1_epi8(2)), _mm_set1_epi8(33));
+ __m128i has_backslash = _mm_cmpeq_epi8(chunk, _mm_set1_epi8('\\'));
+ __m128i needs_escape = _mm_or_si128(too_low_or_dbl_quote, has_backslash);
+ return _mm_movemask_epi8(needs_escape);
+}
+
+ALWAYS_INLINE(static) TARGET_SSE2 int string_scan_simd_sse2(const char **ptr, const char *end, int *mask)
+{
+ while (*ptr + sizeof(__m128i) <= end) {
+ int chunk_mask = compute_chunk_mask_sse2(*ptr);
+ if (chunk_mask) {
+ *mask = chunk_mask;
+ return 1;
+ }
+ *ptr += sizeof(__m128i);
+ }
+
+ return 0;
+}
+
+#include <cpuid.h>
+#endif /* HAVE_CPUID_H */
+
+static inline SIMD_Implementation find_simd_implementation(void)
+{
+ // TODO Revisit. I think the SSE version now only uses SSE2 instructions.
+ if (__builtin_cpu_supports("sse2")) {
+ return SIMD_SSE2;
+ }
+
+ return SIMD_NONE;
+}
+
+#endif /* HAVE_X86INTRIN_H */
+#endif /* X86_64 Support */
+
+#endif /* JSON_ENABLE_SIMD */
+
+#ifndef FIND_SIMD_IMPLEMENTATION_DEFINED
+static inline SIMD_Implementation find_simd_implementation(void)
+{
+ return SIMD_NONE;
+}
+#endif
diff --git a/ext/json/vendor/fpconv.c b/ext/json/vendor/fpconv.c
index 2887c64885..6c9bc2c103 100644
--- a/ext/json/vendor/fpconv.c
+++ b/ext/json/vendor/fpconv.c
@@ -29,6 +29,10 @@
#include <string.h>
#include <stdint.h>
+#if JSON_DEBUG
+#include <assert.h>
+#endif
+
#define npowers 87
#define steppowers 8
#define firstpower -348 /* 10 ^ -348 */
@@ -41,7 +45,7 @@ typedef struct Fp {
int exp;
} Fp;
-static Fp powers_ten[] = {
+static const Fp powers_ten[] = {
{ 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
{ 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
{ 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
@@ -92,7 +96,7 @@ static Fp find_cachedpow10(int exp, int* k)
{
const double one_log_ten = 0.30102999566398114;
- int approx = -(exp + npowers) * one_log_ten;
+ int approx = (int)(-(exp + npowers) * one_log_ten);
int idx = (approx - firstpower) / steppowers;
while(1) {
@@ -123,7 +127,7 @@ static Fp find_cachedpow10(int exp, int* k)
#define absv(n) ((n) < 0 ? -(n) : (n))
#define minv(a, b) ((a) < (b) ? (a) : (b))
-static uint64_t tens[] = {
+static const uint64_t tens[] = {
10000000000000000000U, 1000000000000000000U, 100000000000000000U,
10000000000000000U, 1000000000000000U, 100000000000000U,
10000000000000U, 1000000000000U, 100000000000U,
@@ -244,7 +248,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
uint64_t part2 = upper->frac & (one.frac - 1);
int idx = 0, kappa = 10;
- uint64_t* divp;
+ const uint64_t* divp;
/* 1000000000 */
for(divp = tens + 10; kappa > 0; divp++) {
@@ -268,7 +272,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
}
/* 10 */
- uint64_t* unit = tens + 18;
+ const uint64_t* unit = tens + 18;
while(true) {
part2 *= 10;
@@ -320,15 +324,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
{
int exp = absv(K + ndigits - 1);
- int max_trailing_zeros = 7;
-
- if(neg) {
- max_trailing_zeros -= 1;
- }
-
- /* write plain integer */
- if(K >= 0 && (exp < (ndigits + max_trailing_zeros))) {
-
+ if(K >= 0 && exp < 15) {
memcpy(dest, digits, ndigits);
memset(dest + ndigits, '0', K);
@@ -340,7 +336,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
}
/* write decimal w/o scientific notation */
- if(K < 0 && (K > -7 || exp < 4)) {
+ if(K < 0 && (K > -7 || exp < 10)) {
int offset = ndigits - absv(K);
/* fp < 1.0 -> write leading zero */
if(offset <= 0) {
@@ -432,10 +428,12 @@ static int filter_special(double fp, char* dest)
*
* Input:
* fp -> the double to convert, dest -> destination buffer.
- * The generated string will never be longer than 24 characters.
- * Make sure to pass a pointer to at least 24 bytes of memory.
+ * The generated string will never be longer than 32 characters.
+ * Make sure to pass a pointer to at least 32 bytes of memory.
* The emitted string will not be null terminated.
*
+ *
+ *
* Output:
* The number of written characters.
*
@@ -443,7 +441,7 @@ static int filter_special(double fp, char* dest)
*
* void print(double d)
* {
- * char buf[24 + 1] // plus null terminator
+ * char buf[28 + 1] // plus null terminator
* int str_len = fpconv_dtoa(d, buf);
*
* buf[str_len] = '\0';
@@ -451,7 +449,7 @@ static int filter_special(double fp, char* dest)
* }
*
*/
-static int fpconv_dtoa(double d, char dest[24])
+static int fpconv_dtoa(double d, char dest[32])
{
char digits[18];
@@ -474,6 +472,9 @@ static int fpconv_dtoa(double d, char dest[24])
int ndigits = grisu2(d, digits, &K);
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
+#if JSON_DEBUG
+ assert(str_len <= 32);
+#endif
return str_len;
}
diff --git a/ext/json/vendor/ryu.h b/ext/json/vendor/ryu.h
new file mode 100644
index 0000000000..f06ec814b4
--- /dev/null
+++ b/ext/json/vendor/ryu.h
@@ -0,0 +1,819 @@
+// Copyright 2018 Ulf Adams
+//
+// The contents of this file may be used under the terms of the Apache License,
+// Version 2.0.
+//
+// Alternatively, the contents of this file may be used under the terms of
+// the Boost Software License, Version 1.0.
+//
+// Unless required by applicable law or agreed to in writing, this software
+// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.
+//
+// ---
+//
+// Apache License
+// Version 2.0, January 2004
+// http://www.apache.org/licenses/
+//
+// TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+//
+// 1. Definitions.
+//
+// "License" shall mean the terms and conditions for use, reproduction,
+// and distribution as defined by Sections 1 through 9 of this document.
+//
+// "Licensor" shall mean the copyright owner or entity authorized by
+// the copyright owner that is granting the License.
+//
+// "Legal Entity" shall mean the union of the acting entity and all
+// other entities that control, are controlled by, or are under common
+// control with that entity. For the purposes of this definition,
+// "control" means (i) the power, direct or indirect, to cause the
+// direction or management of such entity, whether by contract or
+// otherwise, or (ii) ownership of fifty percent (50%) or more of the
+// outstanding shares, or (iii) beneficial ownership of such entity.
+//
+// "You" (or "Your") shall mean an individual or Legal Entity
+// exercising permissions granted by this License.
+//
+// "Source" form shall mean the preferred form for making modifications,
+// including but not limited to software source code, documentation
+// source, and configuration files.
+//
+// "Object" form shall mean any form resulting from mechanical
+// transformation or translation of a Source form, including but
+// not limited to compiled object code, generated documentation,
+// and conversions to other media types.
+//
+// "Work" shall mean the work of authorship, whether in Source or
+// Object form, made available under the License, as indicated by a
+// copyright notice that is included in or attached to the work
+// (an example is provided in the Appendix below).
+//
+// "Derivative Works" shall mean any work, whether in Source or Object
+// form, that is based on (or derived from) the Work and for which the
+// editorial revisions, annotations, elaborations, or other modifications
+// represent, as a whole, an original work of authorship. For the purposes
+// of this License, Derivative Works shall not include works that remain
+// separable from, or merely link (or bind by name) to the interfaces of,
+// the Work and Derivative Works thereof.
+//
+// "Contribution" shall mean any work of authorship, including
+// the original version of the Work and any modifications or additions
+// to that Work or Derivative Works thereof, that is intentionally
+// submitted to Licensor for inclusion in the Work by the copyright owner
+// or by an individual or Legal Entity authorized to submit on behalf of
+// the copyright owner. For the purposes of this definition, "submitted"
+// means any form of electronic, verbal, or written communication sent
+// to the Licensor or its representatives, including but not limited to
+// communication on electronic mailing lists, source code control systems,
+// and issue tracking systems that are managed by, or on behalf of, the
+// Licensor for the purpose of discussing and improving the Work, but
+// excluding communication that is conspicuously marked or otherwise
+// designated in writing by the copyright owner as "Not a Contribution."
+//
+// "Contributor" shall mean Licensor and any individual or Legal Entity
+// on behalf of whom a Contribution has been received by Licensor and
+// subsequently incorporated within the Work.
+//
+// 2. Grant of Copyright License. Subject to the terms and conditions of
+// this License, each Contributor hereby grants to You a perpetual,
+// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+// copyright license to reproduce, prepare Derivative Works of,
+// publicly display, publicly perform, sublicense, and distribute the
+// Work and such Derivative Works in Source or Object form.
+//
+// 3. Grant of Patent License. Subject to the terms and conditions of
+// this License, each Contributor hereby grants to You a perpetual,
+// worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+// (except as stated in this section) patent license to make, have made,
+// use, offer to sell, sell, import, and otherwise transfer the Work,
+// where such license applies only to those patent claims licensable
+// by such Contributor that are necessarily infringed by their
+// Contribution(s) alone or by combination of their Contribution(s)
+// with the Work to which such Contribution(s) was submitted. If You
+// institute patent litigation against any entity (including a
+// cross-claim or counterclaim in a lawsuit) alleging that the Work
+// or a Contribution incorporated within the Work constitutes direct
+// or contributory patent infringement, then any patent licenses
+// granted to You under this License for that Work shall terminate
+// as of the date such litigation is filed.
+//
+// 4. Redistribution. You may reproduce and distribute copies of the
+// Work or Derivative Works thereof in any medium, with or without
+// modifications, and in Source or Object form, provided that You
+// meet the following conditions:
+//
+// (a) You must give any other recipients of the Work or
+// Derivative Works a copy of this License; and
+//
+// (b) You must cause any modified files to carry prominent notices
+// stating that You changed the files; and
+//
+// (c) You must retain, in the Source form of any Derivative Works
+// that You distribute, all copyright, patent, trademark, and
+// attribution notices from the Source form of the Work,
+// excluding those notices that do not pertain to any part of
+// the Derivative Works; and
+//
+// (d) If the Work includes a "NOTICE" text file as part of its
+// distribution, then any Derivative Works that You distribute must
+// include a readable copy of the attribution notices contained
+// within such NOTICE file, excluding those notices that do not
+// pertain to any part of the Derivative Works, in at least one
+// of the following places: within a NOTICE text file distributed
+// as part of the Derivative Works; within the Source form or
+// documentation, if provided along with the Derivative Works; or,
+// within a display generated by the Derivative Works, if and
+// wherever such third-party notices normally appear. The contents
+// of the NOTICE file are for informational purposes only and
+// do not modify the License. You may add Your own attribution
+// notices within Derivative Works that You distribute, alongside
+// or as an addendum to the NOTICE text from the Work, provided
+// that such additional attribution notices cannot be construed
+// as modifying the License.
+//
+// You may add Your own copyright statement to Your modifications and
+// may provide additional or different license terms and conditions
+// for use, reproduction, or distribution of Your modifications, or
+// for any such Derivative Works as a whole, provided Your use,
+// reproduction, and distribution of the Work otherwise complies with
+// the conditions stated in this License.
+//
+// 5. Submission of Contributions. Unless You explicitly state otherwise,
+// any Contribution intentionally submitted for inclusion in the Work
+// by You to the Licensor shall be under the terms and conditions of
+// this License, without any additional terms or conditions.
+// Notwithstanding the above, nothing herein shall supersede or modify
+// the terms of any separate license agreement you may have executed
+// with Licensor regarding such Contributions.
+//
+// 6. Trademarks. This License does not grant permission to use the trade
+// names, trademarks, service marks, or product names of the Licensor,
+// except as required for reasonable and customary use in describing the
+// origin of the Work and reproducing the content of the NOTICE file.
+//
+// 7. Disclaimer of Warranty. Unless required by applicable law or
+// agreed to in writing, Licensor provides the Work (and each
+// Contributor provides its Contributions) on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied, including, without limitation, any warranties or conditions
+// of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+// PARTICULAR PURPOSE. You are solely responsible for determining the
+// appropriateness of using or redistributing the Work and assume any
+// risks associated with Your exercise of permissions under this License.
+//
+// 8. Limitation of Liability. In no event and under no legal theory,
+// whether in tort (including negligence), contract, or otherwise,
+// unless required by applicable law (such as deliberate and grossly
+// negligent acts) or agreed to in writing, shall any Contributor be
+// liable to You for damages, including any direct, indirect, special,
+// incidental, or consequential damages of any character arising as a
+// result of this License or out of the use or inability to use the
+// Work (including but not limited to damages for loss of goodwill,
+// work stoppage, computer failure or malfunction, or any and all
+// other commercial damages or losses), even if such Contributor
+// has been advised of the possibility of such damages.
+//
+// 9. Accepting Warranty or Additional Liability. While redistributing
+// the Work or Derivative Works thereof, You may choose to offer,
+// and charge a fee for, acceptance of support, warranty, indemnity,
+// or other liability obligations and/or rights consistent with this
+// License. However, in accepting such obligations, You may act only
+// on Your own behalf and on Your sole responsibility, not on behalf
+// of any other Contributor, and only if You agree to indemnify,
+// defend, and hold each Contributor harmless for any liability
+// incurred by, or claims asserted against, such Contributor by reason
+// of your accepting any such warranty or additional liability.
+//
+// END OF TERMS AND CONDITIONS
+//
+// APPENDIX: How to apply the Apache License to your work.
+//
+// To apply the Apache License to your work, attach the following
+// boilerplate notice, with the fields enclosed by brackets "[]"
+// replaced with your own identifying information. (Don't include
+// the brackets!) The text should be enclosed in the appropriate
+// comment syntax for the file format. We also recommend that a
+// file or class name and description of purpose be included on the
+// same "printed page" as the copyright notice for easier
+// identification within third-party archives.
+//
+// Copyright [yyyy] [name of copyright owner]
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// ---
+//
+// Boost Software License - Version 1.0 - August 17th, 2003
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// ---
+// Minimal Ryu implementation adapted for Ruby JSON gem by Josef Šimánek
+// Optimized for pre-extracted mantissa/exponent from JSON parsing
+// This is a stripped-down version containing only what's needed for
+// converting decimal mantissa+exponent to IEEE 754 double precision.
+
+#ifndef RYU_H
+#define RYU_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+// Detect __builtin_clzll availability (for floor_log2)
+// Note: MSVC doesn't have __builtin_clzll, so we provide a fallback
+#ifdef __clang__
+ #if __has_builtin(__builtin_clzll)
+ #define RYU_HAVE_BUILTIN_CLZLL 1
+ #else
+ #define RYU_HAVE_BUILTIN_CLZLL 0
+ #endif
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ #define RYU_HAVE_BUILTIN_CLZLL 1
+#else
+ #define RYU_HAVE_BUILTIN_CLZLL 0
+#endif
+
+// Count leading zeros (for floor_log2)
+static inline uint32_t ryu_leading_zeros64(uint64_t input)
+{
+#if RYU_HAVE_BUILTIN_CLZLL
+ return __builtin_clzll(input);
+#else
+ // Fallback: binary search for the highest set bit
+ // This works on MSVC and other compilers without __builtin_clzll
+ if (input == 0) return 64;
+ uint32_t n = 0;
+ if (input <= 0x00000000FFFFFFFFULL) { n += 32; input <<= 32; }
+ if (input <= 0x0000FFFFFFFFFFFFULL) { n += 16; input <<= 16; }
+ if (input <= 0x00FFFFFFFFFFFFFFULL) { n += 8; input <<= 8; }
+ if (input <= 0x0FFFFFFFFFFFFFFFULL) { n += 4; input <<= 4; }
+ if (input <= 0x3FFFFFFFFFFFFFFFULL) { n += 2; input <<= 2; }
+ if (input <= 0x7FFFFFFFFFFFFFFFULL) { n += 1; }
+ return n;
+#endif
+}
+
+// These tables are generated by PrintDoubleLookupTable.
+#define DOUBLE_POW5_INV_BITCOUNT 125
+#define DOUBLE_POW5_BITCOUNT 125
+
+#define DOUBLE_POW5_INV_TABLE_SIZE 342
+#define DOUBLE_POW5_TABLE_SIZE 326
+
+static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = {
+ { 1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u },
+ { 5165088340638674453u, 1475739525896764129u }, { 7821419487252849886u, 1180591620717411303u },
+ { 8824922364862649494u, 1888946593147858085u }, { 7059937891890119595u, 1511157274518286468u },
+ { 13026647942995916322u, 1208925819614629174u }, { 9774590264567735146u, 1934281311383406679u },
+ { 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u },
+ { 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u },
+ { 9162556910162266299u, 1267650600228229401u }, { 7281393426775805432u, 2028240960365167042u },
+ { 16893161185646375315u, 1622592768292133633u }, { 2446482504291369283u, 1298074214633706907u },
+ { 7603720821608101175u, 2076918743413931051u }, { 2393627842544570617u, 1661534994731144841u },
+ { 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u },
+ { 5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u },
+ { 3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u },
+ { 6382248639981364905u, 1393796574908163946u }, { 2832900194486363201u, 2230074519853062314u },
+ { 5955668970331000884u, 1784059615882449851u }, { 1075186361522890384u, 1427247692705959881u },
+ { 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u },
+ { 3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u },
+ { 5547241898389809503u, 1870722095783555735u }, { 4437793518711847602u, 1496577676626844588u },
+ { 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u },
+ { 6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u },
+ { 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u },
+ { 14151565162110759939u, 1255420347077336152u }, { 7885109000409574610u, 2008672555323737844u },
+ { 9997436015069570011u, 1606938044258990275u }, { 7997948812055656009u, 1285550435407192220u },
+ { 12796718099289049614u, 2056880696651507552u }, { 2858676849947419045u, 1645504557321206042u },
+ { 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u },
+ { 3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u },
+ { 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u },
+ { 8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u },
+ { 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u },
+ { 15986332124095098083u, 2261564242916331941u }, { 9099716884534168143u, 1809251394333065553u },
+ { 14658471137111155161u, 1447401115466452442u }, { 4348079280205103483u, 1157920892373161954u },
+ { 14335624477811986218u, 1852673427797059126u }, { 7779150767507678651u, 1482138742237647301u },
+ { 2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u },
+ { 12097921058438802501u, 1517710072051350836u }, { 5988988032009131678u, 1214168057641080669u },
+ { 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u },
+ { 7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u },
+ { 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u },
+ { 4951948911778577463u, 2037035976334486086u }, { 272210314680951647u, 1629628781067588869u },
+ { 3907117066486671641u, 1303703024854071095u }, { 6251387306378674625u, 2085924839766513752u },
+ { 16069156289328670670u, 1668739871813211001u }, { 9165976216721026213u, 1334991897450568801u },
+ { 7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u },
+ { 13518030318433270404u, 1367031702989382452u }, { 6871453250525591353u, 2187250724783011924u },
+ { 9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u },
+ { 10282995085511086630u, 2239744742177804210u }, { 8226396068408869304u, 1791795793742243368u },
+ { 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u },
+ { 5324776569667477496u, 1834798892792057209u }, { 7949170070475892320u, 1467839114233645767u },
+ { 17427382500606444826u, 1174271291386916613u }, { 5747719112518849781u, 1878834066219066582u },
+ { 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u },
+ { 5295368560860596524u, 1923926083808324180u }, { 4236294848688477220u, 1539140867046659344u },
+ { 7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u },
+ { 9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u },
+ { 12335095245094488799u, 2017382717255397335u }, { 9868076196075591040u, 1613906173804317868u },
+ { 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u },
+ { 7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u },
+ { 11918976037903224966u, 2115379100128795516u }, { 5845832015580669650u, 1692303280103036413u },
+ { 12055363241948356366u, 1353842624082429130u }, { 841837113407818570u, 2166148198531886609u },
+ { 4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u },
+ { 12225235553534690011u, 2218135755296651887u }, { 2401490813343931363u, 1774508604237321510u },
+ { 1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u },
+ { 6886345170554478103u, 1817096810739017226u }, { 1819727321701672159u, 1453677448591213781u },
+ { 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u },
+ { 15587778368262418694u, 1488565707357402911u }, { 8780873879868024632u, 1190852565885922329u },
+ { 2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u },
+ { 7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u },
+ { 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u },
+ { 1553625868034358140u, 1997919072202235028u }, { 8621598323911307159u, 1598335257761788022u },
+ { 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u },
+ { 121653480894270168u, 1636695303948070935u }, { 97322784715416134u, 1309356243158456748u },
+ { 14913111714512307107u, 2094969989053530796u }, { 8241140556867935363u, 1675975991242824637u },
+ { 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u },
+ { 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u },
+ { 14650556434236701088u, 2196735251241795108u }, { 652398703163629901u, 1757388200993436087u },
+ { 11589965406756634890u, 1405910560794748869u }, { 7475898206584884855u, 2249456897271598191u },
+ { 2291369750525997561u, 1799565517817278553u }, { 9211793429904618695u, 1439652414253822842u },
+ { 18428218302589300235u, 2303443862806116547u }, { 7363877012587619542u, 1842755090244893238u },
+ { 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u },
+ { 2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u },
+ { 13231802778477390823u, 1207667975942893232u }, { 6413489186596184024u, 1932268761508629172u },
+ { 16198837793502678189u, 1545815009206903337u }, { 5580372605318321905u, 1236652007365522670u },
+ { 8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u },
+ { 7190041073742725760u, 1266331655542295214u }, { 436019273762630246u, 2026130648867672343u },
+ { 7727513048493924843u, 1620904519094137874u }, { 9871359253537050198u, 1296723615275310299u },
+ { 4726128361433549347u, 2074757784440496479u }, { 7470251503888749801u, 1659806227552397183u },
+ { 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u },
+ { 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u },
+ { 4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u },
+ { 3483374466074094362u, 1392346379889585943u }, { 1884050330976640656u, 2227754207823337509u },
+ { 5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u },
+ { 5913764258841343181u, 2281220308811097609u }, { 8420360221814984868u, 1824976247048878087u },
+ { 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u },
+ { 10245762345624985047u, 1868775676978051161u }, { 4507261061758077715u, 1495020541582440929u },
+ { 7295157664148372495u, 1196016433265952743u }, { 7982903447895485668u, 1913626293225524389u },
+ { 10075671573058298858u, 1530901034580419511u }, { 4371188443704728763u, 1224720827664335609u },
+ { 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u },
+ { 15839291315758726049u, 1254114127528279663u }, { 3206773216762499739u, 2006582604045247462u },
+ { 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u },
+ { 4907049252451240275u, 2054740586542333401u }, { 236290587219081897u, 1643792469233866721u },
+ { 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u },
+ { 5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u },
+ { 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u },
+ { 12584037722297574282u, 1378913065775496824u }, { 9066413911450387881u, 2206260905240794919u },
+ { 10942479943902220628u, 1765008724192635935u }, { 8753983955121776503u, 1412006979354108748u },
+ { 10317025513452932081u, 2259211166966573997u }, { 874922781278525018u, 1807368933573259198u },
+ { 8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u },
+ { 14767872471458792434u, 1850745787979017418u }, { 746251532941302978u, 1480596630383213935u },
+ { 597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u },
+ { 8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u },
+ { 17270291175157100626u, 1940647615375886168u }, { 2748186495899949531u, 1552518092300708935u },
+ { 2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u },
+ { 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u },
+ { 8826220925580526867u, 2034916513940385215u }, { 7060976740464421494u, 1627933211152308172u },
+ { 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u },
+ { 9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u },
+ { 13015147745246481542u, 2133764618521553367u }, { 3033420566713364587u, 1707011694817242694u },
+ { 6116085268112601993u, 1365609355853794155u }, { 9785736428980163188u, 2184974969366070648u },
+ { 15207286772667951197u, 1747979975492856518u }, { 1097782973908629988u, 1398383980394285215u },
+ { 1756452758253807981u, 2237414368630856344u }, { 5094511021344956708u, 1789931494904685075u },
+ { 4075608817075965366u, 1431945195923748060u }, { 6520974107321544586u, 2291112313477996896u },
+ { 1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u },
+ { 17210690286378213644u, 1173049504500734410u }, { 9090360384495590213u, 1876879207201175057u },
+ { 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u },
+ { 16096930852848599373u, 1921924308174003258u }, { 1809498238053148529u, 1537539446539202607u },
+ { 12515645034668249793u, 1230031557231362085u }, { 1578287981759648052u, 1968050491570179337u },
+ { 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u },
+ { 3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u },
+ { 6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u },
+ { 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u },
+ { 7551343283653851484u, 2113178124542660985u }, { 6041074626923081187u, 1690542499634128788u },
+ { 12211557331022285596u, 1352433999707303030u }, { 1091747655926105338u, 2163894399531684849u },
+ { 4562746939482794594u, 1731115519625347879u }, { 7339546366328145998u, 1384892415700278303u },
+ { 8053925371383123274u, 2215827865120445285u }, { 6443140297106498619u, 1772662292096356228u },
+ { 12533209867169019542u, 1418129833677084982u }, { 5295740528502789974u, 2269007733883335972u },
+ { 15304638867027962949u, 1815206187106668777u }, { 4865013464138549713u, 1452164949685335022u },
+ { 14960057215536570740u, 1161731959748268017u }, { 9178696285890871890u, 1858771135597228828u },
+ { 14721654658196518159u, 1487016908477783062u }, { 4398626097073393881u, 1189613526782226450u },
+ { 7037801755317430209u, 1903381642851562320u }, { 5630241404253944167u, 1522705314281249856u },
+ { 814844308661245011u, 1218164251424999885u }, { 1303750893857992017u, 1949062802279999816u },
+ { 15800395974054034906u, 1559250241823999852u }, { 5261619149759407279u, 1247400193459199882u },
+ { 12107939454356961969u, 1995840309534719811u }, { 5997002748743659252u, 1596672247627775849u },
+ { 8486951013736837725u, 1277337798102220679u }, { 2511075177753209390u, 2043740476963553087u },
+ { 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u },
+ { 4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u },
+ { 3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u },
+ { 9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u },
+ { 5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u },
+ { 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u },
+ { 13453306206113055875u, 1797693134862315907u }, { 3383947335406624054u, 1438154507889852726u },
+ { 16482362180876329456u, 2301047212623764361u }, { 9496540929959153242u, 1840837770099011489u },
+ { 11286581558709232917u, 1472670216079209191u }, { 5339916432225476010u, 1178136172863367353u },
+ { 4854517476818851293u, 1885017876581387765u }, { 3883613981455081034u, 1508014301265110212u },
+ { 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u },
+ { 5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u },
+ { 6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u },
+ { 12969830440044306787u, 1265014083170691364u }, { 9683682259845159889u, 2024022533073106183u },
+ { 15125643437359948558u, 1619218026458484946u }, { 8411165935146048523u, 1295374421166787957u },
+ { 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u },
+ { 8022738107230848036u, 1326463407274790868u }, { 9147032156827446534u, 2122341451639665389u },
+ { 11006974540203867551u, 1697873161311732311u }, { 5116230817421183718u, 1358298529049385849u },
+ { 15564666937357714594u, 2173277646479017358u }, { 1383687105660440706u, 1738622117183213887u },
+ { 12174996128754083534u, 1390897693746571109u }, { 8411947361780802685u, 2225436309994513775u },
+ { 6729557889424642148u, 1780349047995611020u }, { 5383646311539713719u, 1424279238396488816u },
+ { 1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u },
+ { 16285752362063044992u, 1458461940118004547u }, { 5649904260166615347u, 1166769552094403638u },
+ { 5350498001524674232u, 1866831283351045821u }, { 591049586477829062u, 1493465026680836657u },
+ { 11540886113407994219u, 1194772021344669325u }, { 18673707743239135u, 1911635234151470921u },
+ { 14772334225162232601u, 1529308187321176736u }, { 8128518565387875758u, 1223446549856941389u },
+ { 1937583260394870242u, 1957514479771106223u }, { 8928764237799716840u, 1566011583816884978u },
+ { 14521709019723594119u, 1252809267053507982u }, { 8477339172590109297u, 2004494827285612772u },
+ { 17849917782297818407u, 1603595861828490217u }, { 6901236596354434079u, 1282876689462792174u },
+ { 18420676183650915173u, 2052602703140467478u }, { 3668494502695001169u, 1642082162512373983u },
+ { 10313493231639821582u, 1313665730009899186u }, { 9122891541139893884u, 2101865168015838698u },
+ { 14677010862395735754u, 1681492134412670958u }, { 673562245690857633u, 1345193707530136767u }
+};
+
+static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = {
+ { 0u, 1152921504606846976u }, { 0u, 1441151880758558720u },
+ { 0u, 1801439850948198400u }, { 0u, 2251799813685248000u },
+ { 0u, 1407374883553280000u }, { 0u, 1759218604441600000u },
+ { 0u, 2199023255552000000u }, { 0u, 1374389534720000000u },
+ { 0u, 1717986918400000000u }, { 0u, 2147483648000000000u },
+ { 0u, 1342177280000000000u }, { 0u, 1677721600000000000u },
+ { 0u, 2097152000000000000u }, { 0u, 1310720000000000000u },
+ { 0u, 1638400000000000000u }, { 0u, 2048000000000000000u },
+ { 0u, 1280000000000000000u }, { 0u, 1600000000000000000u },
+ { 0u, 2000000000000000000u }, { 0u, 1250000000000000000u },
+ { 0u, 1562500000000000000u }, { 0u, 1953125000000000000u },
+ { 0u, 1220703125000000000u }, { 0u, 1525878906250000000u },
+ { 0u, 1907348632812500000u }, { 0u, 1192092895507812500u },
+ { 0u, 1490116119384765625u }, { 4611686018427387904u, 1862645149230957031u },
+ { 9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u },
+ { 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u },
+ { 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u },
+ { 15629249925580062720u, 2220446049250313080u }, { 9768281203487539200u, 1387778780781445675u },
+ { 7598665485932036096u, 1734723475976807094u }, { 274959820560269312u, 2168404344971008868u },
+ { 9395221924704944128u, 1355252715606880542u }, { 2520655369026404352u, 1694065894508600678u },
+ { 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u },
+ { 13702562178731606016u, 1654361225106055349u }, { 3293144668132343808u, 2067951531382569187u },
+ { 18199116482078572544u, 1292469707114105741u }, { 8913837547316051968u, 1615587133892632177u },
+ { 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u },
+ { 15190102943214346240u, 1577721810442023610u }, { 9764256642163156992u, 1972152263052529513u },
+ { 17631875447420442880u, 1232595164407830945u }, { 8204786253993389888u, 1540743955509788682u },
+ { 1032610780636961552u, 1925929944387235853u }, { 2951224747111794922u, 1203706215242022408u },
+ { 3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u },
+ { 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u },
+ { 3710578054803671186u, 1836709923159824231u }, { 26536550077201078u, 2295887403949780289u },
+ { 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u },
+ { 8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u },
+ { 12076381983474541759u, 1751623080406021338u }, { 5872105442488401391u, 2189528850507526673u },
+ { 15199280947623720629u, 1368455531567204170u }, { 9775729147674874978u, 1710569414459005213u },
+ { 16831347453020981627u, 2138211768073756516u }, { 1296220121283337709u, 1336382355046097823u },
+ { 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u },
+ { 6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u },
+ { 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u },
+ { 532749306367912313u, 1593091911132452277u }, { 5277622651387278295u, 1991364888915565346u },
+ { 7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u },
+ { 8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u },
+ { 10989071563364309441u, 1519290839321567799u }, { 9124653435777998898u, 1899113549151959749u },
+ { 8008751406574943263u, 1186945968219974843u }, { 5399253239791291175u, 1483682460274968554u },
+ { 15972438586593889776u, 1854603075343710692u }, { 759402079766405302u, 1159126922089819183u },
+ { 14784310654990170340u, 1448908652612273978u }, { 9257016281882937117u, 1811135815765342473u },
+ { 16182956370781059300u, 2263919769706678091u }, { 7808504722524468110u, 1414949856066673807u },
+ { 5148944884728197234u, 1768687320083342259u }, { 1824495087482858639u, 2210859150104177824u },
+ { 1140309429676786649u, 1381786968815111140u }, { 1425386787095983311u, 1727233711018888925u },
+ { 6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u },
+ { 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u },
+ { 803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u },
+ { 4714634887749086344u, 2059023035787211567u }, { 9864175832484260821u, 1286889397367007229u },
+ { 16941905809032713930u, 1608611746708759036u }, { 2730638187581340797u, 2010764683385948796u },
+ { 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u },
+ { 4396021111970173586u, 1963637386119090621u }, { 5053356204195052443u, 1227273366324431638u },
+ { 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u },
+ { 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u },
+ { 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u },
+ { 4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u },
+ { 7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u },
+ { 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u },
+ { 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u },
+ { 10956397575869330579u, 2180075438084173168u }, { 6847748484918331612u, 1362547148802608230u },
+ { 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u },
+ { 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u },
+ { 13024893955298202172u, 2079081953128979843u }, { 5834715712847682405u, 1299426220705612402u },
+ { 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u },
+ { 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u },
+ { 12596021324643517422u, 1982767060402850955u }, { 5566670318688504437u, 1239229412751781847u },
+ { 2346651879933242642u, 1549036765939727309u }, { 7545000868343941206u, 1936295957424659136u },
+ { 4715625542714963254u, 1210184973390411960u }, { 5894531928393704067u, 1512731216738014950u },
+ { 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u },
+ { 16997363506238734644u, 1477276578845717724u }, { 2799960309088866689u, 1846595723557147156u },
+ { 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u },
+ { 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u },
+ { 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u },
+ { 3447025083132431277u, 2201313642927583642u }, { 6766076695385157452u, 1375821026829739776u },
+ { 8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u },
+ { 6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u },
+ { 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u },
+ { 5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u },
+ { 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u },
+ { 7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u },
+ { 3885132398186337741u, 1564127418111797597u }, { 9468101516160310080u, 1955159272639746996u },
+ { 15140935484454969608u, 1221974545399841872u }, { 479425281859160394u, 1527468181749802341u },
+ { 5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u },
+ { 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u },
+ { 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u },
+ { 8047776328842869663u, 1820883967578175474u }, { 836348374198811271u, 2276104959472719343u },
+ { 7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u },
+ { 8166621051047176104u, 2222758749485077483u }, { 2798295147690791113u, 1389224218428173427u },
+ { 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u },
+ { 8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u },
+ { 3828506775840797949u, 2119787930951192363u }, { 86973725686804766u, 1324867456844495227u },
+ { 13943775212390669669u, 1656084321055619033u }, { 3594660960206173375u, 2070105401319523792u },
+ { 2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u },
+ { 5816254103165035138u, 2021587305976097453u }, { 5941001823691840913u, 1263492066235060908u },
+ { 7426252279614801142u, 1579365082793826135u }, { 4671129331091113523u, 1974206353492282669u },
+ { 5225298841145639904u, 1233878970932676668u }, { 6531623551432049880u, 1542348713665845835u },
+ { 3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u },
+ { 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u },
+ { 11355826773077190286u, 1176718684132267635u }, { 9583097447919099954u, 1470898355165334544u },
+ { 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u },
+ { 2440964573842414192u, 1436424174966147016u }, { 3051205717303017741u, 1795530218707683770u },
+ { 13037379183483547984u, 2244412773384604712u }, { 8148361989677217490u, 1402757983365377945u },
+ { 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u },
+ { 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u },
+ { 9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u },
+ { 3292878744173340370u, 1672217826086733276u }, { 4116098430216675462u, 2090272282608416595u },
+ { 266718509671728212u, 1306420176630260372u }, { 333398137089660265u, 1633025220787825465u },
+ { 5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u },
+ { 12575375104699370472u, 1594751192175610805u }, { 1884160825592049379u, 1993438990219513507u },
+ { 17318501580490888525u, 1245899368887195941u }, { 7813068920331446945u, 1557374211108994927u },
+ { 5154650131986920777u, 1946717763886243659u }, { 915813323278131534u, 1216698602428902287u },
+ { 14979824709379828129u, 1520873253036127858u }, { 9501408849870009354u, 1901091566295159823u },
+ { 12855909558809837702u, 1188182228934474889u }, { 2234828893230133415u, 1485227786168093612u },
+ { 2793536116537666769u, 1856534732710117015u }, { 8663489100477123587u, 1160334207943823134u },
+ { 1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u },
+ { 9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u },
+ { 16011667041914537212u, 1770529492101780905u }, { 6179525747111007803u, 2213161865127226132u },
+ { 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u },
+ { 15834525901571292854u, 2161290883913306769u }, { 2979049660840976177u, 1350806802445816731u },
+ { 17558870131333383934u, 1688508503057270913u }, { 8113529608884566205u, 2110635628821588642u },
+ { 9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u },
+ { 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u },
+ { 1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u },
+ { 4853210475701136017u, 1258036869061940099u }, { 1454827076199032118u, 1572546086327425124u },
+ { 1818533845248790147u, 1965682607909281405u }, { 3442426662494187794u, 1228551629943300878u },
+ { 13526405364972510550u, 1535689537429126097u }, { 3072948650933474476u, 1919611921786407622u },
+ { 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u },
+ { 9630225068416591280u, 1874621017369538693u }, { 8324733676974063502u, 1171638135855961683u },
+ { 5794231077790191473u, 1464547669819952104u }, { 7242788847237739342u, 1830684587274940130u },
+ { 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u },
+ { 1596658836748081690u, 1787777917260683721u }, { 6607509564362490017u, 2234722396575854651u },
+ { 1823850468512862308u, 1396701497859909157u }, { 6891499104068465790u, 1745876872324886446u },
+ { 17837745916940358045u, 2182346090406108057u }, { 4231062170446641922u, 1363966306503817536u },
+ { 5288827713058302403u, 1704957883129771920u }, { 6611034641322878003u, 2131197353912214900u },
+ { 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u },
+ { 11644235287647684442u, 2081247415929897363u }, { 4971804045566108824u, 1300779634956185852u },
+ { 6214755056957636030u, 1625974543695232315u }, { 3156757802769657134u, 2032468179619040394u },
+ { 6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u },
+ { 17206059723201118751u, 1984832206659219134u }, { 6142101308573311315u, 1240520129162011959u },
+ { 3065940617289251240u, 1550650161452514949u }, { 8444111790038951954u, 1938312701815643686u },
+ { 665883850346957067u, 1211445438634777304u }, { 832354812933696334u, 1514306798293471630u },
+ { 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u },
+ { 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u },
+ { 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u },
+ { 1277659885424598868u, 1805194375864829576u }, { 1597074856780748586u, 2256492969831036970u },
+ { 5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u },
+ { 1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u },
+ { 11243484188358716120u, 1721567512383298469u }, { 219297180166231438u, 2151959390479123087u },
+ { 7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u },
+ { 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u },
+ { 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u },
+ { 16925056528170176201u, 1282667750405742577u }, { 7321262604930556539u, 1603334688007178222u },
+ { 18374950293017971482u, 2004168360008972777u }, { 4566814905495150320u, 1252605225005607986u },
+ { 14931890668723713708u, 1565756531257009982u }, { 9441491299049866327u, 1957195664071262478u },
+ { 1289246043478778550u, 1223247290044539049u }, { 6223243572775861092u, 1529059112555673811u },
+ { 3167368447542438461u, 1911323890694592264u }, { 1979605279714024038u, 1194577431684120165u },
+ { 7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u },
+ { 13606538515115052232u, 1166579523129023598u }, { 7784801107039039482u, 1458224403911279498u },
+ { 507629346944023544u, 1822780504889099373u }, { 5246222702107417334u, 2278475631111374216u },
+ { 3278889188817135834u, 1424047269444608885u }, { 8710297504448807696u, 1780059086805761106u }
+};
+
+// IEEE 754 double precision constants
+#define DOUBLE_MANTISSA_BITS 52
+#define DOUBLE_EXPONENT_BITS 11
+#define DOUBLE_EXPONENT_BIAS 1023
+
+// Helper: floor(log2(value)) using ryu_leading_zeros64
+static inline uint32_t floor_log2(const uint64_t value) {
+ return 63 - ryu_leading_zeros64(value);
+}
+
+// Helper: log2(5^e) approximation
+static inline int32_t log2pow5(const int32_t e) {
+ return (int32_t) ((((uint32_t) e) * 1217359) >> 19);
+}
+
+// Helper: ceil(log2(5^e))
+static inline int32_t ceil_log2pow5(const int32_t e) {
+ return log2pow5(e) + 1;
+}
+
+// Helper: max of two int32
+static inline int32_t max32(int32_t a, int32_t b) {
+ return a < b ? b : a;
+}
+
+// Helper: convert uint64 bits to double
+static inline double int64Bits2Double(uint64_t bits) {
+ double f;
+ memcpy(&f, &bits, sizeof(double));
+ return f;
+}
+
+// Check if value is multiple of 2^p
+static inline bool multipleOfPowerOf2(const uint64_t value, const uint32_t p) {
+ return (value & ((1ull << p) - 1)) == 0;
+}
+
+// Count how many times value is divisible by 5
+// Uses modular inverse to avoid expensive division
+static inline uint32_t pow5Factor(uint64_t value) {
+ const uint64_t m_inv_5 = 14757395258967641293u; // 5 * m_inv_5 = 1 (mod 2^64)
+ const uint64_t n_div_5 = 3689348814741910323u; // 2^64 / 5
+ uint32_t count = 0;
+ for (;;) {
+ value *= m_inv_5;
+ if (value > n_div_5)
+ break;
+ ++count;
+ }
+ return count;
+}
+
+// Check if value is multiple of 5^p
+// Optimized: uses modular inverse instead of division
+static inline bool multipleOfPowerOf5(const uint64_t value, const uint32_t p) {
+ return pow5Factor(value) >= p;
+}
+
+// 128-bit multiplication with shift
+// This is the core operation for converting decimal to binary
+#if defined(__SIZEOF_INT128__)
+// Use native 128-bit integers if available (GCC/Clang)
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+ const unsigned __int128 b0 = ((unsigned __int128) m) * mul[0];
+ const unsigned __int128 b2 = ((unsigned __int128) m) * mul[1];
+ return (uint64_t) (((b0 >> 64) + b2) >> (j - 64));
+}
+#else
+// Fallback for systems without 128-bit integers
+static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
+ const uint32_t aLo = (uint32_t)a;
+ const uint32_t aHi = (uint32_t)(a >> 32);
+ const uint32_t bLo = (uint32_t)b;
+ const uint32_t bHi = (uint32_t)(b >> 32);
+
+ const uint64_t b00 = (uint64_t)aLo * bLo;
+ const uint64_t b01 = (uint64_t)aLo * bHi;
+ const uint64_t b10 = (uint64_t)aHi * bLo;
+ const uint64_t b11 = (uint64_t)aHi * bHi;
+
+ const uint32_t b00Lo = (uint32_t)b00;
+ const uint32_t b00Hi = (uint32_t)(b00 >> 32);
+
+ const uint64_t mid1 = b10 + b00Hi;
+ const uint32_t mid1Lo = (uint32_t)(mid1);
+ const uint32_t mid1Hi = (uint32_t)(mid1 >> 32);
+
+ const uint64_t mid2 = b01 + mid1Lo;
+ const uint32_t mid2Lo = (uint32_t)(mid2);
+ const uint32_t mid2Hi = (uint32_t)(mid2 >> 32);
+
+ const uint64_t pHi = b11 + mid1Hi + mid2Hi;
+ const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo;
+
+ *productHi = pHi;
+ return pLo;
+}
+
+static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
+ return (hi << (64 - dist)) | (lo >> dist);
+}
+
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+ uint64_t high1;
+ const uint64_t low1 = umul128(m, mul[1], &high1);
+ uint64_t high0;
+ umul128(m, mul[0], &high0);
+ const uint64_t sum = high0 + low1;
+ if (sum < high0) {
+ ++high1;
+ }
+ return shiftright128(sum, high1, j - 64);
+}
+#endif
+
+// Main conversion function: decimal mantissa+exponent to IEEE 754 double
+// Optimized for JSON parsing with fast paths for edge cases
+static inline double ryu_s2d_from_parts(uint64_t m10, int m10digits, int32_t e10, bool signedM) {
+ // Fast path: handle zero explicitly (e.g., "0.0", "0e0")
+ if (m10 == 0) {
+ return int64Bits2Double(((uint64_t) signedM) << 63);
+ }
+
+ // Fast path: handle overflow/underflow early
+ if (m10digits + e10 <= -324) {
+ // Underflow to zero
+ return int64Bits2Double(((uint64_t) signedM) << 63);
+ }
+
+ if (m10digits + e10 >= 310) {
+ // Overflow to infinity
+ return int64Bits2Double((((uint64_t) signedM) << 63) | 0x7ff0000000000000ULL);
+ }
+
+ // Convert decimal to binary: m10 * 10^e10 = m2 * 2^e2
+ int32_t e2;
+ uint64_t m2;
+ bool trailingZeros;
+
+ if (e10 >= 0) {
+ // Positive exponent: multiply by 5^e10 and adjust binary exponent
+ e2 = floor_log2(m10) + e10 + log2pow5(e10) - (DOUBLE_MANTISSA_BITS + 1);
+ int j = e2 - e10 - ceil_log2pow5(e10) + DOUBLE_POW5_BITCOUNT;
+ m2 = mulShift64(m10, DOUBLE_POW5_SPLIT[e10], j);
+ trailingZeros = e2 < e10 || (e2 - e10 < 64 && multipleOfPowerOf2(m10, e2 - e10));
+ } else {
+ // Negative exponent: divide by 5^(-e10)
+ e2 = floor_log2(m10) + e10 - ceil_log2pow5(-e10) - (DOUBLE_MANTISSA_BITS + 1);
+ int j = e2 - e10 + ceil_log2pow5(-e10) - 1 + DOUBLE_POW5_INV_BITCOUNT;
+ m2 = mulShift64(m10, DOUBLE_POW5_INV_SPLIT[-e10], j);
+ trailingZeros = multipleOfPowerOf5(m10, -e10);
+ }
+
+ // Compute IEEE 754 exponent
+ uint32_t ieee_e2 = (uint32_t) max32(0, e2 + DOUBLE_EXPONENT_BIAS + floor_log2(m2));
+
+ if (ieee_e2 > 0x7fe) {
+ // Overflow to infinity
+ return int64Bits2Double((((uint64_t) signedM) << 63) | 0x7ff0000000000000ULL);
+ }
+
+ // Compute shift amount for rounding
+ int32_t shift = (ieee_e2 == 0 ? 1 : ieee_e2) - e2 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS;
+
+ // IEEE 754 round-to-even (banker's rounding)
+ trailingZeros &= (m2 & ((1ull << (shift - 1)) - 1)) == 0;
+ uint64_t lastRemovedBit = (m2 >> (shift - 1)) & 1;
+ bool roundUp = (lastRemovedBit != 0) && (!trailingZeros || (((m2 >> shift) & 1) != 0));
+
+ uint64_t ieee_m2 = (m2 >> shift) + roundUp;
+ ieee_m2 &= (1ull << DOUBLE_MANTISSA_BITS) - 1;
+
+ if (ieee_m2 == 0 && roundUp) {
+ ieee_e2++;
+ }
+
+ // Pack sign, exponent, and mantissa into IEEE 754 format
+ // Match original Ryu: group sign+exponent, then shift and add mantissa
+ uint64_t ieee = (((((uint64_t) signedM) << DOUBLE_EXPONENT_BITS) | (uint64_t)ieee_e2) << DOUBLE_MANTISSA_BITS) | ieee_m2;
+ return int64Bits2Double(ieee);
+}
+
+#endif // RYU_H
diff --git a/ext/monitor/depend b/ext/monitor/depend
index bc7ead0d32..0c7d54afc8 100644
--- a/ext/monitor/depend
+++ b/ext/monitor/depend
@@ -127,6 +127,7 @@ monitor.o: $(hdrdir)/ruby/internal/intern/re.h
monitor.o: $(hdrdir)/ruby/internal/intern/ruby.h
monitor.o: $(hdrdir)/ruby/internal/intern/select.h
monitor.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+monitor.o: $(hdrdir)/ruby/internal/intern/set.h
monitor.o: $(hdrdir)/ruby/internal/intern/signal.h
monitor.o: $(hdrdir)/ruby/internal/intern/sprintf.h
monitor.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/monitor/monitor.c b/ext/monitor/monitor.c
index 819c6e7699..c43751c4e2 100644
--- a/ext/monitor/monitor.c
+++ b/ext/monitor/monitor.c
@@ -4,28 +4,35 @@
struct rb_monitor {
long count;
- const VALUE owner;
- const VALUE mutex;
+ VALUE owner;
+ VALUE mutex;
};
static void
monitor_mark(void *ptr)
{
struct rb_monitor *mc = ptr;
- rb_gc_mark(mc->owner);
- rb_gc_mark(mc->mutex);
+ rb_gc_mark_movable(mc->owner);
+ rb_gc_mark_movable(mc->mutex);
}
-static size_t
-monitor_memsize(const void *ptr)
+static void
+monitor_compact(void *ptr)
{
- return sizeof(struct rb_monitor);
+ struct rb_monitor *mc = ptr;
+ mc->owner = rb_gc_location(mc->owner);
+ mc->mutex = rb_gc_location(mc->mutex);
}
static const rb_data_type_t monitor_data_type = {
- "monitor",
- {monitor_mark, RUBY_TYPED_DEFAULT_FREE, monitor_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
+ .wrap_struct_name = "monitor",
+ .function = {
+ .dmark = monitor_mark,
+ .dfree = RUBY_TYPED_DEFAULT_FREE,
+ .dsize = NULL, // Fully embeded
+ .dcompact = monitor_compact,
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
};
static VALUE
@@ -50,10 +57,10 @@ monitor_ptr(VALUE monitor)
return mc;
}
-static int
-mc_owner_p(struct rb_monitor *mc)
+static bool
+mc_owner_p(struct rb_monitor *mc, VALUE current_fiber)
{
- return mc->owner == rb_fiber_current();
+ return mc->owner == current_fiber;
}
/*
@@ -67,17 +74,44 @@ monitor_try_enter(VALUE monitor)
{
struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
+ VALUE current_fiber = rb_fiber_current();
+ if (!mc_owner_p(mc, current_fiber)) {
if (!rb_mutex_trylock(mc->mutex)) {
return Qfalse;
}
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
+ RB_OBJ_WRITE(monitor, &mc->owner, current_fiber);
mc->count = 0;
}
mc->count += 1;
return Qtrue;
}
+
+struct monitor_args {
+ VALUE monitor;
+ struct rb_monitor *mc;
+ VALUE current_fiber;
+};
+
+static inline void
+monitor_args_init(struct monitor_args *args, VALUE monitor)
+{
+ args->monitor = monitor;
+ args->mc = monitor_ptr(monitor);
+ args->current_fiber = rb_fiber_current();
+}
+
+static void
+monitor_enter0(struct monitor_args *args)
+{
+ if (!mc_owner_p(args->mc, args->current_fiber)) {
+ rb_mutex_lock(args->mc->mutex);
+ RB_OBJ_WRITE(args->monitor, &args->mc->owner, args->current_fiber);
+ args->mc->count = 0;
+ }
+ args->mc->count++;
+}
+
/*
* call-seq:
* enter -> nil
@@ -87,27 +121,44 @@ monitor_try_enter(VALUE monitor)
static VALUE
monitor_enter(VALUE monitor)
{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
- rb_mutex_lock(mc->mutex);
- RB_OBJ_WRITE(monitor, &mc->owner, rb_fiber_current());
- mc->count = 0;
- }
- mc->count++;
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_enter0(&args);
return Qnil;
}
+static inline void
+monitor_check_owner0(struct monitor_args *args)
+{
+ if (!mc_owner_p(args->mc, args->current_fiber)) {
+ rb_raise(rb_eThreadError, "current fiber not owner");
+ }
+}
+
/* :nodoc: */
static VALUE
monitor_check_owner(VALUE monitor)
{
- struct rb_monitor *mc = monitor_ptr(monitor);
- if (!mc_owner_p(mc)) {
- rb_raise(rb_eThreadError, "current fiber not owner");
- }
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_check_owner0(&args);
return Qnil;
}
+static void
+monitor_exit0(struct monitor_args *args)
+{
+ monitor_check_owner0(args);
+
+ if (args->mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)args->mc->count);
+ args->mc->count--;
+
+ if (args->mc->count == 0) {
+ RB_OBJ_WRITE(args->monitor, &args->mc->owner, Qnil);
+ rb_mutex_unlock(args->mc->mutex);
+ }
+}
+
/*
* call-seq:
* exit -> nil
@@ -117,17 +168,9 @@ monitor_check_owner(VALUE monitor)
static VALUE
monitor_exit(VALUE monitor)
{
- monitor_check_owner(monitor);
-
- struct rb_monitor *mc = monitor_ptr(monitor);
-
- if (mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)mc->count);
- mc->count--;
-
- if (mc->count == 0) {
- RB_OBJ_WRITE(monitor, &mc->owner, Qnil);
- rb_mutex_unlock(mc->mutex);
- }
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_exit0(&args);
return Qnil;
}
@@ -144,7 +187,7 @@ static VALUE
monitor_owned_p(VALUE monitor)
{
struct rb_monitor *mc = monitor_ptr(monitor);
- return (rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc)) ? Qtrue : Qfalse;
+ return rb_mutex_locked_p(mc->mutex) && mc_owner_p(mc, rb_fiber_current()) ? Qtrue : Qfalse;
}
static VALUE
@@ -210,9 +253,10 @@ monitor_sync_body(VALUE monitor)
}
static VALUE
-monitor_sync_ensure(VALUE monitor)
+monitor_sync_ensure(VALUE v_args)
{
- return monitor_exit(monitor);
+ monitor_exit0((struct monitor_args *)v_args);
+ return Qnil;
}
/*
@@ -226,8 +270,10 @@ monitor_sync_ensure(VALUE monitor)
static VALUE
monitor_synchronize(VALUE monitor)
{
- monitor_enter(monitor);
- return rb_ensure(monitor_sync_body, monitor, monitor_sync_ensure, monitor);
+ struct monitor_args args;
+ monitor_args_init(&args, monitor);
+ monitor_enter0(&args);
+ return rb_ensure(monitor_sync_body, (VALUE)&args, monitor_sync_ensure, (VALUE)&args);
}
void
diff --git a/ext/objspace/depend b/ext/objspace/depend
index a02168b06a..d9dfc0c42b 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -140,6 +140,7 @@ object_tracing.o: $(hdrdir)/ruby/internal/intern/re.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/ruby.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/select.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/set.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/signal.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/sprintf.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -177,14 +178,17 @@ object_tracing.o: $(top_srcdir)/ccan/check_type/check_type.h
object_tracing.o: $(top_srcdir)/ccan/container_of/container_of.h
object_tracing.o: $(top_srcdir)/ccan/list/list.h
object_tracing.o: $(top_srcdir)/ccan/str/str.h
+object_tracing.o: $(top_srcdir)/id_table.h
object_tracing.o: $(top_srcdir)/internal.h
object_tracing.o: $(top_srcdir)/internal/array.h
object_tracing.o: $(top_srcdir)/internal/basic_operators.h
+object_tracing.o: $(top_srcdir)/internal/box.h
object_tracing.o: $(top_srcdir)/internal/compilers.h
object_tracing.o: $(top_srcdir)/internal/gc.h
object_tracing.o: $(top_srcdir)/internal/imemo.h
object_tracing.o: $(top_srcdir)/internal/sanitizers.h
object_tracing.o: $(top_srcdir)/internal/serial.h
+object_tracing.o: $(top_srcdir)/internal/set_table.h
object_tracing.o: $(top_srcdir)/internal/static_assert.h
object_tracing.o: $(top_srcdir)/internal/vm.h
object_tracing.o: $(top_srcdir)/internal/warnings.h
@@ -340,6 +344,7 @@ objspace.o: $(hdrdir)/ruby/internal/intern/re.h
objspace.o: $(hdrdir)/ruby/internal/intern/ruby.h
objspace.o: $(hdrdir)/ruby/internal/intern/select.h
objspace.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+objspace.o: $(hdrdir)/ruby/internal/intern/set.h
objspace.o: $(hdrdir)/ruby/internal/intern/signal.h
objspace.o: $(hdrdir)/ruby/internal/intern/sprintf.h
objspace.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -386,6 +391,7 @@ objspace.o: $(top_srcdir)/id_table.h
objspace.o: $(top_srcdir)/internal.h
objspace.o: $(top_srcdir)/internal/array.h
objspace.o: $(top_srcdir)/internal/basic_operators.h
+objspace.o: $(top_srcdir)/internal/box.h
objspace.o: $(top_srcdir)/internal/class.h
objspace.o: $(top_srcdir)/internal/compilers.h
objspace.o: $(top_srcdir)/internal/gc.h
@@ -393,7 +399,9 @@ objspace.o: $(top_srcdir)/internal/hash.h
objspace.o: $(top_srcdir)/internal/imemo.h
objspace.o: $(top_srcdir)/internal/sanitizers.h
objspace.o: $(top_srcdir)/internal/serial.h
+objspace.o: $(top_srcdir)/internal/set_table.h
objspace.o: $(top_srcdir)/internal/static_assert.h
+objspace.o: $(top_srcdir)/internal/struct.h
objspace.o: $(top_srcdir)/internal/variable.h
objspace.o: $(top_srcdir)/internal/vm.h
objspace.o: $(top_srcdir)/internal/warnings.h
@@ -552,6 +560,7 @@ objspace_dump.o: $(hdrdir)/ruby/internal/intern/re.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/ruby.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/select.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/set.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/signal.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/sprintf.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -593,10 +602,12 @@ objspace_dump.o: $(top_srcdir)/ccan/list/list.h
objspace_dump.o: $(top_srcdir)/ccan/str/str.h
objspace_dump.o: $(top_srcdir)/constant.h
objspace_dump.o: $(top_srcdir)/debug_counter.h
+objspace_dump.o: $(top_srcdir)/encindex.h
objspace_dump.o: $(top_srcdir)/id_table.h
objspace_dump.o: $(top_srcdir)/internal.h
objspace_dump.o: $(top_srcdir)/internal/array.h
objspace_dump.o: $(top_srcdir)/internal/basic_operators.h
+objspace_dump.o: $(top_srcdir)/internal/box.h
objspace_dump.o: $(top_srcdir)/internal/class.h
objspace_dump.o: $(top_srcdir)/internal/compilers.h
objspace_dump.o: $(top_srcdir)/internal/gc.h
@@ -605,8 +616,10 @@ objspace_dump.o: $(top_srcdir)/internal/imemo.h
objspace_dump.o: $(top_srcdir)/internal/io.h
objspace_dump.o: $(top_srcdir)/internal/sanitizers.h
objspace_dump.o: $(top_srcdir)/internal/serial.h
+objspace_dump.o: $(top_srcdir)/internal/set_table.h
objspace_dump.o: $(top_srcdir)/internal/static_assert.h
objspace_dump.o: $(top_srcdir)/internal/string.h
+objspace_dump.o: $(top_srcdir)/internal/struct.h
objspace_dump.o: $(top_srcdir)/internal/variable.h
objspace_dump.o: $(top_srcdir)/internal/vm.h
objspace_dump.o: $(top_srcdir)/internal/warnings.h
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index 0156642ef2..c06f1f68dd 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -203,6 +203,8 @@ allocation_info_tracer_compact_update_object_table_i(st_data_t key, st_data_t va
st_table *table = (st_table *)data;
if (!rb_gc_pointer_to_heap_p(key)) {
+ struct allocation_info *info = (struct allocation_info *)value;
+ xfree(info);
return ST_DELETE;
}
@@ -411,6 +413,13 @@ object_allocations_reporter(FILE *out, void *ptr)
fprintf(out, "== object_allocations_reporter: END\n");
}
+/*
+ * call-seq: trace_object_allocations_debug_start
+ *
+ * Starts tracing object allocations for GC debugging.
+ * If you encounter the BUG "... is T_NONE" (and so on) on your
+ * application, please try this method at the beginning of your app.
+ */
static VALUE
trace_object_allocations_debug_start(VALUE self)
{
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index 0ead94713a..1143e4801d 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -38,10 +38,11 @@
* information as only a *HINT*. Especially, the size of +T_DATA+ may not be
* correct.
*
- * This method is only expected to work with C Ruby.
+ * This method is only expected to work with CRuby.
*
- * From Ruby 2.2, memsize_of(obj) returns a memory size includes
- * sizeof(RVALUE).
+ * From Ruby 3.2 with Variable Width Allocation, it returns the actual slot
+ * size used plus any additional memory allocated outside the slot (such
+ * as external strings, arrays, or hash tables).
*/
static VALUE
@@ -107,28 +108,24 @@ each_object_with_flags(each_obj_with_flags cb, void *ctx)
/*
* call-seq:
- * ObjectSpace.memsize_of_all([klass]) -> Integer
+ * ObjectSpace.memsize_of_all(klass = nil) -> integer
*
- * Return consuming memory size of all living objects in bytes.
+ * Returns the total memory size of all living objects in bytes.
*
- * If +klass+ (should be Class object) is given, return the total memory size
- * of instances of the given class.
+ * ObjectSpace.memsize_of_all # => 12502001
*
- * Note that the returned size is incomplete. You need to deal with this
- * information as only a *HINT*. Especially, the size of +T_DATA+ may not be
- * correct.
+ * If +klass+ is given (which must be a Class or Module), returns the total
+ * memory size of objects whose class is, or is a subclass, of +klass+.
*
- * Note that this method does *NOT* return total malloc'ed memory size.
+ * class MyClass; end
+ * ObjectSpace.memsize_of_all(MyClass) # => 0
+ * o = MyClass.new
+ * ObjectSpace.memsize_of_all(MyClass) # => 40
*
- * This method can be defined by the following Ruby code:
- *
- * def memsize_of_all klass = false
- * total = 0
- * ObjectSpace.each_object{|e|
- * total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass)
- * }
- * total
- * end
+ * Note that the value returned may be an underestimate of the actual amount
+ * of memory used. Therefore, the value returned should only be used as a hint,
+ * rather than a source of truth. In particular, the size of +T_DATA+ objects may
+ * not be correct.
*
* This method is only expected to work with C Ruby.
*/
@@ -140,6 +137,7 @@ memsize_of_all_m(int argc, VALUE *argv, VALUE self)
if (argc > 0) {
rb_scan_args(argc, argv, "01", &data.klass);
+ if (!NIL_P(data.klass)) rb_obj_is_kind_of(Qnil, data.klass);
}
each_object_with_flags(total_i, &data);
@@ -294,28 +292,27 @@ size_t rb_sym_immortal_count(void);
/*
* call-seq:
- * ObjectSpace.count_symbols([result_hash]) -> hash
- *
- * Counts symbols for each Symbol type.
+ * ObjectSpace.count_symbols(result_hash = nil) -> hash
*
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * Returns a hash containing the number of objects for each Symbol type.
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * The types of Symbols are the following:
*
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
+ * - +mortal_dynamic_symbol+: Symbols that are garbage collectable.
+ * - +immortal_dynamic_symbol+: Symbols that are objects allocated from the
+ * garbage collector, but are not garbage collectable.
+ * - +immortal_static_symbol+: Symbols that are not allocated from the
+ * garbage collector, and are thus not garbage collectable.
+ * - +immortal_symbol+: the sum of +immortal_dynamic_symbol+ and +immortal_static_symbol+.
*
- * This method is only expected to work with C Ruby.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * On this version of MRI, they have 3 types of Symbols (and 1 total counts).
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
- * * mortal_dynamic_symbol: GC target symbols (collected by GC)
- * * immortal_dynamic_symbol: Immortal symbols promoted from dynamic symbols (do not collected by GC)
- * * immortal_static_symbol: Immortal symbols (do not collected by GC)
- * * immortal_symbol: total immortal symbols (immortal_dynamic_symbol+immortal_static_symbol)
+ * This method is only expected to work with C Ruby.
*/
static VALUE
@@ -335,35 +332,6 @@ count_symbols(int argc, VALUE *argv, VALUE os)
return hash;
}
-/*
- * call-seq:
- * ObjectSpace.count_nodes([result_hash]) -> hash
- *
- * Counts nodes for each node type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
- *
- * It returns a hash as:
- *
- * {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
- *
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
- *
- * This method is only expected to work with C Ruby.
- */
-
-static VALUE
-count_nodes(int argc, VALUE *argv, VALUE os)
-{
- return setup_hash(argc, argv);
-}
-
static void
cto_i(VALUE v, void *data)
{
@@ -393,32 +361,22 @@ cto_i(VALUE v, void *data)
/*
* call-seq:
- * ObjectSpace.count_tdata_objects([result_hash]) -> hash
+ * ObjectSpace.count_tdata_objects(result_hash = nil) -> hash
*
- * Counts objects for each +T_DATA+ type.
+ * Returns a hash containing the number of objects for each +T_DATA+ type.
+ * The keys are Class objects when the +T_DATA+ object has an associated class,
+ * or Symbol objects of the name defined in the +rb_data_type_struct+ for internal
+ * +T_DATA+ objects.
*
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * ObjectSpace.count_tdata_objects
+ * # => {RBS::Location => 39255, marshal_compat_table: 1, Encoding => 103, mutex: 1, ... }
*
- * It returns a hash as:
- *
- * {RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6,
- * :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99,
- * ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1,
- * Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2}
- * # T_DATA objects existing at startup on r32276.
- *
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * The contents of the returned hash is implementation specific and may change
- * in the future.
- *
- * In this version, keys are Class object or Symbol object.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * If object is kind of normal (accessible) object, the key is Class object.
- * If object is not a kind of normal (internal) object, the key is symbol
- * name, registered by rb_data_type_struct.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -457,28 +415,22 @@ count_imemo_objects_i(VALUE v, void *data)
/*
* call-seq:
- * ObjectSpace.count_imemo_objects([result_hash]) -> hash
- *
- * Counts objects for each +T_IMEMO+ type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
- *
- * It returns a hash as:
+ * ObjectSpace.count_imemo_objects(result_hash = nil) -> hash
*
- * {:imemo_ifunc=>8,
- * :imemo_svar=>7,
- * :imemo_cref=>509,
- * :imemo_memo=>1,
- * :imemo_throw_data=>1}
+ * Returns a hash containing the number of objects for each +T_IMEMO+ type.
+ * The keys are Symbol objects of the +T_IMEMO+ type name.
+ * +T_IMEMO+ objects are Ruby internal objects that are not visible to Ruby
+ * programs.
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * ObjectSpace.count_imemo_objects
+ * # => {imemo_callcache: 5482, imemo_constcache: 1258, imemo_ment: 13906, ... }
*
- * The contents of the returned hash is implementation specific and may change
- * in the future.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * In this version, keys are symbol objects.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -499,11 +451,10 @@ count_imemo_objects(int argc, VALUE *argv, VALUE self)
INIT_IMEMO_TYPE_ID(imemo_ment);
INIT_IMEMO_TYPE_ID(imemo_iseq);
INIT_IMEMO_TYPE_ID(imemo_tmpbuf);
- INIT_IMEMO_TYPE_ID(imemo_ast);
- INIT_IMEMO_TYPE_ID(imemo_parser_strterm);
INIT_IMEMO_TYPE_ID(imemo_callinfo);
INIT_IMEMO_TYPE_ID(imemo_callcache);
INIT_IMEMO_TYPE_ID(imemo_constcache);
+ INIT_IMEMO_TYPE_ID(imemo_fields);
#undef INIT_IMEMO_TYPE_ID
}
@@ -792,7 +743,7 @@ objspace_internal_super_of(VALUE self, VALUE obj)
case T_MODULE:
case T_CLASS:
case T_ICLASS:
- super = RCLASS_SUPER(obj);
+ super = rb_class_super_of(obj);
break;
default:
rb_raise(rb_eArgError, "class or module is expected");
@@ -834,7 +785,6 @@ Init_objspace(void)
rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1);
- rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1);
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index dd0459bf56..da64698346 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -29,7 +29,7 @@
#include "ruby/util.h"
#include "ruby/io.h"
#include "vm_callinfo.h"
-#include "vm_core.h"
+#include "vm_sync.h"
RUBY_EXTERN const char ruby_hexdigits[];
@@ -394,9 +394,10 @@ dump_object(VALUE obj, struct dump_config *dc)
dc->cur_obj = obj;
dc->cur_obj_references = 0;
- if (BUILTIN_TYPE(obj) == T_NODE || BUILTIN_TYPE(obj) == T_IMEMO) {
+ if (BUILTIN_TYPE(obj) == T_NODE || (BUILTIN_TYPE(obj) == T_IMEMO && !IMEMO_TYPE_P(obj, imemo_fields))) {
dc->cur_obj_klass = 0;
- } else {
+ }
+ else {
dc->cur_obj_klass = RBASIC_CLASS(obj);
}
@@ -414,9 +415,11 @@ dump_object(VALUE obj, struct dump_config *dc)
dump_append(dc, obj_type(obj));
dump_append(dc, "\"");
- size_t shape_id = rb_shape_get_shape_id(obj);
- dump_append(dc, ", \"shape_id\":");
- dump_append_sizet(dc, shape_id);
+ if (BUILTIN_TYPE(obj) != T_IMEMO || IMEMO_TYPE_P(obj, imemo_fields)) {
+ size_t shape_id = rb_obj_shape_id(obj) & SHAPE_ID_OFFSET_MASK;
+ dump_append(dc, ", \"shape_id\":");
+ dump_append_sizet(dc, shape_id);
+ }
dump_append(dc, ", \"slot_size\":");
dump_append_sizet(dc, dc->cur_page_slot_size);
@@ -448,13 +451,16 @@ dump_object(VALUE obj, struct dump_config *dc)
break;
case imemo_callcache:
- mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
- if (mid != 0) {
- dump_append(dc, ", \"called_id\":");
- dump_append_id(dc, mid);
-
+ {
VALUE klass = ((const struct rb_callcache *)obj)->klass;
- if (klass != 0) {
+ if (klass != Qundef) {
+ mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
+ if (mid != 0) {
+ dump_append(dc, ", \"called_id\":");
+ dump_append_id(dc, mid);
+
+ }
+
dump_append(dc, ", \"receiver_class\":");
dump_append_ref(dc, klass);
}
@@ -537,7 +543,7 @@ dump_object(VALUE obj, struct dump_config *dc)
case T_CLASS:
dump_append(dc, ", \"variation_count\":");
- dump_append_d(dc, RCLASS_EXT(obj)->variation_count);
+ dump_append_d(dc, rb_class_variation_count(obj));
case T_MODULE:
if (rb_class_get_superclass(obj)) {
@@ -560,7 +566,7 @@ dump_object(VALUE obj, struct dump_config *dc)
}
}
- if (RCLASS_SINGLETON_P(obj)) {
+ if (rb_class_singleton_p(obj)) {
dump_append(dc, ", \"singleton\":true");
}
}
@@ -581,13 +587,13 @@ dump_object(VALUE obj, struct dump_config *dc)
break;
case T_OBJECT:
- if (FL_TEST(obj, ROBJECT_EMBED)) {
+ if (!FL_TEST_RAW(obj, ROBJECT_HEAP)) {
dump_append(dc, ", \"embedded\":true");
}
dump_append(dc, ", \"ivars\":");
- dump_append_lu(dc, ROBJECT_IV_COUNT(obj));
- if (rb_shape_obj_too_complex(obj)) {
+ dump_append_lu(dc, ROBJECT_FIELDS_COUNT(obj));
+ if (rb_shape_obj_too_complex_p(obj)) {
dump_append(dc, ", \"too_complex_shape\":true");
}
break;
@@ -765,15 +771,16 @@ dump_result(struct dump_config *dc)
return dc->given_output;
}
-/* :nodoc: */
static VALUE
-objspace_dump(VALUE os, VALUE obj, VALUE output)
+dump_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE obj = ((VALUE*)args_p)[0];
+ VALUE output = ((VALUE*)args_p)[1];
+
if (!RB_SPECIAL_CONST_P(obj)) {
dc.cur_page_slot_size = rb_gc_obj_slot_size(obj);
}
-
dump_output(&dc, output, Qnil, Qnil, Qnil);
dump_object(obj, &dc);
@@ -781,69 +788,73 @@ objspace_dump(VALUE os, VALUE obj, VALUE output)
return dump_result(&dc);
}
+/* :nodoc: */
+static VALUE
+objspace_dump(VALUE os, VALUE obj, VALUE output)
+{
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = output;
+ return rb_vm_lock_with_barrier(dump_locked, (void*)args);
+}
+
static void
-shape_i(rb_shape_t *shape, void *data)
+shape_id_i(shape_id_t shape_id, void *data)
{
struct dump_config *dc = (struct dump_config *)data;
- size_t shape_id = rb_shape_id(shape);
if (shape_id < dc->shapes_since) {
return;
}
dump_append(dc, "{\"address\":");
- dump_append_ref(dc, (VALUE)shape);
+ dump_append_ref(dc, (VALUE)RSHAPE(shape_id));
dump_append(dc, ", \"type\":\"SHAPE\", \"id\":");
dump_append_sizet(dc, shape_id);
- if (shape->type != SHAPE_ROOT) {
+ if (RSHAPE_TYPE(shape_id) != SHAPE_ROOT) {
dump_append(dc, ", \"parent_id\":");
- dump_append_lu(dc, shape->parent_id);
+ dump_append_lu(dc, RSHAPE_PARENT_RAW_ID(shape_id));
}
dump_append(dc, ", \"depth\":");
- dump_append_sizet(dc, rb_shape_depth(shape));
+ dump_append_sizet(dc, rb_shape_depth(shape_id));
- dump_append(dc, ", \"shape_type\":");
- switch((enum shape_type)shape->type) {
+ switch (RSHAPE_TYPE(shape_id)) {
case SHAPE_ROOT:
- dump_append(dc, "\"ROOT\"");
+ dump_append(dc, ", \"shape_type\":\"ROOT\"");
break;
case SHAPE_IVAR:
- dump_append(dc, "\"IVAR\"");
+ dump_append(dc, ", \"shape_type\":\"IVAR\"");
dump_append(dc, ",\"edge_name\":");
- dump_append_id(dc, shape->edge_name);
+ dump_append_id(dc, RSHAPE_EDGE_NAME(shape_id));
break;
- case SHAPE_FROZEN:
- dump_append(dc, "\"FROZEN\"");
- break;
- case SHAPE_T_OBJECT:
- dump_append(dc, "\"T_OBJECT\"");
+ case SHAPE_OBJ_ID:
+ dump_append(dc, ", \"shape_type\":\"OBJ_ID\"");
break;
- case SHAPE_OBJ_TOO_COMPLEX:
- dump_append(dc, "\"OBJ_TOO_COMPLEX\"");
- break;
- default:
- rb_bug("[objspace] unexpected shape type");
}
dump_append(dc, ", \"edges\":");
- dump_append_sizet(dc, rb_shape_edges_count(shape));
+ dump_append_sizet(dc, rb_shape_edges_count(shape_id));
dump_append(dc, ", \"memsize\":");
- dump_append_sizet(dc, rb_shape_memsize(shape));
+ dump_append_sizet(dc, rb_shape_memsize(shape_id));
dump_append(dc, "}\n");
}
-/* :nodoc: */
static VALUE
-objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
+dump_all_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE full = ((VALUE*)args_p)[1];
+ VALUE since = ((VALUE*)args_p)[2];
+ VALUE shapes = ((VALUE*)args_p)[3];
+
dump_output(&dc, output, full, since, shapes);
if (!dc.partial_dump || dc.since == 0) {
@@ -853,7 +864,7 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
}
if (RTEST(shapes)) {
- rb_shape_each_shape(shape_i, &dc);
+ rb_shape_each_shape_id(shape_id_i, &dc);
}
/* dump all objects */
@@ -864,17 +875,41 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
/* :nodoc: */
static VALUE
-objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
+objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
+{
+ VALUE args[4];
+ args[0] = output;
+ args[1] = full;
+ args[2] = since;
+ args[3] = shapes;
+ return rb_vm_lock_with_barrier(dump_all_locked, (void*)args);
+}
+
+static VALUE
+dump_shapes_locked(void *args_p)
{
struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE shapes = ((VALUE*)args_p)[1];
+
dump_output(&dc, output, Qfalse, Qnil, shapes);
if (RTEST(shapes)) {
- rb_shape_each_shape(shape_i, &dc);
+ rb_shape_each_shape_id(shape_id_i, &dc);
}
return dump_result(&dc);
}
+/* :nodoc: */
+static VALUE
+objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
+{
+ VALUE args[2];
+ args[0] = output;
+ args[1] = shapes;
+ return rb_vm_lock_with_barrier(dump_shapes_locked, (void*)args);
+}
+
void
Init_objspace_dump(VALUE rb_mObjSpace)
{
@@ -882,6 +917,9 @@ Init_objspace_dump(VALUE rb_mObjSpace)
#if 0
rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */
#endif
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ RB_EXT_RACTOR_SAFE(true);
+#endif
rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2);
rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 4);
diff --git a/ext/openssl/History.md b/ext/openssl/History.md
index ad3417f9d0..419237ff16 100644
--- a/ext/openssl/History.md
+++ b/ext/openssl/History.md
@@ -1,3 +1,100 @@
+Version 4.0.0
+=============
+
+Compatibility
+-------------
+
+* Ruby >= 2.7
+* OpenSSL >= 1.1.1, LibreSSL >= 3.9, and AWS-LC 1.66.0
+ - Removed support for OpenSSL 1.0.2-1.1.0 and LibreSSL 3.1-3.8.
+ [[GitHub #835]](https://github.com/ruby/openssl/issues/835)
+ - Added support for AWS-LC.
+ [[GitHub #833]](https://github.com/ruby/openssl/issues/833)
+
+
+Notable changes
+---------------
+
+* `OpenSSL::SSL`
+ - Reduce overhead when writing to `OpenSSL::SSL::SSLSocket`. `#syswrite` no
+ longer creates a temporary String object.
+ [[GitHub #831]](https://github.com/ruby/openssl/pull/831)
+ - Make `OpenSSL::SSL::SSLContext#min_version=` and `#max_version=` wrap the
+ corresponding OpenSSL APIs directly, and remove the fallback to SSL options.
+ [[GitHub #849]](https://github.com/ruby/openssl/pull/849)
+ - Add `OpenSSL::SSL::SSLContext#sigalgs=` and `#client_sigalgs=` for
+ specifying signature algorithms to use for connections.
+ [[GitHub #895]](https://github.com/ruby/openssl/pull/895)
+ - Rename `OpenSSL::SSL::SSLContext#ecdh_curves=` to `#groups=` following
+ the underlying OpenSSL API rename. This method is no longer specific to
+ ECDHE. The old method remains as an alias.
+ [[GitHub #900]](https://github.com/ruby/openssl/pull/900)
+ - Add `OpenSSL::SSL::SSLSocket#sigalg`, `#peer_sigalg`, and `#group` for
+ getting the signature algorithm and the key agreement group used in the
+ current connection.
+ [[GitHub #908]](https://github.com/ruby/openssl/pull/908)
+ - Enable `SSL_CTX_set_dh_auto()` for servers by default.
+ [[GitHub #924]](https://github.com/ruby/openssl/pull/924)
+ - Improve Ractor compatibility. Note that the internal-use constant
+ `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS` is now frozen.
+ [[GitHub #925]](https://github.com/ruby/openssl/pull/925)
+* `OpenSSL::PKey`
+ - Remove `OpenSSL::PKey::EC::Point#mul` support with array arguments. The
+ underlying OpenSSL API has been removed, and the method has been deprecated
+ since ruby/openssl v3.0.0.
+ [[GitHub #843]](https://github.com/ruby/openssl/pull/843)
+ - `OpenSSL::PKey::{RSA,DSA,DH}#params` uses `nil` to indicate missing fields
+ instead of the number `0`.
+ [[GitHub #774]](https://github.com/ruby/openssl/pull/774)
+ - Unify `OpenSSL::PKey::PKeyError` classes. The former subclasses
+ `OpenSSL::PKey::DHError`, `OpenSSL::PKey::DSAError`,
+ `OpenSSL::PKey::ECError`, and `OpenSSL::PKey::RSAError` have been merged
+ into a single class.
+ [[GitHub #929]](https://github.com/ruby/openssl/pull/929)
+* `OpenSSL::Cipher`
+ - `OpenSSL::Cipher#encrypt` and `#decrypt` no longer accept arguments.
+ Passing passwords has been deprecated since Ruby 1.8.2 (released in 2004).
+ [[GitHub #887]](https://github.com/ruby/openssl/pull/887)
+ - `OpenSSL::Cipher#final` raises `OpenSSL::Cipher::AuthTagError` when the
+ integrity check fails for AEAD ciphers. `OpenSSL::Cipher::AuthTagError` is a
+ new subclass of `OpenSSL::Cipher::CipherError`, which was previously raised.
+ [[GitHub #939]](https://github.com/ruby/openssl/pull/939)
+ - `OpenSSL::Cipher.new` now raises `OpenSSL::Cipher::CipherError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" cipher algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::Digest`
+ - `OpenSSL::Digest.new` now raises `OpenSSL::Digest::DigestError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" digest algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::ASN1.decode` now assumes a 1950-2049 year range for `UTCTime`
+ according to RFC 5280. It previously used a 1969-2068 range. The encoder
+ has always used the 1950-2049 range.
+ [[GitHub #909]](https://github.com/ruby/openssl/pull/909)
+* `OpenSSL::OpenSSLError`, the base class for all ruby/openssl errors, carry
+ an additional attribute `#errors` to keep the content of OpenSSL's error
+ queue. Also, add `#detailed_message` for Ruby 3.2 or later.
+ [[GitHub #976]](https://github.com/ruby/openssl/pull/976)
+* `OpenSSL::PKCS7.new` raises `OpenSSL::PKCS7::PKCS7Error` instead of
+ `ArgumentError` on error to be consistent with other constructors.
+ [[GitHub #983]](https://github.com/ruby/openssl/pull/983)
+
+
+Version 3.3.2
+=============
+
+Merged changes in 3.1.3 and 3.2.3.
+
+
+Version 3.3.1
+=============
+
+Merged changes in 3.1.2 and 3.2.2.
+
+
Version 3.3.0
=============
@@ -74,6 +171,18 @@ And various non-user-visible changes and bug fixes. Please see the commit
history for more details.
+Version 3.2.3
+=============
+
+Merged changes in 3.1.3.
+
+
+Version 3.2.2
+=============
+
+Merged changes in 3.1.2.
+
+
Version 3.2.1
=============
@@ -120,6 +229,33 @@ Notable changes
[[GitHub #141]](https://github.com/ruby/openssl/pull/141)
+Version 3.1.3
+=============
+
+Bug fixes
+---------
+
+* Fix missing NULL check for `EVP_PKEY_get0()` functions with OpenSSL 3.x.
+ [[GitHub #957]](https://github.com/ruby/openssl/pull/957)
+
+
+Version 3.1.2
+=============
+
+Bug fixes
+---------
+
+* Fix crash when attempting to export an incomplete `OpenSSL::PKey::DSA` key.
+ [[GitHub #845]](https://github.com/ruby/openssl/issues/845)
+ [[GitHub #847]](https://github.com/ruby/openssl/pull/847)
+* Remove the `OpenSSL::X509::V_FLAG_CRL_CHECK_ALL` flag from the default store
+ used by `OpenSSL::SSL::SSLContext#set_params`. It causes certificate
+ verification to fail with OpenSSL 3.6.0. It has no effect with any other
+ OpenSSL versions.
+ [[GitHub #949]](https://github.com/ruby/openssl/issues/949)
+ [[GitHub #950]](https://github.com/ruby/openssl/pull/950)
+
+
Version 3.1.1
=============
diff --git a/ext/openssl/depend b/ext/openssl/depend
index 0a8800a94a..435f4a1c68 100644
--- a/ext/openssl/depend
+++ b/ext/openssl/depend
@@ -142,6 +142,7 @@ ossl.o: $(hdrdir)/ruby/internal/intern/re.h
ossl.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl.o: $(hdrdir)/ruby/internal/intern/select.h
ossl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl.o: $(hdrdir)/ruby/internal/intern/set.h
ossl.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -338,6 +339,7 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_asn1.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -534,6 +536,7 @@ ossl_bio.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_bio.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -730,6 +733,7 @@ ossl_bn.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_bn.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -926,6 +930,7 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_cipher.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1122,6 +1127,7 @@ ossl_config.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_config.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1318,6 +1324,7 @@ ossl_digest.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_digest.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1514,6 +1521,7 @@ ossl_engine.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_engine.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1710,6 +1718,7 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_hmac.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1906,6 +1915,7 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_kdf.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2102,6 +2112,7 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2298,6 +2309,7 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2494,6 +2506,7 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2690,6 +2703,7 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2886,6 +2900,7 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3082,6 +3097,7 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3278,6 +3294,7 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3474,6 +3491,7 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3670,6 +3688,7 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3866,6 +3885,7 @@ ossl_provider.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_provider.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_provider.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_provider.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_provider.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_provider.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_provider.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_provider.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4062,6 +4082,7 @@ ossl_rand.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_rand.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4258,6 +4279,7 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ssl.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4454,6 +4476,7 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4650,6 +4673,7 @@ ossl_ts.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_ts.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -4846,6 +4870,7 @@ ossl_x509.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5042,6 +5067,7 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5238,6 +5264,7 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5434,6 +5461,7 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5630,6 +5658,7 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -5826,6 +5855,7 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509name.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -6022,6 +6052,7 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509req.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -6218,6 +6249,7 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -6414,6 +6446,7 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/intern/re.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/ruby.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/select.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ossl_x509store.o: $(hdrdir)/ruby/internal/intern/set.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/signal.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index 5bb045e895..a897c86b65 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -38,8 +38,12 @@ Logging::message "=== OpenSSL for Ruby configurator ===\n"
$defs.push("-D""OPENSSL_SUPPRESS_DEPRECATED")
-have_func("rb_io_descriptor")
-have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") # Ruby 3.1
+# Missing in TruffleRuby
+have_func("rb_call_super_kw(0, NULL, 0)", "ruby.h")
+# Ruby 3.1
+have_func("rb_io_descriptor", "ruby/io.h")
+have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h")
+# Ruby 3.2
have_func("rb_io_timeout", "ruby/io.h")
Logging::message "=== Checking for system dependent stuff... ===\n"
@@ -135,6 +139,11 @@ ssl_h = "openssl/ssl.h".freeze
# compile options
have_func("RAND_egd()", "openssl/rand.h")
+# added in OpenSSL 1.0.2, not in LibreSSL yet
+have_func("SSL_CTX_set1_sigalgs_list(NULL, NULL)", ssl_h)
+# added in OpenSSL 1.0.2, not in LibreSSL or AWS-LC yet
+have_func("SSL_CTX_set1_client_sigalgs_list(NULL, NULL)", ssl_h)
+
# added in 1.1.0, currently not in LibreSSL
have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0)", evp_h)
@@ -142,7 +151,7 @@ have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0
have_func("EVP_PKEY_check(NULL)", evp_h)
# added in 3.0.0
-have_func("SSL_set0_tmp_dh_pkey(NULL, NULL)", ssl_h)
+have_func("SSL_CTX_set0_tmp_dh_pkey(NULL, NULL)", ssl_h)
have_func("ERR_get_error_all(NULL, NULL, NULL, NULL, NULL)", "openssl/err.h")
have_func("SSL_CTX_load_verify_file(NULL, \"\")", ssl_h)
have_func("BN_check_prime(NULL, NULL, NULL)", "openssl/bn.h")
@@ -151,9 +160,15 @@ have_func("EVP_MD_CTX_get_pkey_ctx(NULL)", evp_h)
have_func("EVP_PKEY_eq(NULL, NULL)", evp_h)
have_func("EVP_PKEY_dup(NULL)", evp_h)
+# added in 3.2.0
+have_func("SSL_get0_group_name(NULL)", ssl_h)
+
# added in 3.4.0
have_func("TS_VERIFY_CTX_set0_certs(NULL, NULL)", ts_h)
+# added in 3.5.0
+have_func("SSL_get0_peer_signature_name(NULL, NULL)", ssl_h)
+
Logging::message "=== Checking done. ===\n"
# Append flags from environment variables.
diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb
index 0889923890..98fa8d39f2 100644
--- a/ext/openssl/lib/openssl.rb
+++ b/ext/openssl/lib/openssl.rb
@@ -13,23 +13,26 @@
require 'openssl.so'
require_relative 'openssl/bn'
-require_relative 'openssl/asn1'
-require_relative 'openssl/pkey'
require_relative 'openssl/cipher'
require_relative 'openssl/digest'
require_relative 'openssl/hmac'
-require_relative 'openssl/x509'
-require_relative 'openssl/ssl'
require_relative 'openssl/pkcs5'
+require_relative 'openssl/pkey'
+require_relative 'openssl/ssl'
require_relative 'openssl/version'
+require_relative 'openssl/x509'
module OpenSSL
- # call-seq:
- # OpenSSL.secure_compare(string, string) -> boolean
+ # :call-seq:
+ # OpenSSL.secure_compare(string, string) -> true or false
#
# Constant time memory comparison. Inputs are hashed using SHA-256 to mask
# the length of the secret. Returns +true+ if the strings are identical,
# +false+ otherwise.
+ #
+ # This method is expensive due to the SHA-256 hashing. In most cases, where
+ # the input lengths are known to be equal or are not sensitive,
+ # OpenSSL.fixed_length_secure_compare should be used instead.
def self.secure_compare(a, b)
hashed_a = OpenSSL::Digest.digest('SHA256', a)
hashed_b = OpenSSL::Digest.digest('SHA256', b)
diff --git a/ext/openssl/lib/openssl/asn1.rb b/ext/openssl/lib/openssl/asn1.rb
deleted file mode 100644
index 89fa28e1fb..0000000000
--- a/ext/openssl/lib/openssl/asn1.rb
+++ /dev/null
@@ -1,188 +0,0 @@
-# frozen_string_literal: true
-#--
-#
-# = Ruby-space definitions that completes C-space funcs for ASN.1
-#
-# = Licence
-# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
-#++
-
-module OpenSSL
- module ASN1
- class ASN1Data
- #
- # Carries the value of a ASN.1 type.
- # Please confer Constructive and Primitive for the mappings between
- # ASN.1 data types and Ruby classes.
- #
- attr_accessor :value
-
- # An Integer representing the tag number of this ASN1Data. Never +nil+.
- attr_accessor :tag
-
- # A Symbol representing the tag class of this ASN1Data. Never +nil+.
- # See ASN1Data for possible values.
- attr_accessor :tag_class
-
- #
- # Never +nil+. A boolean value indicating whether the encoding uses
- # indefinite length (in the case of parsing) or whether an indefinite
- # length form shall be used (in the encoding case).
- # In DER, every value uses definite length form. But in scenarios where
- # large amounts of data need to be transferred it might be desirable to
- # have some kind of streaming support available.
- # For example, huge OCTET STRINGs are preferably sent in smaller-sized
- # chunks, each at a time.
- # This is possible in BER by setting the length bytes of an encoding
- # to zero and by this indicating that the following value will be
- # sent in chunks. Indefinite length encodings are always constructed.
- # The end of such a stream of chunks is indicated by sending a EOC
- # (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
- # encoding, but also primitive types such as e.g. OCTET STRINGS or
- # BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
- #
- attr_accessor :indefinite_length
-
- alias infinite_length indefinite_length
- alias infinite_length= indefinite_length=
-
- #
- # :call-seq:
- # OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
- #
- # _value_: Please have a look at Constructive and Primitive to see how Ruby
- # types are mapped to ASN.1 types and vice versa.
- #
- # _tag_: An Integer indicating the tag number.
- #
- # _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
- # possible values.
- #
- # == Example
- # asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
- # tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
- #
- def initialize(value, tag, tag_class)
- raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
-
- @tag = tag
- @value = value
- @tag_class = tag_class
- @indefinite_length = false
- end
- end
-
- module TaggedASN1Data
- #
- # May be used as a hint for encoding a value either implicitly or
- # explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
- # _tagging_ is not set when a ASN.1 structure is parsed using
- # OpenSSL::ASN1.decode.
- #
- attr_accessor :tagging
-
- # :call-seq:
- # OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
- #
- # _value_: is mandatory.
- #
- # _tag_: optional, may be specified for tagged values. If no _tag_ is
- # specified, the UNIVERSAL tag corresponding to the Primitive sub-class
- # is used by default.
- #
- # _tagging_: may be used as an encoding hint to encode a value either
- # explicitly or implicitly, see ASN1 for possible values.
- #
- # _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
- # +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
- # +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
- # cf. ASN1.
- #
- # == Example
- # int = OpenSSL::ASN1::Integer.new(42)
- # zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
- # private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
- #
- def initialize(value, tag = nil, tagging = nil, tag_class = nil)
- tag ||= ASN1.take_default_tag(self.class)
-
- raise ASN1Error, "must specify tag number" unless tag
-
- if tagging
- raise ASN1Error, "invalid tagging method" unless tagging.is_a?(Symbol)
- end
-
- tag_class ||= tagging ? :CONTEXT_SPECIFIC : :UNIVERSAL
-
- raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
-
- @tagging = tagging
- super(value ,tag, tag_class)
- end
- end
-
- class Primitive < ASN1Data
- include TaggedASN1Data
-
- undef_method :indefinite_length=
- undef_method :infinite_length=
- end
-
- class Constructive < ASN1Data
- include TaggedASN1Data
- include Enumerable
-
- # :call-seq:
- # asn1_ary.each { |asn1| block } => asn1_ary
- #
- # Calls the given block once for each element in self, passing that element
- # as parameter _asn1_. If no block is given, an enumerator is returned
- # instead.
- #
- # == Example
- # asn1_ary.each do |asn1|
- # puts asn1
- # end
- #
- def each(&blk)
- @value.each(&blk)
-
- self
- end
- end
-
- class Boolean < Primitive ; end
- class Integer < Primitive ; end
- class Enumerated < Primitive ; end
-
- class BitString < Primitive
- attr_accessor :unused_bits
-
- def initialize(*)
- super
-
- @unused_bits = 0
- end
- end
-
- class EndOfContent < ASN1Data
- def initialize
- super("", 0, :UNIVERSAL)
- end
- end
-
- # :nodoc:
- def self.take_default_tag(klass)
- tag = CLASS_TAG_MAP[klass]
-
- return tag if tag
-
- sklass = klass.superclass
-
- return unless sklass
-
- take_default_tag(sklass)
- end
- end
-end
diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb
index 5cda1e931c..46ddfd6021 100644
--- a/ext/openssl/lib/openssl/digest.rb
+++ b/ext/openssl/lib/openssl/digest.rb
@@ -57,7 +57,7 @@ module OpenSSL
# OpenSSL::Digest("MD5")
# # => OpenSSL::Digest::MD5
#
- # Digest("Foo")
+ # OpenSSL::Digest("Foo")
# # => NameError: wrong constant name Foo
def Digest(name)
diff --git a/ext/openssl/lib/openssl/pkey.rb b/ext/openssl/lib/openssl/pkey.rb
index 3d1e8885ca..39871e15dd 100644
--- a/ext/openssl/lib/openssl/pkey.rb
+++ b/ext/openssl/lib/openssl/pkey.rb
@@ -7,6 +7,9 @@
require_relative 'marshal'
module OpenSSL::PKey
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ DHError = PKeyError
+
class DH
include OpenSSL::Marshal
@@ -102,7 +105,7 @@ module OpenSSL::PKey
# puts dh0.pub_key == dh.pub_key #=> false
def generate_key!
if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000
- raise DHError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \
+ raise PKeyError, "OpenSSL::PKey::DH is immutable on OpenSSL 3.0; " \
"use OpenSSL::PKey.generate_key instead"
end
@@ -147,6 +150,9 @@ module OpenSSL::PKey
end
end
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ DSAError = PKeyError
+
class DSA
include OpenSSL::Marshal
@@ -242,13 +248,9 @@ module OpenSSL::PKey
# sig = dsa.sign_raw(nil, digest)
# p dsa.verify_raw(nil, sig, digest) #=> true
def syssign(string)
- q or raise OpenSSL::PKey::DSAError, "incomplete DSA"
- private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!"
- begin
- sign_raw(nil, string)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::DSAError, $!.message
- end
+ q or raise PKeyError, "incomplete DSA"
+ private? or raise PKeyError, "Private DSA key needed!"
+ sign_raw(nil, string)
end
# :call-seq:
@@ -266,12 +268,13 @@ module OpenSSL::PKey
# A \DSA signature value.
def sysverify(digest, sig)
verify_raw(nil, sig, digest)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::DSAError, $!.message
end
end
if defined?(EC)
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ ECError = PKeyError
+
class EC
include OpenSSL::Marshal
@@ -282,8 +285,6 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
def dsa_sign_asn1(data)
sign_raw(nil, data)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::ECError, $!.message
end
# :call-seq:
@@ -293,8 +294,6 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
def dsa_verify_asn1(data, sig)
verify_raw(nil, sig, data)
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::ECError, $!.message
end
# :call-seq:
@@ -334,6 +333,9 @@ module OpenSSL::PKey
end
end
+ # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.
+ RSAError = PKeyError
+
class RSA
include OpenSSL::Marshal
@@ -407,15 +409,11 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
# PKey::PKey#verify_recover instead.
def private_encrypt(string, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- private? or raise OpenSSL::PKey::RSAError, "private key needed."
- begin
- sign_raw(nil, string, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ private? or raise PKeyError, "private key needed."
+ sign_raw(nil, string, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -430,14 +428,10 @@ module OpenSSL::PKey
# Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
# PKey::PKey#verify_recover instead.
def public_decrypt(string, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- begin
- verify_recover(nil, string, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ verify_recover(nil, string, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -452,14 +446,10 @@ module OpenSSL::PKey
# <b>Deprecated in version 3.0</b>.
# Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
def public_encrypt(data, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- begin
- encrypt(data, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ encrypt(data, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
# :call-seq:
@@ -473,15 +463,11 @@ module OpenSSL::PKey
# <b>Deprecated in version 3.0</b>.
# Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
def private_decrypt(data, padding = PKCS1_PADDING)
- n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
- private? or raise OpenSSL::PKey::RSAError, "private key needed."
- begin
- decrypt(data, {
- "rsa_padding_mode" => translate_padding_mode(padding),
- })
- rescue OpenSSL::PKey::PKeyError
- raise OpenSSL::PKey::RSAError, $!.message
- end
+ n or raise PKeyError, "incomplete RSA"
+ private? or raise PKeyError, "private key needed."
+ decrypt(data, {
+ "rsa_padding_mode" => translate_padding_mode(padding),
+ })
end
PKCS1_PADDING = 1
@@ -500,7 +486,7 @@ module OpenSSL::PKey
when PKCS1_OAEP_PADDING
"oaep"
else
- raise OpenSSL::PKey::PKeyError, "unsupported padding mode"
+ raise PKeyError, "unsupported padding mode"
end
end
end
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index a0ad5dc3a6..3268c126b9 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -32,25 +32,6 @@ module OpenSSL
}.call
}
- if defined?(OpenSSL::PKey::DH)
- DH_ffdhe2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
------BEGIN DH PARAMETERS-----
-MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
-+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
-87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
-YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
-7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
-ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
------END DH PARAMETERS-----
- _end_of_pem_
- private_constant :DH_ffdhe2048
-
- DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
- warn "using default DH parameters." if $VERBOSE
- DH_ffdhe2048
- }
- end
-
if !OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL")
DEFAULT_PARAMS.merge!(
min_version: OpenSSL::SSL::TLS1_VERSION,
@@ -85,26 +66,13 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
AES256-SHA256
AES128-SHA
AES256-SHA
- }.join(":"),
+ }.join(":").freeze,
)
end
+ DEFAULT_PARAMS.freeze
DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc:
DEFAULT_CERT_STORE.set_default_paths
- DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
-
- # A callback invoked when DH parameters are required for ephemeral DH key
- # exchange.
- #
- # The callback is invoked with the SSLSocket, a
- # flag indicating the use of an export cipher and the keylength
- # required.
- #
- # The callback must return an OpenSSL::PKey::DH instance of the correct
- # key length.
- #
- # <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.
- attr_accessor :tmp_dh_callback
# A callback invoked at connect time to distinguish between multiple
# server names.
@@ -147,7 +115,14 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
params.each{|name, value| self.__send__("#{name}=", value) }
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
unless self.ca_file or self.ca_path or self.cert_store
- self.cert_store = DEFAULT_CERT_STORE
+ if not defined?(Ractor) or Ractor.current == Ractor.main
+ self.cert_store = DEFAULT_CERT_STORE
+ else
+ self.cert_store = Ractor.current[:__openssl_default_store__] ||=
+ OpenSSL::X509::Store.new.tap { |store|
+ store.set_default_paths
+ }
+ end
end
end
return params
@@ -457,10 +432,6 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
@context.client_cert_cb
end
- def tmp_dh_callback
- @context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK
- end
-
def session_new_cb
@context.session_new_cb
end
diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb
index 3398fe39cc..88570562e2 100644
--- a/ext/openssl/lib/openssl/version.rb
+++ b/ext/openssl/lib/openssl/version.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module OpenSSL
- VERSION = "3.3.0"
+ # The version string of Ruby/OpenSSL.
+ VERSION = "4.0.0"
end
diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb
index 6459d37b12..66765ffeab 100644
--- a/ext/openssl/lib/openssl/x509.rb
+++ b/ext/openssl/lib/openssl/x509.rb
@@ -346,6 +346,15 @@ module OpenSSL
include Extension::CRLDistributionPoints
include Extension::AuthorityInfoAccess
+ def inspect
+ "#<#{self.class}: " \
+ "subject=#{subject.inspect}, " \
+ "issuer=#{issuer.inspect}, " \
+ "serial=#{serial.inspect}, " \
+ "not_before=#{not_before.inspect rescue "(error)"}, " \
+ "not_after=#{not_after.inspect rescue "(error)"}>"
+ end
+
def pretty_print(q)
q.object_group(self) {
q.breakable
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec
index 9f7c718592..7072d599d8 100644
--- a/ext/openssl/openssl.gemspec
+++ b/ext/openssl/openssl.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "openssl"
- spec.version = "3.3.0"
+ spec.version = "4.0.0"
spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"]
spec.email = ["ruby-core@ruby-lang.org"]
spec.summary = %q{SSL/TLS and general-purpose cryptography for Ruby}
@@ -13,7 +13,8 @@ Gem::Specification.new do |spec|
spec.files = []
spec.add_runtime_dependency('jruby-openssl', '~> 0.14')
else
- spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "COPYING"]
+ spec.files = Dir.glob(["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md"], base: File.expand_path("..", __FILE__)) +
+ ["BSDL", "COPYING"]
spec.require_paths = ["lib"]
spec.extensions = ["ext/openssl/extconf.rb"]
end
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 60780790b0..98127fcba0 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -13,71 +13,71 @@
/*
* Data Conversion
*/
-#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \
-VALUE \
-ossl_##name##_ary2sk0(VALUE ary) \
-{ \
- STACK_OF(type) *sk; \
- VALUE val; \
- type *x; \
- int i; \
- \
- Check_Type(ary, T_ARRAY); \
- sk = sk_##type##_new_null(); \
- if (!sk) ossl_raise(eOSSLError, NULL); \
- \
- for (i = 0; i < RARRAY_LEN(ary); i++) { \
- val = rb_ary_entry(ary, i); \
- if (!rb_obj_is_kind_of(val, expected_class)) { \
- sk_##type##_pop_free(sk, type##_free); \
- ossl_raise(eOSSLError, "object in array not" \
- " of class ##type##"); \
- } \
- x = dup(val); /* NEED TO DUP */ \
- sk_##type##_push(sk, x); \
- } \
- return (VALUE)sk; \
-} \
- \
-STACK_OF(type) * \
-ossl_protect_##name##_ary2sk(VALUE ary, int *status) \
-{ \
- return (STACK_OF(type)*)rb_protect( \
- (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \
- ary, \
- status); \
-} \
- \
-STACK_OF(type) * \
-ossl_##name##_ary2sk(VALUE ary) \
-{ \
- STACK_OF(type) *sk; \
- int status = 0; \
- \
- sk = ossl_protect_##name##_ary2sk(ary, &status); \
- if (status) rb_jump_tag(status); \
- \
- return sk; \
+#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup) \
+VALUE \
+ossl_##name##_ary2sk0(VALUE ary) \
+{ \
+ STACK_OF(type) *sk; \
+ VALUE val; \
+ type *x; \
+ int i; \
+ \
+ Check_Type(ary, T_ARRAY); \
+ sk = sk_##type##_new_null(); \
+ if (!sk) ossl_raise(eOSSLError, NULL); \
+ \
+ for (i = 0; i < RARRAY_LEN(ary); i++) { \
+ val = rb_ary_entry(ary, i); \
+ if (!rb_obj_is_kind_of(val, expected_class)) { \
+ sk_##type##_pop_free(sk, type##_free); \
+ ossl_raise(eOSSLError, "object in array not" \
+ " of class ##type##"); \
+ } \
+ x = dup(val); /* NEED TO DUP */ \
+ sk_##type##_push(sk, x); \
+ } \
+ return (VALUE)sk; \
+} \
+ \
+STACK_OF(type) * \
+ossl_protect_##name##_ary2sk(VALUE ary, int *status) \
+{ \
+ return (STACK_OF(type)*)rb_protect( \
+ (VALUE (*)(VALUE))ossl_##name##_ary2sk0, \
+ ary, \
+ status); \
+} \
+ \
+STACK_OF(type) * \
+ossl_##name##_ary2sk(VALUE ary) \
+{ \
+ STACK_OF(type) *sk; \
+ int status = 0; \
+ \
+ sk = ossl_protect_##name##_ary2sk(ary, &status); \
+ if (status) rb_jump_tag(status); \
+ \
+ return sk; \
}
OSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr)
-#define OSSL_IMPL_SK2ARY(name, type) \
-VALUE \
-ossl_##name##_sk2ary(const STACK_OF(type) *sk) \
-{ \
- type *t; \
- int i, num; \
- VALUE ary; \
- \
- RUBY_ASSERT(sk != NULL); \
- num = sk_##type##_num(sk); \
- ary = rb_ary_new_capa(num); \
- \
- for (i=0; i<num; i++) { \
- t = sk_##type##_value(sk, i); \
- rb_ary_push(ary, ossl_##name##_new(t)); \
- } \
- return ary; \
+#define OSSL_IMPL_SK2ARY(name, type) \
+VALUE \
+ossl_##name##_sk2ary(const STACK_OF(type) *sk) \
+{ \
+ type *t; \
+ int i, num; \
+ VALUE ary; \
+ \
+ RUBY_ASSERT(sk != NULL); \
+ num = sk_##type##_num(sk); \
+ ary = rb_ary_new_capa(num); \
+ \
+ for (i=0; i<num; i++) { \
+ t = sk_##type##_value(sk, i); \
+ rb_ary_push(ary, ossl_##name##_new(t)); \
+ } \
+ return ary; \
}
OSSL_IMPL_SK2ARY(x509, X509)
OSSL_IMPL_SK2ARY(x509crl, X509_CRL)
@@ -97,14 +97,14 @@ ossl_str_new(const char *ptr, long len, int *pstate)
str = rb_protect(ossl_str_new_i, len, &state);
if (pstate)
- *pstate = state;
+ *pstate = state;
if (state) {
- if (!pstate)
- rb_set_errinfo(Qnil);
- return Qnil;
+ if (!pstate)
+ rb_set_errinfo(Qnil);
+ return Qnil;
}
if (ptr)
- memcpy(RSTRING_PTR(str), ptr, len);
+ memcpy(RSTRING_PTR(str), ptr, len);
return str;
}
@@ -117,22 +117,22 @@ ossl_buf2str(char *buf, int len)
str = ossl_str_new(buf, len, &state);
OPENSSL_free(buf);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return str;
}
void
-ossl_bin2hex(unsigned char *in, char *out, size_t inlen)
+ossl_bin2hex(const unsigned char *in, char *out, size_t inlen)
{
const char *hex = "0123456789abcdef";
size_t i;
assert(inlen <= LONG_MAX / 2);
for (i = 0; i < inlen; i++) {
- unsigned char p = in[i];
+ unsigned char p = in[i];
- out[i * 2 + 0] = hex[p >> 4];
- out[i * 2 + 1] = hex[p & 0x0f];
+ out[i * 2 + 0] = hex[p >> 4];
+ out[i * 2 + 1] = hex[p & 0x0f];
}
}
@@ -143,14 +143,14 @@ VALUE
ossl_pem_passwd_value(VALUE pass)
{
if (NIL_P(pass))
- return Qnil;
+ return Qnil;
StringValue(pass);
/* PEM_BUFSIZE is currently used as the second argument of pem_password_cb,
* that is +max_len+ of ossl_pem_passwd_cb() */
if (RSTRING_LEN(pass) > PEM_BUFSIZE)
- ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE);
+ ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE);
return pass;
}
@@ -160,7 +160,7 @@ ossl_pem_passwd_cb0(VALUE flag)
{
VALUE pass = rb_yield(flag);
if (NIL_P(pass))
- return Qnil;
+ return Qnil;
StringValue(pass);
return pass;
}
@@ -173,46 +173,46 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)
VALUE rflag, pass = (VALUE)pwd_;
if (RTEST(pass)) {
- /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not
- * work because it does not allow NUL characters and truncates to 1024
- * bytes silently if the input is over 1024 bytes */
- if (RB_TYPE_P(pass, T_STRING)) {
- len = RSTRING_LEN(pass);
- if (len <= max_len) {
- memcpy(buf, RSTRING_PTR(pass), len);
- return (int)len;
- }
- }
- OSSL_Debug("passed data is not valid String???");
- return -1;
+ /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not
+ * work because it does not allow NUL characters and truncates to 1024
+ * bytes silently if the input is over 1024 bytes */
+ if (RB_TYPE_P(pass, T_STRING)) {
+ len = RSTRING_LEN(pass);
+ if (len <= max_len) {
+ memcpy(buf, RSTRING_PTR(pass), len);
+ return (int)len;
+ }
+ }
+ OSSL_Debug("passed data is not valid String???");
+ return -1;
}
if (!rb_block_given_p()) {
- return PEM_def_callback(buf, max_len, flag, NULL);
+ return PEM_def_callback(buf, max_len, flag, NULL);
}
while (1) {
- /*
- * when the flag is nonzero, this password
- * will be used to perform encryption; otherwise it will
- * be used to perform decryption.
- */
- rflag = flag ? Qtrue : Qfalse;
- pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
- if (status) {
- /* ignore an exception raised. */
- rb_set_errinfo(Qnil);
- return -1;
- }
- if (NIL_P(pass))
- return -1;
- len = RSTRING_LEN(pass);
- if (len > max_len) {
- rb_warning("password must not be longer than %d bytes", max_len);
- continue;
- }
- memcpy(buf, RSTRING_PTR(pass), len);
- break;
+ /*
+ * when the flag is nonzero, this password
+ * will be used to perform encryption; otherwise it will
+ * be used to perform decryption.
+ */
+ rflag = flag ? Qtrue : Qfalse;
+ pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
+ if (status) {
+ /* ignore an exception raised. */
+ rb_set_errinfo(Qnil);
+ return -1;
+ }
+ if (NIL_P(pass))
+ return -1;
+ len = RSTRING_LEN(pass);
+ if (len > max_len) {
+ rb_warning("password must not be longer than %d bytes", max_len);
+ continue;
+ }
+ memcpy(buf, RSTRING_PTR(pass), len);
+ break;
}
return (int)len;
}
@@ -247,19 +247,24 @@ VALUE
ossl_to_der_if_possible(VALUE obj)
{
if(rb_respond_to(obj, ossl_s_to_der))
- return ossl_to_der(obj);
+ return ossl_to_der(obj);
return obj;
}
/*
* Errors
*/
+static ID id_i_errors;
+
+static void collect_errors_into(VALUE ary);
+
VALUE
ossl_make_error(VALUE exc, VALUE str)
{
unsigned long e;
const char *data;
int flags;
+ VALUE errors = rb_ary_new();
if (NIL_P(str))
str = rb_str_new(NULL, 0);
@@ -276,10 +281,12 @@ ossl_make_error(VALUE exc, VALUE str)
rb_str_cat_cstr(str, msg ? msg : "(null)");
if (flags & ERR_TXT_STRING && data)
rb_str_catf(str, " (%s)", data);
- ossl_clear_error();
+ collect_errors_into(errors);
}
- return rb_exc_new_str(exc, str);
+ VALUE obj = rb_exc_new_str(exc, str);
+ rb_ivar_set(obj, id_i_errors, errors);
+ return obj;
}
void
@@ -289,24 +296,23 @@ ossl_raise(VALUE exc, const char *fmt, ...)
VALUE err;
if (fmt) {
- va_start(args, fmt);
- err = rb_vsprintf(fmt, args);
- va_end(args);
+ va_start(args, fmt);
+ err = rb_vsprintf(fmt, args);
+ va_end(args);
}
else {
- err = Qnil;
+ err = Qnil;
}
rb_exc_raise(ossl_make_error(exc, err));
}
-void
-ossl_clear_error(void)
+static void
+collect_errors_into(VALUE ary)
{
- if (dOSSL == Qtrue) {
+ if (dOSSL == Qtrue || !NIL_P(ary)) {
unsigned long e;
const char *file, *data, *func, *lib, *reason;
- char append[256] = "";
int line, flags;
#ifdef HAVE_ERR_GET_ERROR_ALL
@@ -318,13 +324,18 @@ ossl_clear_error(void)
lib = ERR_lib_error_string(e);
reason = ERR_reason_error_string(e);
+ VALUE str = rb_sprintf("error:%08lX:%s:%s:%s", e, lib ? lib : "",
+ func ? func : "", reason ? reason : "");
if (flags & ERR_TXT_STRING) {
if (!data)
data = "(null)";
- snprintf(append, sizeof(append), " (%s)", data);
+ rb_str_catf(str, " (%s)", data);
}
- rb_warn("error on stack: error:%08lX:%s:%s:%s%s", e, lib ? lib : "",
- func ? func : "", reason ? reason : "", append);
+
+ if (dOSSL == Qtrue)
+ rb_warn("error on stack: %"PRIsVALUE, str);
+ if (!NIL_P(ary))
+ rb_ary_push(ary, str);
}
}
else {
@@ -332,14 +343,59 @@ ossl_clear_error(void)
}
}
+void
+ossl_clear_error(void)
+{
+ collect_errors_into(Qnil);
+}
+
+/*
+ * call-seq:
+ * ossl_error.detailed_message(**) -> string
+ *
+ * Returns the exception message decorated with the captured \OpenSSL error
+ * queue entries.
+ */
+static VALUE
+osslerror_detailed_message(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str;
+#ifdef HAVE_RB_CALL_SUPER_KW
+ // Ruby >= 3.2
+ if (RTEST(rb_funcall(rb_eException, rb_intern("method_defined?"), 1,
+ ID2SYM(rb_intern("detailed_message")))))
+ str = rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
+ else
+#endif
+ str = rb_funcall(self, rb_intern("message"), 0);
+ VALUE errors = rb_attr_get(self, id_i_errors);
+
+ // OpenSSLError was not created by ossl_make_error()
+ if (!RB_TYPE_P(errors, T_ARRAY))
+ return str;
+
+ str = rb_str_resurrect(str);
+ rb_str_catf(str, "\nOpenSSL error queue reported %ld errors:",
+ RARRAY_LEN(errors));
+ for (long i = 0; i < RARRAY_LEN(errors); i++) {
+ VALUE err = RARRAY_AREF(errors, i);
+ rb_str_catf(str, "\n%"PRIsVALUE, err);
+ }
+ return str;
+}
+
/*
* call-seq:
* OpenSSL.errors -> [String...]
*
- * See any remaining errors held in queue.
+ * Returns any remaining errors held in the \OpenSSL thread-local error queue
+ * and clears the queue. This should normally return an empty array.
+ *
+ * This is intended for debugging Ruby/OpenSSL. If you see any errors here,
+ * it likely indicates a bug in the extension. Please file an issue at
+ * https://github.com/ruby/openssl.
*
- * Any errors you see here are probably due to a bug in Ruby's OpenSSL
- * implementation.
+ * For debugging your program, OpenSSL.debug= may be useful.
*/
static VALUE
ossl_get_errors(VALUE _)
@@ -363,6 +419,8 @@ VALUE dOSSL;
/*
* call-seq:
* OpenSSL.debug -> true | false
+ *
+ * Returns whether Ruby/OpenSSL's debug mode is currently enabled.
*/
static VALUE
ossl_debug_get(VALUE self)
@@ -372,9 +430,9 @@ ossl_debug_get(VALUE self)
/*
* call-seq:
- * OpenSSL.debug = boolean -> boolean
+ * OpenSSL.debug = boolean
*
- * Turns on or off debug mode. With debug mode, all errors added to the OpenSSL
+ * Turns on or off debug mode. With debug mode, all errors added to the \OpenSSL
* error queue will be printed to stderr.
*/
static VALUE
@@ -388,6 +446,8 @@ ossl_debug_set(VALUE self, VALUE val)
/*
* call-seq:
* OpenSSL.fips_mode -> true | false
+ *
+ * Returns whether the FIPS mode is currently enabled.
*/
static VALUE
ossl_fips_mode_get(VALUE self)
@@ -408,10 +468,10 @@ ossl_fips_mode_get(VALUE self)
/*
* call-seq:
- * OpenSSL.fips_mode = boolean -> boolean
+ * OpenSSL.fips_mode = boolean
*
* Turns FIPS mode on or off. Turning on FIPS mode will obviously only have an
- * effect for FIPS-capable installations of the OpenSSL library. Trying to do
+ * effect for FIPS-capable installations of the \OpenSSL library. Trying to do
* so otherwise will result in an error.
*
* === Examples
@@ -434,30 +494,30 @@ ossl_fips_mode_set(VALUE self, VALUE enabled)
return enabled;
#elif defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC)
if (RTEST(enabled)) {
- int mode = FIPS_mode();
- if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
- ossl_raise(eOSSLError, "Turning on FIPS mode failed");
+ int mode = FIPS_mode();
+ if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
+ ossl_raise(eOSSLError, "Turning on FIPS mode failed");
} else {
- if(!FIPS_mode_set(0)) /* turning off twice is OK */
- ossl_raise(eOSSLError, "Turning off FIPS mode failed");
+ if(!FIPS_mode_set(0)) /* turning off twice is OK */
+ ossl_raise(eOSSLError, "Turning off FIPS mode failed");
}
return enabled;
#else
if (RTEST(enabled))
- ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode");
+ ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode");
return enabled;
#endif
}
/*
* call-seq:
- * OpenSSL.fixed_length_secure_compare(string, string) -> boolean
+ * OpenSSL.fixed_length_secure_compare(string, string) -> true or false
*
* Constant time memory comparison for fixed length strings, such as results
- * of HMAC calculations.
+ * of \HMAC calculations.
*
* Returns +true+ if the strings are identical, +false+ if they are of the same
- * length but not identical. If the length is different, +ArgumentError+ is
+ * length but not identical. If the length is different, ArgumentError is
* raised.
*/
static VALUE
@@ -473,13 +533,13 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
}
switch (CRYPTO_memcmp(p1, p2, len1)) {
- case 0: return Qtrue;
- default: return Qfalse;
+ case 0: return Qtrue;
+ default: return Qfalse;
}
}
/*
- * OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the
+ * OpenSSL provides \SSL, TLS and general purpose cryptography. It wraps the
* OpenSSL[https://www.openssl.org/] library.
*
* = Examples
@@ -534,7 +594,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Loading an Encrypted Key
*
- * OpenSSL will prompt you for your password when loading an encrypted key.
+ * \OpenSSL will prompt you for your password when loading an encrypted key.
* If you will not be able to type in the password you may provide it when
* loading the key:
*
@@ -597,7 +657,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* == PBKDF2 Password-based Encryption
*
- * If supported by the underlying OpenSSL version used, Password-based
+ * If supported by the underlying \OpenSSL version used, Password-based
* Encryption should use the features of PKCS5. If not supported or if
* required by legacy applications, the older, less secure methods specified
* in RFC 2898 are also supported (see below).
@@ -656,7 +716,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* decrypted = cipher.update encrypted
* decrypted << cipher.final
*
- * == X509 Certificates
+ * == \X509 Certificates
*
* === Creating a Certificate
*
@@ -693,7 +753,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* extension_factory.create_extension('subjectKeyIdentifier', 'hash')
*
* The list of supported extensions (and in some cases their possible values)
- * can be derived from the "objects.h" file in the OpenSSL source code.
+ * can be derived from the "objects.h" file in the \OpenSSL source code.
*
* === Signing a Certificate
*
@@ -847,23 +907,23 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* io.write csr_cert.to_pem
* end
*
- * == SSL and TLS Connections
+ * == \SSL and TLS Connections
*
- * Using our created key and certificate we can create an SSL or TLS connection.
- * An SSLContext is used to set up an SSL session.
+ * Using our created key and certificate we can create an \SSL or TLS
+ * connection. An OpenSSL::SSL::SSLContext is used to set up an \SSL session.
*
* context = OpenSSL::SSL::SSLContext.new
*
- * === SSL Server
+ * === \SSL Server
*
- * An SSL server requires the certificate and private key to communicate
+ * An \SSL server requires the certificate and private key to communicate
* securely with its clients:
*
* context.cert = cert
* context.key = key
*
- * Then create an SSLServer with a TCP server socket and the context. Use the
- * SSLServer like an ordinary TCP server.
+ * Then create an OpenSSL::SSL::SSLServer with a TCP server socket and the
+ * context. Use the SSLServer like an ordinary TCP server.
*
* require 'socket'
*
@@ -882,14 +942,15 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* ssl_connection.close
* end
*
- * === SSL client
+ * === \SSL client
*
- * An SSL client is created with a TCP socket and the context.
- * SSLSocket#connect must be called to initiate the SSL handshake and start
- * encryption. A key and certificate are not required for the client socket.
+ * An \SSL client is created with a TCP socket and the context.
+ * OpenSSL::SSL::SSLSocket#connect must be called to initiate the \SSL handshake
+ * and start encryption. A key and certificate are not required for the client
+ * socket.
*
- * Note that SSLSocket#close doesn't close the underlying socket by default. Set
- * SSLSocket#sync_close to true if you want.
+ * Note that OpenSSL::SSL::SSLSocket#close doesn't close the underlying socket
+ * by default. Set OpenSSL::SSL::SSLSocket#sync_close to true if you want.
*
* require 'socket'
*
@@ -905,7 +966,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Peer Verification
*
- * An unverified SSL connection does not provide much security. For enhanced
+ * An unverified \SSL connection does not provide much security. For enhanced
* security the client or server can verify the certificate of its peer.
*
* The client can be modified to verify the server's certificate against the
@@ -956,22 +1017,34 @@ Init_openssl(void)
rb_define_singleton_method(mOSSL, "fixed_length_secure_compare", ossl_crypto_fixed_length_secure_compare, 2);
/*
- * Version of OpenSSL the ruby OpenSSL extension was built with
+ * \OpenSSL library version string used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
+ rb_define_const(mOSSL, "OPENSSL_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OPENSSL_VERSION_TEXT)));
/*
- * Version of OpenSSL the ruby OpenSSL extension is running with
+ * \OpenSSL library version string currently used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
+ rb_define_const(
+ mOSSL,
+ "OPENSSL_LIBRARY_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OpenSSL_version(OPENSSL_VERSION)))
+ );
/*
- * Version number of OpenSSL the ruby OpenSSL extension was built with
- * (base 16). The formats are below.
+ * \OpenSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
+ *
+ * The version number is encoded into a single integer value. The number
+ * follows the format:
*
- * [OpenSSL 3] <tt>0xMNN00PP0 (major minor 00 patch 0)</tt>
- * [OpenSSL before 3] <tt>0xMNNFFPPS (major minor fix patch status)</tt>
- * [LibreSSL] <tt>0x20000000 (fixed value)</tt>
+ * [\OpenSSL 3.0.0 or later]
+ * <tt>0xMNN00PP0</tt> (major minor 00 patch 0)
+ * [\OpenSSL 1.1.1 or earlier]
+ * <tt>0xMNNFFPPS</tt> (major minor fix patch status)
+ * [LibreSSL]
+ * <tt>0x20000000</tt> (a fixed value)
*
* See also the man page OPENSSL_VERSION_NUMBER(3).
*/
@@ -979,9 +1052,12 @@ Init_openssl(void)
#if defined(LIBRESSL_VERSION_NUMBER)
/*
- * Version number of LibreSSL the ruby OpenSSL extension was built with
- * (base 16). The format is <tt>0xMNNFF00f (major minor fix 00
- * status)</tt>. This constant is only defined in LibreSSL cases.
+ * LibreSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
+ *
+ * This constant is only defined if the extension was compiled against
+ * LibreSSL. The number follows the format:
+ * <tt>0xMNNFF00f</tt> (major minor fix 00 status).
*
* See also the man page LIBRESSL_VERSION_NUMBER(3).
*/
@@ -989,30 +1065,50 @@ Init_openssl(void)
#endif
/*
- * Boolean indicating whether OpenSSL is FIPS-capable or not
+ * Boolean indicating whether the \OpenSSL library is FIPS-capable or not.
+ * Always <tt>true</tt> for \OpenSSL 3.0 and later.
+ *
+ * This is obsolete and will be removed in the future.
+ * See also OpenSSL.fips_mode.
*/
rb_define_const(mOSSL, "OPENSSL_FIPS",
/* OpenSSL 3 is FIPS-capable even when it is installed without fips option */
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
Qtrue
#elif defined(OPENSSL_FIPS)
- Qtrue
+ Qtrue
#elif defined(OPENSSL_IS_AWSLC) // AWS-LC FIPS can only be enabled during compile time.
- FIPS_mode() ? Qtrue : Qfalse
+ FIPS_mode() ? Qtrue : Qfalse
#else
- Qfalse
+ Qfalse
#endif
- );
+ );
rb_define_module_function(mOSSL, "fips_mode", ossl_fips_mode_get, 0);
rb_define_module_function(mOSSL, "fips_mode=", ossl_fips_mode_set, 1);
rb_global_variable(&eOSSLError);
/*
- * Generic error,
- * common for all classes under OpenSSL module
+ * Generic error class for OpenSSL. All error classes in this library
+ * inherit from this class.
+ *
+ * This class indicates that an error was reported by the underlying
+ * \OpenSSL library.
+ */
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
+ /*
+ * \OpenSSL error queue entries captured at the time the exception was
+ * raised. The same information is printed to stderr if OpenSSL.debug is
+ * set to +true+.
+ *
+ * This is an array of zero or more strings, ordered from the oldest to the
+ * newest. The format of the strings is not stable and may vary across
+ * versions of \OpenSSL or versions of this Ruby extension.
+ *
+ * See also the man page ERR_get_error(3).
*/
- eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_attr(eOSSLError, rb_intern_const("errors"), 1, 0, 0);
+ rb_define_method(eOSSLError, "detailed_message", osslerror_detailed_message, -1);
/*
* Init debug core
@@ -1028,6 +1124,7 @@ Init_openssl(void)
* Get ID of to_der
*/
ossl_s_to_der = rb_intern("to_der");
+ id_i_errors = rb_intern("@errors");
/*
* Init components
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index 9b20829b3f..0b479a7200 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -71,6 +71,11 @@
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
# define OSSL_USE_PROVIDER
+# include <openssl/provider.h>
+#endif
+
+#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+# define OSSL_HAVE_IMMUTABLE_PKEY
#endif
/*
@@ -87,10 +92,10 @@ extern VALUE eOSSLError;
* CheckTypes
*/
#define OSSL_Check_Kind(obj, klass) do {\
- if (!rb_obj_is_kind_of((obj), (klass))) {\
- ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %"PRIsVALUE")",\
- rb_obj_class(obj), (klass));\
- }\
+ if (!rb_obj_is_kind_of((obj), (klass))) {\
+ ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %"PRIsVALUE")",\
+ rb_obj_class(obj), (klass));\
+ }\
} while (0)
/*
@@ -126,7 +131,7 @@ do{\
* Convert binary string to hex string. The caller is responsible for
* ensuring out has (2 * len) bytes of capacity.
*/
-void ossl_bin2hex(unsigned char *in, char *out, size_t len);
+void ossl_bin2hex(const unsigned char *in, char *out, size_t len);
/*
* Our default PEM callback
@@ -169,11 +174,11 @@ VALUE ossl_to_der_if_possible(VALUE);
extern VALUE dOSSL;
#define OSSL_Debug(...) do { \
- if (dOSSL == Qtrue) { \
- fprintf(stderr, "OSSL_DEBUG: "); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
- } \
+ if (dOSSL == Qtrue) { \
+ fprintf(stderr, "OSSL_DEBUG: "); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
+ } \
} while (0)
/*
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index ea3ec2f210..71a87f0463 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -9,63 +9,81 @@
*/
#include "ossl.h"
-static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
- int depth, int yield, long *num_read);
+/********/
+/*
+ * ASN1 module
+ */
+#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
+#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
+#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
+#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
+#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)
+
+#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v))
+#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v))
+#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v))
+#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v))
+#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
+
+VALUE mASN1;
+static VALUE eASN1Error;
+
+VALUE cASN1Data;
+static VALUE cASN1Primitive;
+static VALUE cASN1Constructive;
+
+static VALUE cASN1EndOfContent;
+static VALUE cASN1Boolean; /* BOOLEAN */
+static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
+static VALUE cASN1BitString; /* BIT STRING */
+static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
+static VALUE cASN1NumericString, cASN1PrintableString;
+static VALUE cASN1T61String, cASN1VideotexString;
+static VALUE cASN1IA5String, cASN1GraphicString;
+static VALUE cASN1ISO64String, cASN1GeneralString;
+static VALUE cASN1UniversalString, cASN1BMPString;
+static VALUE cASN1Null; /* NULL */
+static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
+static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
+static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
+
+static VALUE sym_IMPLICIT, sym_EXPLICIT;
+static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
+static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
+static ID id_each;
/*
* DATE conversion
*/
+static VALUE
+time_utc_new(VALUE args)
+{
+ return rb_funcallv(rb_cTime, rb_intern("utc"), 6, (VALUE *)args);
+}
+
+static VALUE
+time_utc_new_rescue(VALUE args, VALUE exc)
+{
+ rb_raise(eASN1Error, "invalid time");
+}
+
VALUE
asn1time_to_time(const ASN1_TIME *time)
{
struct tm tm;
- VALUE argv[6];
- int count;
-
- memset(&tm, 0, sizeof(struct tm));
-
- switch (time->type) {
- case V_ASN1_UTCTIME:
- count = sscanf((const char *)time->data, "%2d%2d%2d%2d%2d%2dZ",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
- &tm.tm_sec);
-
- if (count == 5) {
- tm.tm_sec = 0;
- } else if (count != 6) {
- ossl_raise(rb_eTypeError, "bad UTCTIME format: \"%s\"",
- time->data);
- }
- if (tm.tm_year < 69) {
- tm.tm_year += 2000;
- } else {
- tm.tm_year += 1900;
- }
- break;
- case V_ASN1_GENERALIZEDTIME:
- count = sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
- &tm.tm_sec);
- if (count == 5) {
- tm.tm_sec = 0;
- }
- else if (count != 6) {
- ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format: \"%s\"",
- time->data);
- }
- break;
- default:
- rb_warning("unknown time format");
- return Qnil;
- }
- argv[0] = INT2NUM(tm.tm_year);
- argv[1] = INT2NUM(tm.tm_mon);
- argv[2] = INT2NUM(tm.tm_mday);
- argv[3] = INT2NUM(tm.tm_hour);
- argv[4] = INT2NUM(tm.tm_min);
- argv[5] = INT2NUM(tm.tm_sec);
-
- return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
+ if (!ASN1_TIME_to_tm(time, &tm))
+ ossl_raise(eASN1Error, "ASN1_TIME_to_tm");
+
+ VALUE args[] = {
+ INT2NUM(tm.tm_year + 1900),
+ INT2NUM(tm.tm_mon + 1),
+ INT2NUM(tm.tm_mday),
+ INT2NUM(tm.tm_hour),
+ INT2NUM(tm.tm_min),
+ INT2NUM(tm.tm_sec),
+ };
+ return rb_rescue2(time_utc_new, (VALUE)args, time_utc_new_rescue, Qnil,
+ rb_eArgError, 0);
}
static VALUE
@@ -80,13 +98,13 @@ ossl_time_split(VALUE time, time_t *sec, int *days)
VALUE num = rb_Integer(time);
if (FIXNUM_P(num)) {
- time_t t = FIX2LONG(num);
- *sec = t % 86400;
- *days = rb_long2int(t / 86400);
+ time_t t = FIX2LONG(num);
+ *sec = t % 86400;
+ *days = rb_long2int(t / 86400);
}
else {
- *days = NUM2INT(rb_funcall(num, rb_intern("/"), 1, INT2FIX(86400)));
- *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400)));
+ *days = NUM2INT(rb_funcall(num, rb_intern("/"), 1, INT2FIX(86400)));
+ *sec = NUM2TIMET(rb_funcall(num, rb_intern("%"), 1, INT2FIX(86400)));
}
}
@@ -96,7 +114,8 @@ ossl_time_split(VALUE time, time_t *sec, int *days)
VALUE
asn1str_to_str(const ASN1_STRING *str)
{
- return rb_str_new((const char *)str->data, str->length);
+ return rb_str_new((const char *)ASN1_STRING_get0_data(str),
+ ASN1_STRING_length(str));
}
/*
@@ -109,16 +128,15 @@ asn1integer_to_num(const ASN1_INTEGER *ai)
VALUE num;
if (!ai) {
- ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
+ ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
}
- if (ai->type == V_ASN1_ENUMERATED)
- /* const_cast: workaround for old OpenSSL */
- bn = ASN1_ENUMERATED_to_BN((ASN1_ENUMERATED *)ai, NULL);
+ if (ASN1_STRING_type(ai) == V_ASN1_ENUMERATED)
+ bn = ASN1_ENUMERATED_to_BN(ai, NULL);
else
- bn = ASN1_INTEGER_to_BN(ai, NULL);
+ bn = ASN1_INTEGER_to_BN(ai, NULL);
if (!bn)
- ossl_raise(eOSSLError, NULL);
+ ossl_raise(eOSSLError, NULL);
num = ossl_bn_new(bn);
BN_free(bn);
@@ -131,12 +149,12 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
BIGNUM *bn;
if (NIL_P(obj))
- ossl_raise(rb_eTypeError, "Can't convert nil into Integer");
+ ossl_raise(rb_eTypeError, "Can't convert nil into Integer");
bn = GetBNPtr(obj);
if (!(ai = BN_to_ASN1_INTEGER(bn, ai)))
- ossl_raise(eOSSLError, NULL);
+ ossl_raise(eOSSLError, NULL);
return ai;
}
@@ -147,43 +165,47 @@ asn1integer_to_num_i(VALUE arg)
return asn1integer_to_num((ASN1_INTEGER *)arg);
}
-/********/
/*
- * ASN1 module
+ * ASN1_OBJECT conversions
*/
-#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
-#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
-#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
-#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
-#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)
-
-#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
-
-VALUE mASN1;
-VALUE eASN1Error;
+VALUE
+ossl_asn1obj_to_string_oid(const ASN1_OBJECT *a1obj)
+{
+ VALUE str;
+ int len;
-VALUE cASN1Data;
-static VALUE cASN1Primitive;
-static VALUE cASN1Constructive;
+ str = rb_usascii_str_new(NULL, 127);
+ len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
+ if (len <= 0 || len == INT_MAX)
+ ossl_raise(eOSSLError, "OBJ_obj2txt");
+ if (len > RSTRING_LEN(str)) {
+ /* +1 is for the \0 terminator added by OBJ_obj2txt() */
+ rb_str_resize(str, len + 1);
+ len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
+ if (len <= 0)
+ ossl_raise(eOSSLError, "OBJ_obj2txt");
+ }
+ rb_str_set_len(str, len);
+ return str;
+}
-static VALUE cASN1EndOfContent;
-static VALUE cASN1Boolean; /* BOOLEAN */
-static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
-static VALUE cASN1BitString; /* BIT STRING */
-static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
-static VALUE cASN1NumericString, cASN1PrintableString;
-static VALUE cASN1T61String, cASN1VideotexString;
-static VALUE cASN1IA5String, cASN1GraphicString;
-static VALUE cASN1ISO64String, cASN1GeneralString;
-static VALUE cASN1UniversalString, cASN1BMPString;
-static VALUE cASN1Null; /* NULL */
-static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
-static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
-static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
+VALUE
+ossl_asn1obj_to_string(const ASN1_OBJECT *obj)
+{
+ int nid = OBJ_obj2nid(obj);
+ if (nid != NID_undef)
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
+ return ossl_asn1obj_to_string_oid(obj);
+}
-static VALUE sym_IMPLICIT, sym_EXPLICIT;
-static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
-static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
+VALUE
+ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj)
+{
+ int nid = OBJ_obj2nid(obj);
+ if (nid != NID_undef)
+ return rb_str_new_cstr(OBJ_nid2ln(nid));
+ return ossl_asn1obj_to_string_oid(obj);
+}
/*
* Ruby to ASN1 converters
@@ -192,9 +214,9 @@ static ASN1_BOOLEAN
obj_to_asn1bool(VALUE obj)
{
if (NIL_P(obj))
- ossl_raise(rb_eTypeError, "Can't convert nil into Boolean");
+ ossl_raise(rb_eTypeError, "Can't convert nil into Boolean");
- return RTEST(obj) ? 0xff : 0x0;
+ return RTEST(obj) ? 0xff : 0x0;
}
static ASN1_INTEGER*
@@ -209,11 +231,11 @@ obj_to_asn1bstr(VALUE obj, long unused_bits)
ASN1_BIT_STRING *bstr;
if (unused_bits < 0 || unused_bits > 7)
- ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\
- "the range 0 to 7");
+ ossl_raise(eASN1Error, "unused_bits for a bitstring value must be in "\
+ "the range 0 to 7");
StringValue(obj);
if(!(bstr = ASN1_BIT_STRING_new()))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ASN1_BIT_STRING_set(bstr, (unsigned char *)RSTRING_PTR(obj), RSTRING_LENINT(obj));
bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits;
@@ -228,7 +250,7 @@ obj_to_asn1str(VALUE obj)
StringValue(obj);
if(!(str = ASN1_STRING_new()))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj));
return str;
@@ -240,15 +262,15 @@ obj_to_asn1null(VALUE obj)
ASN1_NULL *null;
if(!NIL_P(obj))
- ossl_raise(eASN1Error, "nil expected");
+ ossl_raise(eASN1Error, "nil expected");
if(!(null = ASN1_NULL_new()))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return null;
}
-static ASN1_OBJECT*
-obj_to_asn1obj(VALUE obj)
+ASN1_OBJECT *
+ossl_to_asn1obj(VALUE obj)
{
ASN1_OBJECT *a1obj;
@@ -270,7 +292,7 @@ obj_to_asn1utime(VALUE time)
ossl_time_split(time, &sec, &off_days);
if (!(t = ASN1_UTCTIME_adj(NULL, sec, off_days, 0)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return t;
}
@@ -285,7 +307,7 @@ obj_to_asn1gtime(VALUE time)
ossl_time_split(time, &sec, &off_days);
if (!(t = ASN1_GENERALIZEDTIME_adj(NULL, sec, off_days, 0)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return t;
}
@@ -298,7 +320,7 @@ obj_to_asn1derstr(VALUE obj)
str = ossl_to_der(obj);
if(!(a1str = ASN1_STRING_new()))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str));
return a1str;
@@ -313,9 +335,9 @@ decode_bool(unsigned char* der, long length)
const unsigned char *p = der;
if (length != 3)
- ossl_raise(eASN1Error, "invalid length for BOOLEAN");
+ ossl_raise(eASN1Error, "invalid length for BOOLEAN");
if (p[0] != 1 || p[1] != 1)
- ossl_raise(eASN1Error, "invalid BOOLEAN");
+ ossl_raise(eASN1Error, "invalid BOOLEAN");
return p[2] ? Qtrue : Qfalse;
}
@@ -330,9 +352,9 @@ decode_int(unsigned char* der, long length)
p = der;
if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1integer_to_num_i,
- (VALUE)ai, &status);
+ (VALUE)ai, &status);
ASN1_INTEGER_free(ai);
if(status) rb_jump_tag(status);
@@ -349,11 +371,11 @@ decode_bstr(unsigned char* der, long length, long *unused_bits)
p = der;
if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
len = bstr->length;
*unused_bits = 0;
if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT)
- *unused_bits = bstr->flags & 0x07;
+ *unused_bits = bstr->flags & 0x07;
ret = rb_str_new((const char *)bstr->data, len);
ASN1_BIT_STRING_free(bstr);
@@ -370,9 +392,9 @@ decode_enum(unsigned char* der, long length)
p = der;
if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1integer_to_num_i,
- (VALUE)ai, &status);
+ (VALUE)ai, &status);
ASN1_ENUMERATED_free(ai);
if(status) rb_jump_tag(status);
@@ -387,38 +409,33 @@ decode_null(unsigned char* der, long length)
p = der;
if(!(null = d2i_ASN1_NULL(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ASN1_NULL_free(null);
return Qnil;
}
+VALUE
+asn1obj_to_string_i(VALUE arg)
+{
+ return ossl_asn1obj_to_string((const ASN1_OBJECT *)arg);
+}
+
static VALUE
decode_obj(unsigned char* der, long length)
{
ASN1_OBJECT *obj;
const unsigned char *p;
VALUE ret;
- int nid;
- BIO *bio;
+ int state;
p = der;
- if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
- if((nid = OBJ_obj2nid(obj)) != NID_undef){
- ASN1_OBJECT_free(obj);
- ret = rb_str_new2(OBJ_nid2sn(nid));
- }
- else{
- if(!(bio = BIO_new(BIO_s_mem()))){
- ASN1_OBJECT_free(obj);
- ossl_raise(eASN1Error, NULL);
- }
- i2a_ASN1_OBJECT(bio, obj);
- ASN1_OBJECT_free(obj);
- ret = ossl_membio2str(bio);
- }
-
+ if (!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
+ ossl_raise(eASN1Error, "d2i_ASN1_OBJECT");
+ ret = rb_protect(asn1obj_to_string_i, (VALUE)obj, &state);
+ ASN1_OBJECT_free(obj);
+ if (state)
+ rb_jump_tag(state);
return ret;
}
@@ -432,9 +449,9 @@ decode_time(unsigned char* der, long length)
p = der;
if(!(time = d2i_ASN1_TIME(NULL, &p, length)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
ret = rb_protect(asn1time_to_time_i,
- (VALUE)time, &status);
+ (VALUE)time, &status);
ASN1_TIME_free(time);
if(status) rb_jump_tag(status);
@@ -445,7 +462,7 @@ static VALUE
decode_eoc(unsigned char *der, long length)
{
if (length != 2 || !(der[0] == 0x00 && der[1] == 0x00))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return rb_str_new("", 0);
}
@@ -510,62 +527,62 @@ ossl_asn1_get_asn1type(VALUE obj)
tag = ossl_asn1_default_tag(obj);
value = ossl_asn1_get_value(obj);
switch(tag){
- case V_ASN1_BOOLEAN:
- ptr = (void*)(VALUE)obj_to_asn1bool(value);
- free_func = NULL;
- break;
- case V_ASN1_INTEGER: /* FALLTHROUGH */
- case V_ASN1_ENUMERATED:
- ptr = obj_to_asn1int(value);
- free_func = (free_func_type *)ASN1_INTEGER_free;
- break;
- case V_ASN1_BIT_STRING:
+ case V_ASN1_BOOLEAN:
+ ptr = (void*)(VALUE)obj_to_asn1bool(value);
+ free_func = NULL;
+ break;
+ case V_ASN1_INTEGER: /* FALLTHROUGH */
+ case V_ASN1_ENUMERATED:
+ ptr = obj_to_asn1int(value);
+ free_func = (free_func_type *)ASN1_INTEGER_free;
+ break;
+ case V_ASN1_BIT_STRING:
rflag = rb_attr_get(obj, sivUNUSED_BITS);
- ptr = obj_to_asn1bstr(value, NUM2INT(rflag));
- free_func = (free_func_type *)ASN1_BIT_STRING_free;
- break;
- case V_ASN1_NULL:
- ptr = obj_to_asn1null(value);
- free_func = (free_func_type *)ASN1_NULL_free;
- break;
- case V_ASN1_OCTET_STRING: /* FALLTHROUGH */
- case V_ASN1_UTF8STRING: /* FALLTHROUGH */
- case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */
- case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */
- case V_ASN1_T61STRING: /* FALLTHROUGH */
- case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */
- case V_ASN1_IA5STRING: /* FALLTHROUGH */
- case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */
- case V_ASN1_ISO64STRING: /* FALLTHROUGH */
- case V_ASN1_GENERALSTRING: /* FALLTHROUGH */
- case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */
- case V_ASN1_BMPSTRING:
- ptr = obj_to_asn1str(value);
- free_func = (free_func_type *)ASN1_STRING_free;
- break;
- case V_ASN1_OBJECT:
- ptr = obj_to_asn1obj(value);
- free_func = (free_func_type *)ASN1_OBJECT_free;
- break;
- case V_ASN1_UTCTIME:
- ptr = obj_to_asn1utime(value);
- free_func = (free_func_type *)ASN1_TIME_free;
- break;
- case V_ASN1_GENERALIZEDTIME:
- ptr = obj_to_asn1gtime(value);
- free_func = (free_func_type *)ASN1_TIME_free;
- break;
- case V_ASN1_SET: /* FALLTHROUGH */
- case V_ASN1_SEQUENCE:
- ptr = obj_to_asn1derstr(obj);
- free_func = (free_func_type *)ASN1_STRING_free;
- break;
- default:
- ossl_raise(eASN1Error, "unsupported ASN.1 type");
+ ptr = obj_to_asn1bstr(value, NUM2INT(rflag));
+ free_func = (free_func_type *)ASN1_BIT_STRING_free;
+ break;
+ case V_ASN1_NULL:
+ ptr = obj_to_asn1null(value);
+ free_func = (free_func_type *)ASN1_NULL_free;
+ break;
+ case V_ASN1_OCTET_STRING: /* FALLTHROUGH */
+ case V_ASN1_UTF8STRING: /* FALLTHROUGH */
+ case V_ASN1_NUMERICSTRING: /* FALLTHROUGH */
+ case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */
+ case V_ASN1_T61STRING: /* FALLTHROUGH */
+ case V_ASN1_VIDEOTEXSTRING: /* FALLTHROUGH */
+ case V_ASN1_IA5STRING: /* FALLTHROUGH */
+ case V_ASN1_GRAPHICSTRING: /* FALLTHROUGH */
+ case V_ASN1_ISO64STRING: /* FALLTHROUGH */
+ case V_ASN1_GENERALSTRING: /* FALLTHROUGH */
+ case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */
+ case V_ASN1_BMPSTRING:
+ ptr = obj_to_asn1str(value);
+ free_func = (free_func_type *)ASN1_STRING_free;
+ break;
+ case V_ASN1_OBJECT:
+ ptr = ossl_to_asn1obj(value);
+ free_func = (free_func_type *)ASN1_OBJECT_free;
+ break;
+ case V_ASN1_UTCTIME:
+ ptr = obj_to_asn1utime(value);
+ free_func = (free_func_type *)ASN1_TIME_free;
+ break;
+ case V_ASN1_GENERALIZEDTIME:
+ ptr = obj_to_asn1gtime(value);
+ free_func = (free_func_type *)ASN1_TIME_free;
+ break;
+ case V_ASN1_SET: /* FALLTHROUGH */
+ case V_ASN1_SEQUENCE:
+ ptr = obj_to_asn1derstr(obj);
+ free_func = (free_func_type *)ASN1_STRING_free;
+ break;
+ default:
+ ossl_raise(eASN1Error, "unsupported ASN.1 type");
}
if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){
- if(free_func) free_func(ptr);
- ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
+ if(free_func) free_func(ptr);
+ ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
}
memset(ret, 0, sizeof(ASN1_TYPE));
ASN1_TYPE_set(ret, tag, ptr);
@@ -580,10 +597,10 @@ ossl_asn1_default_tag(VALUE obj)
tmp_class = CLASS_OF(obj);
while (!NIL_P(tmp_class)) {
- tag = rb_hash_lookup(class_tag_map, tmp_class);
- if (tag != Qnil)
- return NUM2INT(tag);
- tmp_class = rb_class_superclass(tmp_class);
+ tag = rb_hash_lookup(class_tag_map, tmp_class);
+ if (tag != Qnil)
+ return NUM2INT(tag);
+ tmp_class = rb_class_superclass(tmp_class);
}
return -1;
@@ -596,7 +613,7 @@ ossl_asn1_tag(VALUE obj)
tag = ossl_asn1_get_tag(obj);
if(NIL_P(tag))
- ossl_raise(eASN1Error, "tag number not specified");
+ ossl_raise(eASN1Error, "tag number not specified");
return NUM2INT(tag);
}
@@ -608,28 +625,57 @@ ossl_asn1_tag_class(VALUE obj)
s = ossl_asn1_get_tag_class(obj);
if (NIL_P(s) || s == sym_UNIVERSAL)
- return V_ASN1_UNIVERSAL;
+ return V_ASN1_UNIVERSAL;
else if (s == sym_APPLICATION)
- return V_ASN1_APPLICATION;
+ return V_ASN1_APPLICATION;
else if (s == sym_CONTEXT_SPECIFIC)
- return V_ASN1_CONTEXT_SPECIFIC;
+ return V_ASN1_CONTEXT_SPECIFIC;
else if (s == sym_PRIVATE)
- return V_ASN1_PRIVATE;
+ return V_ASN1_PRIVATE;
else
- ossl_raise(eASN1Error, "invalid tag class");
+ ossl_raise(eASN1Error, "invalid tag class");
}
static VALUE
ossl_asn1_class2sym(int tc)
{
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
- return sym_PRIVATE;
+ return sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- return sym_CONTEXT_SPECIFIC;
+ return sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- return sym_APPLICATION;
+ return sym_APPLICATION;
else
- return sym_UNIVERSAL;
+ return sym_UNIVERSAL;
+}
+
+/*
+ * call-seq:
+ * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
+ *
+ * _value_: Please have a look at Constructive and Primitive to see how Ruby
+ * types are mapped to ASN.1 types and vice versa.
+ *
+ * _tag_: An Integer indicating the tag number.
+ *
+ * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
+ * possible values.
+ *
+ * == Example
+ * asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
+ * tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
+ */
+static VALUE
+ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
+{
+ if(!SYMBOL_P(tag_class))
+ ossl_raise(eASN1Error, "invalid tag class");
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+
+ return self;
}
static VALUE
@@ -645,35 +691,35 @@ to_der_internal(VALUE self, int constructed, int indef_len, VALUE body)
body_length = RSTRING_LENINT(body);
if (ossl_asn1_get_tagging(self) == sym_EXPLICIT) {
- int inner_length, e_encoding = indef_len ? 2 : 1;
-
- if (default_tag_number == -1)
- ossl_raise(eASN1Error, "explicit tagging of unknown tag");
-
- inner_length = ASN1_object_size(encoding, body_length, default_tag_number);
- total_length = ASN1_object_size(e_encoding, inner_length, tag_number);
- str = rb_str_new(NULL, total_length);
- p = (unsigned char *)RSTRING_PTR(str);
- /* Put explicit tag */
- ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class);
- /* Append inner object */
- ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL);
- memcpy(p, RSTRING_PTR(body), body_length);
- p += body_length;
- if (indef_len) {
- ASN1_put_eoc(&p); /* For inner object */
- ASN1_put_eoc(&p); /* For wrapper object */
- }
+ int inner_length, e_encoding = indef_len ? 2 : 1;
+
+ if (default_tag_number == -1)
+ ossl_raise(eASN1Error, "explicit tagging of unknown tag");
+
+ inner_length = ASN1_object_size(encoding, body_length, default_tag_number);
+ total_length = ASN1_object_size(e_encoding, inner_length, tag_number);
+ str = rb_str_new(NULL, total_length);
+ p = (unsigned char *)RSTRING_PTR(str);
+ /* Put explicit tag */
+ ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class);
+ /* Append inner object */
+ ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL);
+ memcpy(p, RSTRING_PTR(body), body_length);
+ p += body_length;
+ if (indef_len) {
+ ASN1_put_eoc(&p); /* For inner object */
+ ASN1_put_eoc(&p); /* For wrapper object */
+ }
}
else {
- total_length = ASN1_object_size(encoding, body_length, tag_number);
- str = rb_str_new(NULL, total_length);
- p = (unsigned char *)RSTRING_PTR(str);
- ASN1_put_object(&p, encoding, body_length, tag_number, tag_class);
- memcpy(p, RSTRING_PTR(body), body_length);
- p += body_length;
- if (indef_len)
- ASN1_put_eoc(&p);
+ total_length = ASN1_object_size(encoding, body_length, tag_number);
+ str = rb_str_new(NULL, total_length);
+ p = (unsigned char *)RSTRING_PTR(str);
+ ASN1_put_object(&p, encoding, body_length, tag_number, tag_class);
+ memcpy(p, RSTRING_PTR(body), body_length);
+ p += body_length;
+ if (indef_len)
+ ASN1_put_eoc(&p);
}
assert(p - (unsigned char *)RSTRING_PTR(str) == total_length);
return str;
@@ -696,18 +742,22 @@ ossl_asn1data_to_der(VALUE self)
VALUE value = ossl_asn1_get_value(self);
if (rb_obj_is_kind_of(value, rb_cArray))
- return ossl_asn1cons_to_der(self);
+ return ossl_asn1cons_to_der(self);
else {
- if (RTEST(ossl_asn1_get_indefinite_length(self)))
- ossl_raise(eASN1Error, "indefinite length form cannot be used " \
- "with primitive encoding");
- return ossl_asn1prim_to_der(self);
+ if (RTEST(ossl_asn1_get_indefinite_length(self)))
+ ossl_raise(eASN1Error, "indefinite length form cannot be used " \
+ "with primitive encoding");
+ return ossl_asn1prim_to_der(self);
}
}
+static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);
+static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
+ int depth, int yield, long *num_read);
+
static VALUE
int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
- VALUE tc, long *num_read)
+ VALUE tc, long *num_read)
{
VALUE value, asn1data;
unsigned char *p;
@@ -716,63 +766,64 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
p = *pp;
if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) {
- switch(tag){
- case V_ASN1_EOC:
- value = decode_eoc(p, hlen+length);
- break;
- case V_ASN1_BOOLEAN:
- value = decode_bool(p, hlen+length);
- break;
- case V_ASN1_INTEGER:
- value = decode_int(p, hlen+length);
- break;
- case V_ASN1_BIT_STRING:
- value = decode_bstr(p, hlen+length, &flag);
- break;
- case V_ASN1_NULL:
- value = decode_null(p, hlen+length);
- break;
- case V_ASN1_ENUMERATED:
- value = decode_enum(p, hlen+length);
- break;
- case V_ASN1_OBJECT:
- value = decode_obj(p, hlen+length);
- break;
- case V_ASN1_UTCTIME: /* FALLTHROUGH */
- case V_ASN1_GENERALIZEDTIME:
- value = decode_time(p, hlen+length);
- break;
- default:
- /* use original value */
- p += hlen;
- value = rb_str_new((const char *)p, length);
- break;
- }
+ switch(tag){
+ case V_ASN1_EOC:
+ value = decode_eoc(p, hlen+length);
+ break;
+ case V_ASN1_BOOLEAN:
+ value = decode_bool(p, hlen+length);
+ break;
+ case V_ASN1_INTEGER:
+ value = decode_int(p, hlen+length);
+ break;
+ case V_ASN1_BIT_STRING:
+ value = decode_bstr(p, hlen+length, &flag);
+ break;
+ case V_ASN1_NULL:
+ value = decode_null(p, hlen+length);
+ break;
+ case V_ASN1_ENUMERATED:
+ value = decode_enum(p, hlen+length);
+ break;
+ case V_ASN1_OBJECT:
+ value = decode_obj(p, hlen+length);
+ break;
+ case V_ASN1_UTCTIME: /* FALLTHROUGH */
+ case V_ASN1_GENERALIZEDTIME:
+ value = decode_time(p, hlen+length);
+ break;
+ default:
+ /* use original value */
+ p += hlen;
+ value = rb_str_new((const char *)p, length);
+ break;
+ }
}
else {
- p += hlen;
- value = rb_str_new((const char *)p, length);
+ p += hlen;
+ value = rb_str_new((const char *)p, length);
}
*pp += hlen + length;
*num_read = hlen + length;
if (tc == sym_UNIVERSAL &&
- tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
- VALUE klass = *ossl_asn1_info[tag].klass;
- if (tag == V_ASN1_EOC)
- asn1data = rb_funcall(cASN1EndOfContent, rb_intern("new"), 0);
- else {
- VALUE args[4] = { value, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(klass, rb_intern("new"), 4, args);
- }
- if(tag == V_ASN1_BIT_STRING){
- rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
- }
+ tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
+ VALUE klass = *ossl_asn1_info[tag].klass;
+ VALUE args[4];
+ args[0] = value;
+ args[1] = INT2NUM(tag);
+ args[2] = Qnil;
+ args[3] = tc;
+ asn1data = rb_obj_alloc(klass);
+ ossl_asn1_initialize(4, args, asn1data);
+ if(tag == V_ASN1_BIT_STRING){
+ rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
+ }
}
else {
- VALUE args[3] = { value, INT2NUM(tag), tc };
- asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
+ asn1data = rb_obj_alloc(cASN1Data);
+ ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);
}
return asn1data;
@@ -780,8 +831,8 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
static VALUE
int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
- long *offset, int depth, int yield, int j,
- int tag, VALUE tc, long *num_read)
+ long *offset, int depth, int yield, int j,
+ int tag, VALUE tc, long *num_read)
{
VALUE value, asn1data, ary;
int indefinite;
@@ -792,40 +843,42 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
available_len = indefinite ? max_len : length;
while (available_len > 0) {
- long inner_read = 0;
- value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);
- *num_read += inner_read;
- available_len -= inner_read;
-
- if (indefinite &&
- ossl_asn1_tag(value) == V_ASN1_EOC &&
- ossl_asn1_get_tag_class(value) == sym_UNIVERSAL) {
- break;
- }
- rb_ary_push(ary, value);
+ long inner_read = 0;
+ value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);
+ *num_read += inner_read;
+ available_len -= inner_read;
+
+ if (indefinite) {
+ if (ossl_asn1_tag(value) == V_ASN1_EOC &&
+ ossl_asn1_get_tag_class(value) == sym_UNIVERSAL)
+ break;
+ if (available_len == 0)
+ ossl_raise(eASN1Error, "EOC missing in indefinite length encoding");
+ }
+ rb_ary_push(ary, value);
}
if (tc == sym_UNIVERSAL) {
- if (tag == V_ASN1_SEQUENCE) {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Sequence, rb_intern("new"), 4, args);
- } else if (tag == V_ASN1_SET) {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Set, rb_intern("new"), 4, args);
- } else {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Constructive, rb_intern("new"), 4, args);
- }
+ VALUE args[4];
+ if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)
+ asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass);
+ else
+ asn1data = rb_obj_alloc(cASN1Constructive);
+ args[0] = ary;
+ args[1] = INT2NUM(tag);
+ args[2] = Qnil;
+ args[3] = tc;
+ ossl_asn1_initialize(4, args, asn1data);
}
else {
- VALUE args[3] = {ary, INT2NUM(tag), tc};
- asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
+ asn1data = rb_obj_alloc(cASN1Data);
+ ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);
}
if (indefinite)
- ossl_asn1_set_indefinite_length(asn1data, Qtrue);
+ ossl_asn1_set_indefinite_length(asn1data, Qtrue);
else
- ossl_asn1_set_indefinite_length(asn1data, Qfalse);
+ ossl_asn1_set_indefinite_length(asn1data, Qfalse);
*offset = off;
return asn1data;
@@ -833,7 +886,7 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
static VALUE
ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
- int yield, long *num_read)
+ int yield, long *num_read)
{
unsigned char *start, *p;
const unsigned char *p0;
@@ -849,46 +902,46 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
if(j & 0x80) ossl_raise(eASN1Error, NULL);
if(len > length) ossl_raise(eASN1Error, "value is too short");
if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
- tag_class = sym_PRIVATE;
+ tag_class = sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- tag_class = sym_CONTEXT_SPECIFIC;
+ tag_class = sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- tag_class = sym_APPLICATION;
+ tag_class = sym_APPLICATION;
else
- tag_class = sym_UNIVERSAL;
+ tag_class = sym_UNIVERSAL;
hlen = p - start;
if(yield) {
- VALUE arg = rb_ary_new();
- rb_ary_push(arg, LONG2NUM(depth));
- rb_ary_push(arg, LONG2NUM(*offset));
- rb_ary_push(arg, LONG2NUM(hlen));
- rb_ary_push(arg, LONG2NUM(len));
- rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
- rb_ary_push(arg, ossl_asn1_class2sym(tc));
- rb_ary_push(arg, INT2NUM(tag));
- rb_yield(arg);
+ VALUE arg = rb_ary_new();
+ rb_ary_push(arg, LONG2NUM(depth));
+ rb_ary_push(arg, LONG2NUM(*offset));
+ rb_ary_push(arg, LONG2NUM(hlen));
+ rb_ary_push(arg, LONG2NUM(len));
+ rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
+ rb_ary_push(arg, ossl_asn1_class2sym(tc));
+ rb_ary_push(arg, INT2NUM(tag));
+ rb_yield(arg);
}
if(j & V_ASN1_CONSTRUCTED) {
- *pp += hlen;
- off += hlen;
- asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);
- inner_read += hlen;
+ *pp += hlen;
+ off += hlen;
+ asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);
+ inner_read += hlen;
}
else {
- if ((j & 0x01) && (len == 0))
- ossl_raise(eASN1Error, "indefinite length for primitive value");
- asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);
- off += hlen + len;
+ if ((j & 0x01) && (len == 0))
+ ossl_raise(eASN1Error, "indefinite length for primitive value");
+ asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);
+ off += hlen + len;
}
if (num_read)
- *num_read = inner_read;
+ *num_read = inner_read;
if (len != 0 && inner_read != hlen + len) {
- ossl_raise(eASN1Error,
- "Type mismatch. Bytes read: %ld Bytes available: %ld",
- inner_read, hlen + len);
+ ossl_raise(eASN1Error,
+ "Type mismatch. Bytes read: %ld Bytes available: %ld",
+ inner_read, hlen + len);
}
*offset = off;
@@ -899,9 +952,9 @@ static void
int_ossl_decode_sanity_check(long len, long read, long offset)
{
if (len != 0 && (read != len || offset != len)) {
- ossl_raise(eASN1Error,
- "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld",
- read, len, offset);
+ ossl_raise(eASN1Error,
+ "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld",
+ read, len, offset);
}
}
@@ -1001,17 +1054,94 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
tmp_len = len;
ary = rb_ary_new();
while (tmp_len > 0) {
- long tmp_read = 0;
- val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
- rb_ary_push(ary, val);
- read += tmp_read;
- tmp_len -= tmp_read;
+ long tmp_read = 0;
+ val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
+ rb_ary_push(ary, val);
+ read += tmp_read;
+ tmp_len -= tmp_read;
}
RB_GC_GUARD(tmp);
int_ossl_decode_sanity_check(len, read, offset);
return ary;
}
+/*
+ * call-seq:
+ * OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
+ *
+ * _value_: is mandatory.
+ *
+ * _tag_: optional, may be specified for tagged values. If no _tag_ is
+ * specified, the UNIVERSAL tag corresponding to the Primitive sub-class
+ * is used by default.
+ *
+ * _tagging_: may be used as an encoding hint to encode a value either
+ * explicitly or implicitly, see ASN1 for possible values.
+ *
+ * _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
+ * +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
+ * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
+ * cf. ASN1.
+ *
+ * == Example
+ * int = OpenSSL::ASN1::Integer.new(42)
+ * zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
+ * private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
+ */
+static VALUE
+ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
+{
+ VALUE value, tag, tagging, tag_class;
+ int default_tag;
+
+ rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
+ default_tag = ossl_asn1_default_tag(self);
+
+ if (default_tag == -1 || argc > 1) {
+ if(NIL_P(tag))
+ ossl_raise(eASN1Error, "must specify tag number");
+ if(!NIL_P(tagging) && !SYMBOL_P(tagging))
+ ossl_raise(eASN1Error, "invalid tagging method");
+ if(NIL_P(tag_class)) {
+ if (NIL_P(tagging))
+ tag_class = sym_UNIVERSAL;
+ else
+ tag_class = sym_CONTEXT_SPECIFIC;
+ }
+ if(!SYMBOL_P(tag_class))
+ ossl_raise(eASN1Error, "invalid tag class");
+ }
+ else{
+ tag = INT2NUM(default_tag);
+ tagging = Qnil;
+ tag_class = sym_UNIVERSAL;
+ }
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tagging(self, tagging);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+ if (default_tag == V_ASN1_BIT_STRING)
+ rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0));
+
+ return self;
+}
+
+static VALUE
+ossl_asn1eoc_initialize(VALUE self) {
+ VALUE tag, tagging, tag_class, value;
+ tag = INT2FIX(0);
+ tagging = Qnil;
+ tag_class = sym_UNIVERSAL;
+ value = rb_str_new("", 0);
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tagging(self, tagging);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+ return self;
+}
+
static VALUE
ossl_asn1eoc_to_der(VALUE self)
{
@@ -1034,20 +1164,20 @@ ossl_asn1prim_to_der(VALUE self)
VALUE str;
if (ossl_asn1_default_tag(self) == -1) {
- str = ossl_asn1_get_value(self);
- return to_der_internal(self, 0, 0, StringValue(str));
+ str = ossl_asn1_get_value(self);
+ return to_der_internal(self, 0, 0, StringValue(str));
}
asn1 = ossl_asn1_get_asn1type(self);
alllen = i2d_ASN1_TYPE(asn1, NULL);
if (alllen < 0) {
- ASN1_TYPE_free(asn1);
- ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
+ ASN1_TYPE_free(asn1);
+ ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
}
str = ossl_str_new(NULL, alllen, &state);
if (state) {
- ASN1_TYPE_free(asn1);
- rb_jump_tag(state);
+ ASN1_TYPE_free(asn1);
+ rb_jump_tag(state);
}
p0 = p1 = (unsigned char *)RSTRING_PTR(str);
if (i2d_ASN1_TYPE(asn1, &p0) < 0) {
@@ -1060,7 +1190,7 @@ ossl_asn1prim_to_der(VALUE self)
/* Strip header since to_der_internal() wants only the payload */
j = ASN1_get_object((const unsigned char **)&p1, &bodylen, &tag, &tc, alllen);
if (j & 0x80)
- ossl_raise(eASN1Error, "ASN1_get_object"); /* should not happen */
+ ossl_raise(eASN1Error, "ASN1_get_object"); /* should not happen */
return to_der_internal(self, 0, 0, rb_str_drop_bytes(str, alllen - bodylen));
}
@@ -1082,22 +1212,22 @@ ossl_asn1cons_to_der(VALUE self)
ary = rb_convert_type(ossl_asn1_get_value(self), T_ARRAY, "Array", "to_a");
str = rb_str_new(NULL, 0);
for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE item = RARRAY_AREF(ary, i);
-
- if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) {
- if (i != RARRAY_LEN(ary) - 1)
- ossl_raise(eASN1Error, "illegal EOC octets in value");
-
- /*
- * EOC is not really part of the content, but we required to add one
- * at the end in the past.
- */
- break;
- }
-
- item = ossl_to_der_if_possible(item);
- StringValue(item);
- rb_str_append(str, item);
+ VALUE item = RARRAY_AREF(ary, i);
+
+ if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) {
+ if (i != RARRAY_LEN(ary) - 1)
+ ossl_raise(eASN1Error, "illegal EOC octets in value");
+
+ /*
+ * EOC is not really part of the content, but we required to add one
+ * at the end in the past.
+ */
+ break;
+ }
+
+ item = ossl_to_der_if_possible(item);
+ StringValue(item);
+ rb_str_append(str, item);
}
return to_der_internal(self, 1, indef_len, str);
@@ -1105,6 +1235,27 @@ ossl_asn1cons_to_der(VALUE self)
/*
* call-seq:
+ * asn1_ary.each { |asn1| block } => asn1_ary
+ *
+ * Calls the given block once for each element in self, passing that element
+ * as parameter _asn1_. If no block is given, an enumerator is returned
+ * instead.
+ *
+ * == Example
+ * asn1_ary.each do |asn1|
+ * puts asn1
+ * end
+ */
+static VALUE
+ossl_asn1cons_each(VALUE self)
+{
+ rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0);
+
+ return self;
+}
+
+/*
+ * call-seq:
* OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)
*
* This adds a new ObjectId to the internal tables. Where _object_id_ is the
@@ -1122,7 +1273,7 @@ ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln)
StringValueCStr(ln);
if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln)))
- ossl_raise(eASN1Error, NULL);
+ ossl_raise(eASN1Error, NULL);
return Qtrue;
}
@@ -1142,7 +1293,7 @@ ossl_asn1obj_get_sn(VALUE self)
val = ossl_asn1_get_value(self);
if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
+ ret = rb_str_new2(OBJ_nid2sn(nid));
return ret;
}
@@ -1162,7 +1313,7 @@ ossl_asn1obj_get_ln(VALUE self)
val = ossl_asn1_get_value(self);
if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)
- ret = rb_str_new2(OBJ_nid2ln(nid));
+ ret = rb_str_new2(OBJ_nid2ln(nid));
return ret;
}
@@ -1170,23 +1321,7 @@ ossl_asn1obj_get_ln(VALUE self)
static VALUE
asn1obj_get_oid_i(VALUE vobj)
{
- ASN1_OBJECT *a1obj = (void *)vobj;
- VALUE str;
- int len;
-
- str = rb_usascii_str_new(NULL, 127);
- len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
- if (len <= 0 || len == INT_MAX)
- ossl_raise(eASN1Error, "OBJ_obj2txt");
- if (len > RSTRING_LEN(str)) {
- /* +1 is for the \0 terminator added by OBJ_obj2txt() */
- rb_str_resize(str, len + 1);
- len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
- if (len <= 0)
- ossl_raise(eASN1Error, "OBJ_obj2txt");
- }
- rb_str_set_len(str, len);
- return str;
+ return ossl_asn1obj_to_string_oid((const ASN1_OBJECT *)vobj);
}
/*
@@ -1203,11 +1338,11 @@ ossl_asn1obj_get_oid(VALUE self)
ASN1_OBJECT *a1obj;
int state;
- a1obj = obj_to_asn1obj(ossl_asn1_get_value(self));
+ a1obj = ossl_to_asn1obj(ossl_asn1_get_value(self));
str = rb_protect(asn1obj_get_oid_i, (VALUE)a1obj, &state);
ASN1_OBJECT_free(a1obj);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return str;
}
@@ -1232,7 +1367,7 @@ ossl_asn1obj_eq(VALUE self, VALUE other)
#define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \
static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\
-{ return rb_funcallv_public(cASN1##klass, rb_intern("new"), argc, argv); }
+{ return rb_funcall3(cASN1##klass, rb_intern("new"), argc, argv); }
OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)
OSSL_ASN1_IMPL_FACTORY_METHOD(Integer)
@@ -1262,13 +1397,6 @@ void
Init_ossl_asn1(void)
{
#undef rb_intern
- VALUE ary;
- int i;
-
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
sym_UNIVERSAL = ID2SYM(rb_intern_const("UNIVERSAL"));
sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const("CONTEXT_SPECIFIC"));
@@ -1418,17 +1546,20 @@ Init_ossl_asn1(void)
rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1);
rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1);
rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1);
- ary = rb_ary_new();
+ VALUE ary = rb_ary_new_capa(ossl_asn1_info_size);
+ for (int i = 0; i < ossl_asn1_info_size; i++) {
+ const char *name = ossl_asn1_info[i].name;
+ if (name[0] == '[')
+ continue;
+ rb_define_const(mASN1, name, INT2NUM(i));
+ rb_ary_store(ary, i, rb_obj_freeze(rb_str_new_cstr(name)));
+ }
+ rb_obj_freeze(ary);
/*
* Array storing tag names at the tag's index.
*/
rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary);
- for(i = 0; i < ossl_asn1_info_size; i++){
- if(ossl_asn1_info[i].name[0] == '[') continue;
- rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i));
- rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name));
- }
/* Document-class: OpenSSL::ASN1::ASN1Data
*
@@ -1518,6 +1649,42 @@ Init_ossl_asn1(void)
* puts int2.value # => 1
*/
cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
+ /*
+ * Carries the value of a ASN.1 type.
+ * Please confer Constructive and Primitive for the mappings between
+ * ASN.1 data types and Ruby classes.
+ */
+ rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
+ /*
+ * An Integer representing the tag number of this ASN1Data. Never +nil+.
+ */
+ rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
+ /*
+ * A Symbol representing the tag class of this ASN1Data. Never +nil+.
+ * See ASN1Data for possible values.
+ */
+ rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
+ /*
+ * Never +nil+. A boolean value indicating whether the encoding uses
+ * indefinite length (in the case of parsing) or whether an indefinite
+ * length form shall be used (in the encoding case).
+ * In DER, every value uses definite length form. But in scenarios where
+ * large amounts of data need to be transferred it might be desirable to
+ * have some kind of streaming support available.
+ * For example, huge OCTET STRINGs are preferably sent in smaller-sized
+ * chunks, each at a time.
+ * This is possible in BER by setting the length bytes of an encoding
+ * to zero and by this indicating that the following value will be
+ * sent in chunks. Indefinite length encodings are always constructed.
+ * The end of such a stream of chunks is indicated by sending a EOC
+ * (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
+ * encoding, but also primitive types such as e.g. OCTET STRINGS or
+ * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
+ */
+ rb_attr(cASN1Data, rb_intern("indefinite_length"), 1, 1, 0);
+ rb_define_alias(cASN1Data, "infinite_length", "indefinite_length");
+ rb_define_alias(cASN1Data, "infinite_length=", "indefinite_length=");
+ rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
/* Document-class: OpenSSL::ASN1::Primitive
@@ -1585,6 +1752,16 @@ Init_ossl_asn1(void)
* prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
*/
cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
+ /*
+ * May be used as a hint for encoding a value either implicitly or
+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+ * _tagging_ is not set when a ASN.1 structure is parsed using
+ * OpenSSL::ASN1.decode.
+ */
+ rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
+ rb_undef_method(cASN1Primitive, "indefinite_length=");
+ rb_undef_method(cASN1Primitive, "infinite_length=");
+ rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);
/* Document-class: OpenSSL::ASN1::Constructive
@@ -1615,7 +1792,17 @@ Init_ossl_asn1(void)
* set = OpenSSL::ASN1::Set.new( [ int, str ] )
*/
cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
+ rb_include_module(cASN1Constructive, rb_mEnumerable);
+ /*
+ * May be used as a hint for encoding a value either implicitly or
+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+ * _tagging_ is not set when a ASN.1 structure is parsed using
+ * OpenSSL::ASN1.decode.
+ */
+ rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
+ rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
+ rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);
#define OSSL_ASN1_DEFINE_CLASS(name, super) \
do{\
@@ -1664,10 +1851,13 @@ do{\
rb_define_alias(cASN1ObjectId, "short_name", "sn");
rb_define_alias(cASN1ObjectId, "long_name", "ln");
rb_define_method(cASN1ObjectId, "==", ossl_asn1obj_eq, 1);
+ rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
+ rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0);
rb_define_method(cASN1EndOfContent, "to_der", ossl_asn1eoc_to_der, 0);
class_tag_map = rb_hash_new();
+ rb_gc_register_mark_object(class_tag_map);
rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC));
rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN));
rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER));
@@ -1691,5 +1881,7 @@ do{\
rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
- rb_define_const(mASN1, "CLASS_TAG_MAP", class_tag_map);
+ rb_obj_freeze(class_tag_map);
+
+ id_each = rb_intern_const("each");
}
diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h
index 3b689c0ee7..b605df8f3f 100644
--- a/ext/openssl/ossl_asn1.h
+++ b/ext/openssl/ossl_asn1.h
@@ -32,10 +32,24 @@ VALUE asn1integer_to_num(const ASN1_INTEGER *);
ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *);
/*
+ * ASN1_OBJECT conversions
+ */
+ASN1_OBJECT *ossl_to_asn1obj(VALUE obj);
+/*
+ * Returns the short name if available, the dotted decimal notation otherwise.
+ * This is the most common way to return ASN1_OBJECT to Ruby.
+ */
+VALUE ossl_asn1obj_to_string(const ASN1_OBJECT *a1obj);
+/*
+ * However, some places use long names instead. This is likely unintentional,
+ * but we keep the current behavior in existing methods.
+ */
+VALUE ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *a1obj);
+
+/*
* ASN1 module
*/
extern VALUE mASN1;
-extern VALUE eASN1Error;
extern VALUE cASN1Data;
diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c
index 2ef2080507..4edde5091d 100644
--- a/ext/openssl/ossl_bio.c
+++ b/ext/openssl/ossl_bio.c
@@ -16,11 +16,11 @@ ossl_obj2bio(volatile VALUE *pobj)
BIO *bio;
if (RB_TYPE_P(obj, T_FILE))
- obj = rb_funcallv(obj, rb_intern("read"), 0, NULL);
+ obj = rb_funcallv(obj, rb_intern("read"), 0, NULL);
StringValue(obj);
bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj));
if (!bio)
- ossl_raise(eOSSLError, "BIO_new_mem_buf");
+ ossl_raise(eOSSLError, "BIO_new_mem_buf");
*pobj = obj;
return bio;
}
@@ -36,7 +36,7 @@ ossl_membio2str(BIO *bio)
ret = ossl_str_new(buf->data, buf->length, &state);
BIO_free(bio);
if (state)
- rb_jump_tag(state);
+ rb_jump_tag(state);
return ret;
}
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index 8699ce8ec5..9014f2df2b 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -11,19 +11,19 @@
#include "ossl.h"
#define NewBN(klass) \
- TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
+ TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
#define SetBN(obj, bn) do { \
- if (!(bn)) { \
- ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
- } \
- RTYPEDDATA_DATA(obj) = (bn); \
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+ RTYPEDDATA_DATA(obj) = (bn); \
} while (0)
#define GetBN(obj, bn) do { \
- TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
- if (!(bn)) { \
- ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
- } \
+ TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
} while (0)
static void
@@ -35,7 +35,7 @@ ossl_bn_free(void *ptr)
static const rb_data_type_t ossl_bn_type = {
"OpenSSL/BN",
{
- 0, ossl_bn_free,
+ 0, ossl_bn_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
};
@@ -61,10 +61,9 @@ ossl_bn_new(const BIGNUM *bn)
VALUE obj;
obj = NewBN(cBN);
- newbn = bn ? BN_dup(bn) : BN_new();
- if (!newbn) {
- ossl_raise(eBNError, NULL);
- }
+ newbn = BN_dup(bn);
+ if (!newbn)
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, newbn);
return obj;
@@ -76,40 +75,40 @@ integer_to_bnptr(VALUE obj, BIGNUM *orig)
BIGNUM *bn;
if (FIXNUM_P(obj)) {
- long i;
- unsigned char bin[sizeof(long)];
- long n = FIX2LONG(obj);
- unsigned long un = labs(n);
-
- for (i = sizeof(long) - 1; 0 <= i; i--) {
- bin[i] = un & 0xff;
- un >>= 8;
- }
-
- bn = BN_bin2bn(bin, sizeof(bin), orig);
- if (!bn)
- ossl_raise(eBNError, "BN_bin2bn");
- if (n < 0)
- BN_set_negative(bn, 1);
+ long i;
+ unsigned char bin[sizeof(long)];
+ long n = FIX2LONG(obj);
+ unsigned long un = labs(n);
+
+ for (i = sizeof(long) - 1; 0 <= i; i--) {
+ bin[i] = un & 0xff;
+ un >>= 8;
+ }
+
+ bn = BN_bin2bn(bin, sizeof(bin), orig);
+ if (!bn)
+ ossl_raise(eBNError, "BN_bin2bn");
+ if (n < 0)
+ BN_set_negative(bn, 1);
}
else { /* assuming Bignum */
- size_t len = rb_absint_size(obj, NULL);
- unsigned char *bin;
- VALUE buf;
- int sign;
-
- if (INT_MAX < len) {
- rb_raise(eBNError, "bignum too long");
- }
- bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
- sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
-
- bn = BN_bin2bn(bin, (int)len, orig);
- ALLOCV_END(buf);
- if (!bn)
- ossl_raise(eBNError, "BN_bin2bn");
- if (sign < 0)
- BN_set_negative(bn, 1);
+ size_t len = rb_absint_size(obj, NULL);
+ unsigned char *bin;
+ VALUE buf;
+ int sign;
+
+ if (INT_MAX < len) {
+ rb_raise(eBNError, "bignum too long");
+ }
+ bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
+ sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
+
+ bn = BN_bin2bn(bin, (int)len, orig);
+ ALLOCV_END(buf);
+ if (!bn)
+ ossl_raise(eBNError, "BN_bin2bn");
+ if (sign < 0)
+ BN_set_negative(bn, 1);
}
return bn;
@@ -122,11 +121,11 @@ try_convert_to_bn(VALUE obj)
VALUE newobj = Qnil;
if (rb_obj_is_kind_of(obj, cBN))
- return obj;
+ return obj;
if (RB_INTEGER_TYPE_P(obj)) {
- newobj = NewBN(cBN); /* Handle potential mem leaks */
- bn = integer_to_bnptr(obj, NULL);
- SetBN(newobj, bn);
+ newobj = NewBN(cBN); /* Handle potential mem leaks */
+ bn = integer_to_bnptr(obj, NULL);
+ SetBN(newobj, bn);
}
return newobj;
@@ -140,7 +139,7 @@ ossl_bn_value_ptr(volatile VALUE *ptr)
tmp = try_convert_to_bn(*ptr);
if (NIL_P(tmp))
- ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
+ ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
GetBN(tmp, bn);
*ptr = tmp;
@@ -210,7 +209,7 @@ ossl_bn_alloc(VALUE klass)
VALUE obj = NewBN(klass);
if (!(bn = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj, bn);
@@ -252,7 +251,7 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
char *ptr;
if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
- base = NUM2INT(bs);
+ base = NUM2INT(bs);
}
if (NIL_P(str)) {
@@ -261,49 +260,49 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (RB_INTEGER_TYPE_P(str)) {
- GetBN(self, bn);
- integer_to_bnptr(str, bn);
+ GetBN(self, bn);
+ integer_to_bnptr(str, bn);
- return self;
+ return self;
}
if (RTEST(rb_obj_is_kind_of(str, cBN))) {
- BIGNUM *other;
-
- GetBN(self, bn);
- GetBN(str, other); /* Safe - we checked kind_of? above */
- if (!BN_copy(bn, other)) {
- ossl_raise(eBNError, NULL);
- }
- return self;
+ BIGNUM *other;
+
+ GetBN(self, bn);
+ GetBN(str, other); /* Safe - we checked kind_of? above */
+ if (!BN_copy(bn, other)) {
+ ossl_raise(eBNError, NULL);
+ }
+ return self;
}
GetBN(self, bn);
switch (base) {
- case 0:
+ case 0:
ptr = StringValuePtr(str);
if (!BN_mpi2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 2:
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 2:
ptr = StringValuePtr(str);
if (!BN_bin2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 10:
- if (!BN_dec2bn(&bn, StringValueCStr(str))) {
- ossl_raise(eBNError, NULL);
- }
- break;
- case 16:
- if (!BN_hex2bn(&bn, StringValueCStr(str))) {
- ossl_raise(eBNError, NULL);
- }
- break;
- default:
- ossl_raise(rb_eArgError, "invalid radix %d", base);
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 10:
+ if (!BN_dec2bn(&bn, StringValueCStr(str))) {
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ case 16:
+ if (!BN_hex2bn(&bn, StringValueCStr(str))) {
+ ossl_raise(eBNError, NULL);
+ }
+ break;
+ default:
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return self;
}
@@ -335,32 +334,32 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
char *buf;
if (rb_scan_args(argc, argv, "01", &bs) == 1) {
- base = NUM2INT(bs);
+ base = NUM2INT(bs);
}
GetBN(self, bn);
switch (base) {
- case 0:
- len = BN_bn2mpi(bn, NULL);
+ case 0:
+ len = BN_bn2mpi(bn, NULL);
str = rb_str_new(0, len);
- if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
- ossl_raise(eBNError, NULL);
- break;
- case 2:
- len = BN_num_bytes(bn);
+ if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+ ossl_raise(eBNError, NULL);
+ break;
+ case 2:
+ len = BN_num_bytes(bn);
str = rb_str_new(0, len);
- if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
- ossl_raise(eBNError, NULL);
- break;
- case 10:
- if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
- str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
- break;
- case 16:
- if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
- str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
- break;
- default:
- ossl_raise(rb_eArgError, "invalid radix %d", base);
+ if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+ ossl_raise(eBNError, NULL);
+ break;
+ case 10:
+ if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
+ str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+ break;
+ case 16:
+ if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
+ str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+ break;
+ default:
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return str;
@@ -380,7 +379,7 @@ ossl_bn_to_i(VALUE self)
GetBN(self, bn);
if (!(txt = BN_bn2hex(bn))) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
num = rb_cstr_to_inum(txt, 16, Qtrue);
OPENSSL_free(txt);
@@ -398,31 +397,31 @@ static VALUE
ossl_bn_coerce(VALUE self, VALUE other)
{
switch(TYPE(other)) {
- case T_STRING:
- self = ossl_bn_to_s(0, NULL, self);
- break;
- case T_FIXNUM:
- case T_BIGNUM:
- self = ossl_bn_to_i(self);
- break;
- default:
- if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
- ossl_raise(rb_eTypeError, "Don't know how to coerce");
- }
+ case T_STRING:
+ self = ossl_bn_to_s(0, NULL, self);
+ break;
+ case T_FIXNUM:
+ case T_BIGNUM:
+ self = ossl_bn_to_i(self);
+ break;
+ default:
+ if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
+ ossl_raise(rb_eTypeError, "Don't know how to coerce");
+ }
}
return rb_assoc_new(other, self);
}
-#define BIGNUM_BOOL1(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn; \
- GetBN(self, bn); \
- if (BN_##func(bn)) { \
- return Qtrue; \
- } \
- return Qfalse; \
+#define BIGNUM_BOOL1(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn; \
+ GetBN(self, bn); \
+ if (BN_##func(bn)) { \
+ return Qtrue; \
+ } \
+ return Qfalse; \
}
/*
@@ -457,27 +456,27 @@ ossl_bn_is_negative(VALUE self)
GetBN(self, bn);
if (BN_is_zero(bn))
- return Qfalse;
+ return Qfalse;
return BN_is_negative(bn) ? Qtrue : Qfalse;
}
-#define BIGNUM_1c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn, *result; \
- VALUE obj; \
- GetBN(self, bn); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_1c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn, *result; \
+ VALUE obj; \
+ GetBN(self, bn); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -487,23 +486,23 @@ ossl_bn_is_negative(VALUE self)
*/
BIGNUM_1c(sqr)
-#define BIGNUM_2(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -520,23 +519,23 @@ BIGNUM_2(add)
*/
BIGNUM_2(sub)
-#define BIGNUM_2c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -574,18 +573,18 @@ BIGNUM_2c(gcd)
*/
BIGNUM_2c(mod_sqr)
-#define BIGNUM_2cr(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \
- ossl_raise(eBNError, NULL); \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_2cr(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \
+ ossl_raise(eBNError, NULL); \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -620,16 +619,16 @@ ossl_bn_div(VALUE self, VALUE other)
obj1 = NewBN(klass);
obj2 = NewBN(klass);
if (!(r1 = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
if (!(r2 = BN_new())) {
- BN_free(r1);
- ossl_raise(eBNError, NULL);
+ BN_free(r1);
+ ossl_raise(eBNError, NULL);
}
if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
- BN_free(r1);
- BN_free(r2);
- ossl_raise(eBNError, NULL);
+ BN_free(r1);
+ BN_free(r2);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj1, r1);
SetBN(obj2, r2);
@@ -637,24 +636,24 @@ ossl_bn_div(VALUE self, VALUE other)
return rb_ary_new3(2, obj1, obj2);
}
-#define BIGNUM_3c(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
- BIGNUM *bn3 = GetBNPtr(other2), *result; \
- VALUE obj; \
- GetBN(self, bn1); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_3c(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
+ BIGNUM *bn3 = GetBNPtr(other2), *result; \
+ VALUE obj; \
+ GetBN(self, bn1); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -685,17 +684,17 @@ BIGNUM_3c(mod_mul)
*/
BIGNUM_3c(mod_exp)
-#define BIGNUM_BIT(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE bit) \
- { \
- BIGNUM *bn; \
- rb_check_frozen(self); \
- GetBN(self, bn); \
- if (BN_##func(bn, NUM2INT(bit)) <= 0) { \
- ossl_raise(eBNError, NULL); \
- } \
- return self; \
+#define BIGNUM_BIT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bit) \
+ { \
+ BIGNUM *bn; \
+ rb_check_frozen(self); \
+ GetBN(self, bn); \
+ if (BN_##func(bn, NUM2INT(bit)) <= 0) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ return self; \
}
/*
@@ -734,30 +733,30 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit)
b = NUM2INT(bit);
GetBN(self, bn);
if (BN_is_bit_set(bn, b)) {
- return Qtrue;
+ return Qtrue;
}
return Qfalse;
}
-#define BIGNUM_SHIFT(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE bits) \
- { \
- BIGNUM *bn, *result; \
- int b; \
- VALUE obj; \
- b = NUM2INT(bits); \
- GetBN(self, bn); \
- obj = NewBN(rb_obj_class(self)); \
- if (!(result = BN_new())) { \
- ossl_raise(eBNError, NULL); \
- } \
- if (BN_##func(result, bn, b) <= 0) { \
- BN_free(result); \
- ossl_raise(eBNError, NULL); \
- } \
- SetBN(obj, result); \
- return obj; \
+#define BIGNUM_SHIFT(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn, *result; \
+ int b; \
+ VALUE obj; \
+ b = NUM2INT(bits); \
+ GetBN(self, bn); \
+ obj = NewBN(rb_obj_class(self)); \
+ if (!(result = BN_new())) { \
+ ossl_raise(eBNError, NULL); \
+ } \
+ if (BN_##func(result, bn, b) <= 0) { \
+ BN_free(result); \
+ ossl_raise(eBNError, NULL); \
+ } \
+ SetBN(obj, result); \
+ return obj; \
}
/*
@@ -774,18 +773,18 @@ BIGNUM_SHIFT(lshift)
*/
BIGNUM_SHIFT(rshift)
-#define BIGNUM_SELF_SHIFT(func) \
- static VALUE \
- ossl_bn_self_##func(VALUE self, VALUE bits) \
- { \
- BIGNUM *bn; \
- int b; \
- rb_check_frozen(self); \
- b = NUM2INT(bits); \
- GetBN(self, bn); \
- if (BN_##func(bn, bn, b) <= 0) \
- ossl_raise(eBNError, NULL); \
- return self; \
+#define BIGNUM_SELF_SHIFT(func) \
+ static VALUE \
+ ossl_bn_self_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn; \
+ int b; \
+ rb_check_frozen(self); \
+ b = NUM2INT(bits); \
+ GetBN(self, bn); \
+ if (BN_##func(bn, bn, b) <= 0) \
+ ossl_raise(eBNError, NULL); \
+ return self; \
}
/*
@@ -887,32 +886,32 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
num = NUM2INT(vnum);
if (vsafe == Qfalse) {
- safe = 0;
+ safe = 0;
}
if (!NIL_P(vadd)) {
- add = GetBNPtr(vadd);
- rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
+ add = GetBNPtr(vadd);
+ rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
}
obj = NewBN(klass);
if (!(result = BN_new())) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) {
- BN_free(result);
- ossl_raise(eBNError, NULL);
+ BN_free(result);
+ ossl_raise(eBNError, NULL);
}
SetBN(obj, result);
return obj;
}
-#define BIGNUM_NUM(func) \
- static VALUE \
- ossl_bn_##func(VALUE self) \
- { \
- BIGNUM *bn; \
- GetBN(self, bn); \
- return INT2NUM(BN_##func(bn)); \
+#define BIGNUM_NUM(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self) \
+ { \
+ BIGNUM *bn; \
+ GetBN(self, bn); \
+ return INT2NUM(BN_##func(bn)); \
}
/*
@@ -943,7 +942,7 @@ ossl_bn_copy(VALUE self, VALUE other)
bn2 = GetBNPtr(other);
if (!BN_copy(bn1, bn2)) {
- ossl_raise(eBNError, NULL);
+ ossl_raise(eBNError, NULL);
}
return self;
}
@@ -962,7 +961,7 @@ ossl_bn_uplus(VALUE self)
obj = NewBN(cBN);
bn2 = BN_dup(bn1);
if (!bn2)
- ossl_raise(eBNError, "BN_dup");
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, bn2);
return obj;
@@ -982,7 +981,7 @@ ossl_bn_uminus(VALUE self)
obj = NewBN(cBN);
bn2 = BN_dup(bn1);
if (!bn2)
- ossl_raise(eBNError, "BN_dup");
+ ossl_raise(eBNError, "BN_dup");
SetBN(obj, bn2);
BN_set_negative(bn2, !BN_is_negative(bn2));
@@ -1007,13 +1006,13 @@ ossl_bn_abs(VALUE self)
}
}
-#define BIGNUM_CMP(func) \
- static VALUE \
- ossl_bn_##func(VALUE self, VALUE other) \
- { \
- BIGNUM *bn1, *bn2 = GetBNPtr(other); \
- GetBN(self, bn1); \
- return INT2NUM(BN_##func(bn1, bn2)); \
+#define BIGNUM_CMP(func) \
+ static VALUE \
+ ossl_bn_##func(VALUE self, VALUE other) \
+ { \
+ BIGNUM *bn1, *bn2 = GetBNPtr(other); \
+ GetBN(self, bn1); \
+ return INT2NUM(BN_##func(bn1, bn2)); \
}
/*
@@ -1050,11 +1049,11 @@ ossl_bn_eq(VALUE self, VALUE other)
GetBN(self, bn1);
other = try_convert_to_bn(other);
if (NIL_P(other))
- return Qfalse;
+ return Qfalse;
GetBN(other, bn2);
if (!BN_cmp(bn1, bn2)) {
- return Qtrue;
+ return Qtrue;
}
return Qfalse;
}
@@ -1073,7 +1072,7 @@ ossl_bn_eql(VALUE self, VALUE other)
BIGNUM *bn1, *bn2;
if (!rb_obj_is_kind_of(other, cBN))
- return Qfalse;
+ return Qfalse;
GetBN(self, bn1);
GetBN(other, bn2);
@@ -1100,8 +1099,8 @@ ossl_bn_hash(VALUE self)
len = BN_num_bytes(bn);
buf = ALLOCV(tmp, len);
if (BN_bn2bin(bn, buf) != len) {
- ALLOCV_END(tmp);
- ossl_raise(eBNError, "BN_bn2bin");
+ ALLOCV_END(tmp);
+ ossl_raise(eBNError, "BN_bn2bin");
}
hash = ST2FIX(rb_memhash(buf, len));
@@ -1203,11 +1202,6 @@ ossl_bn_set_flags(VALUE self, VALUE arg)
void
Init_ossl_bn(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
#ifdef HAVE_RB_EXT_RACTOR_SAFE
ossl_bn_ctx_key = rb_ractor_local_storage_ptr_newkey(&ossl_bn_ctx_key_type);
#else
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index d737fa74ff..f3cd247c8f 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -14,7 +14,7 @@
#define AllocCipher(obj, ctx) do { \
(ctx) = EVP_CIPHER_CTX_new(); \
if (!(ctx)) \
- ossl_raise(rb_eRuntimeError, NULL); \
+ ossl_raise(rb_eRuntimeError, NULL); \
RTYPEDDATA_DATA(obj) = (ctx); \
} while (0)
#define GetCipherInit(obj, ctx) do { \
@@ -23,7 +23,7 @@
#define GetCipher(obj, ctx) do { \
GetCipherInit((obj), (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Cipher not initialized!"); \
} \
} while (0)
@@ -32,7 +32,8 @@
*/
static VALUE cCipher;
static VALUE eCipherError;
-static ID id_auth_tag_len, id_key_set;
+static VALUE eAuthTagError;
+static ID id_auth_tag_len, id_key_set, id_cipher_holder;
static VALUE ossl_cipher_alloc(VALUE klass);
static void ossl_cipher_free(void *ptr);
@@ -40,35 +41,63 @@ static void ossl_cipher_free(void *ptr);
static const rb_data_type_t ossl_cipher_type = {
"OpenSSL/Cipher",
{
- 0, ossl_cipher_free,
+ 0, ossl_cipher_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
+#ifdef OSSL_USE_PROVIDER
+static void
+ossl_evp_cipher_free(void *ptr)
+{
+ // This is safe to call against const EVP_CIPHER * returned by
+ // EVP_get_cipherbyname()
+ EVP_CIPHER_free(ptr);
+}
+
+static const rb_data_type_t ossl_evp_cipher_holder_type = {
+ "OpenSSL/EVP_CIPHER",
+ {
+ .dfree = ossl_evp_cipher_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+};
+#endif
+
/*
* PUBLIC
*/
const EVP_CIPHER *
-ossl_evp_get_cipherbyname(VALUE obj)
+ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder)
{
+ *holder = Qnil;
if (rb_obj_is_kind_of(obj, cCipher)) {
- EVP_CIPHER_CTX *ctx;
-
- GetCipher(obj, ctx);
-
- return EVP_CIPHER_CTX_cipher(ctx);
+ EVP_CIPHER_CTX *ctx;
+ GetCipher(obj, ctx);
+ EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_CIPHER_CTX_cipher(ctx);
+#ifdef OSSL_USE_PROVIDER
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
+ if (!EVP_CIPHER_up_ref(cipher))
+ ossl_raise(eCipherError, "EVP_CIPHER_up_ref");
+ RTYPEDDATA_DATA(*holder) = cipher;
+#endif
+ return cipher;
}
- else {
- const EVP_CIPHER *cipher;
- StringValueCStr(obj);
- cipher = EVP_get_cipherbyname(RSTRING_PTR(obj));
- if (!cipher)
- ossl_raise(rb_eArgError,
- "unsupported cipher algorithm: %"PRIsVALUE, obj);
-
- return cipher;
+ const char *name = StringValueCStr(obj);
+ EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name);
+#ifdef OSSL_USE_PROVIDER
+ if (!cipher) {
+ ossl_clear_error();
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);
+ cipher = EVP_CIPHER_fetch(NULL, name, NULL);
+ RTYPEDDATA_DATA(*holder) = cipher;
}
+#endif
+ if (!cipher)
+ ossl_raise(eCipherError, "unsupported cipher algorithm: %"PRIsVALUE,
+ obj);
+ return cipher;
}
VALUE
@@ -77,10 +106,13 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
VALUE ret;
EVP_CIPHER_CTX *ctx;
+ // NOTE: This does not set id_cipher_holder because this function should
+ // only be called from ossl_engine.c, which will not use any
+ // reference-counted ciphers.
ret = ossl_cipher_alloc(cCipher);
AllocCipher(ret, ctx);
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return ret;
}
@@ -113,19 +145,17 @@ ossl_cipher_initialize(VALUE self, VALUE str)
{
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
- char *name;
+ VALUE cipher_holder;
- name = StringValueCStr(str);
GetCipherInit(self, ctx);
if (ctx) {
- ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
+ ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
}
+ cipher = ossl_evp_cipher_fetch(str, &cipher_holder);
AllocCipher(self, ctx);
- if (!(cipher = EVP_get_cipherbyname(name))) {
- ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str);
- }
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, "EVP_CipherInit_ex");
+ rb_ivar_set(self, id_cipher_holder, cipher_holder);
return self;
}
@@ -141,11 +171,11 @@ ossl_cipher_copy(VALUE self, VALUE other)
GetCipherInit(self, ctx1);
if (!ctx1) {
- AllocCipher(self, ctx1);
+ AllocCipher(self, ctx1);
}
GetCipher(other, ctx2);
if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return self;
}
@@ -170,8 +200,8 @@ ossl_s_ciphers(VALUE self)
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
- add_cipher_name_to_ary,
- (void*)ary);
+ add_cipher_name_to_ary,
+ (void*)ary);
return ary;
}
@@ -192,53 +222,22 @@ ossl_cipher_reset(VALUE self)
GetCipher(self, ctx);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return self;
}
static VALUE
-ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
+ossl_cipher_init(VALUE self, int enc)
{
EVP_CIPHER_CTX *ctx;
- unsigned char key[EVP_MAX_KEY_LENGTH], *p_key = NULL;
- unsigned char iv[EVP_MAX_IV_LENGTH], *p_iv = NULL;
- VALUE pass, init_v;
-
- if(rb_scan_args(argc, argv, "02", &pass, &init_v) > 0){
- /*
- * oops. this code mistakes salt for IV.
- * We deprecated the arguments for this method, but we decided
- * keeping this behaviour for backward compatibility.
- */
- VALUE cname = rb_class_path(rb_obj_class(self));
- rb_warn("arguments for %"PRIsVALUE"#encrypt and %"PRIsVALUE"#decrypt were deprecated; "
- "use %"PRIsVALUE"#pkcs5_keyivgen to derive key and IV",
- cname, cname, cname);
- StringValue(pass);
- GetCipher(self, ctx);
- if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv));
- else{
- StringValue(init_v);
- if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) {
- memset(iv, 0, EVP_MAX_IV_LENGTH);
- memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v));
- }
- else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv));
- }
- EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
- (unsigned char *)RSTRING_PTR(pass), RSTRING_LENINT(pass), 1, key, NULL);
- p_key = key;
- p_iv = iv;
- }
- else {
- GetCipher(self, ctx);
- }
- if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) {
- ossl_raise(eCipherError, NULL);
+
+ GetCipher(self, ctx);
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, enc) != 1) {
+ ossl_raise(eCipherError, "EVP_CipherInit_ex");
}
- rb_ivar_set(self, id_key_set, p_key ? Qtrue : Qfalse);
+ rb_ivar_set(self, id_key_set, Qfalse);
return self;
}
@@ -249,16 +248,15 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
*
* Initializes the Cipher for encryption.
*
- * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
- * following methods:
- * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
+ * Make sure to call either #encrypt or #decrypt before using the Cipher for
+ * any operation or setting any parameters.
*
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).
*/
static VALUE
-ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
+ossl_cipher_encrypt(VALUE self)
{
- return ossl_cipher_init(argc, argv, self, 1);
+ return ossl_cipher_init(self, 1);
}
/*
@@ -267,16 +265,15 @@ ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
*
* Initializes the Cipher for decryption.
*
- * Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
- * following methods:
- * * [#key=, #iv=, #random_key, #random_iv, #pkcs5_keyivgen]
+ * Make sure to call either #encrypt or #decrypt before using the Cipher for
+ * any operation or setting any parameters.
*
* Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).
*/
static VALUE
-ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
+ossl_cipher_decrypt(VALUE self)
{
- return ossl_cipher_init(argc, argv, self, 0);
+ return ossl_cipher_init(self, 0);
}
/*
@@ -285,46 +282,42 @@ ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
*
* Generates and sets the key/IV based on a password.
*
- * *WARNING*: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40,
- * or DES with MD5 or SHA1. Using anything else (like AES) will generate the
- * key/iv using an OpenSSL specific method. This method is deprecated and
- * should no longer be used. Use a PKCS5 v2 key generation method from
- * OpenSSL::PKCS5 instead.
+ * *WARNING*: This method is deprecated and should not be used. This method
+ * corresponds to EVP_BytesToKey(), a non-standard OpenSSL extension of the
+ * legacy PKCS #5 v1.5 key derivation function. See OpenSSL::KDF for other
+ * options to derive keys from passwords.
*
* === Parameters
* * _salt_ must be an 8 byte string if provided.
* * _iterations_ is an integer with a default of 2048.
* * _digest_ is a Digest object that defaults to 'MD5'
- *
- * A minimum of 1000 iterations is recommended.
- *
*/
static VALUE
ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
const EVP_MD *digest;
- VALUE vpass, vsalt, viter, vdigest;
+ VALUE vpass, vsalt, viter, vdigest, md_holder;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
int iter;
rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
StringValue(vpass);
if(!NIL_P(vsalt)){
- StringValue(vsalt);
- if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
- ossl_raise(eCipherError, "salt must be an 8-octet string");
- salt = (unsigned char *)RSTRING_PTR(vsalt);
+ StringValue(vsalt);
+ if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
+ ossl_raise(eCipherError, "salt must be an 8-octet string");
+ salt = (unsigned char *)RSTRING_PTR(vsalt);
}
iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
if (iter <= 0)
- rb_raise(rb_eArgError, "iterations must be a positive integer");
- digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_get_digestbyname(vdigest);
+ rb_raise(rb_eArgError, "iterations must be a positive integer");
+ digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_md_fetch(vdigest, &md_holder);
GetCipher(self, ctx);
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
- (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
+ (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
OPENSSL_cleanse(key, sizeof key);
OPENSSL_cleanse(iv, sizeof iv);
@@ -335,25 +328,25 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
static int
ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr,
- const unsigned char *in, long in_len)
+ const unsigned char *in, long in_len)
{
int out_part_len;
int limit = INT_MAX / 2 + 1;
long out_len = 0;
do {
- int in_part_len = in_len > limit ? limit : (int)in_len;
+ int in_part_len = in_len > limit ? limit : (int)in_len;
- if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
- &out_part_len, in, in_part_len))
- return 0;
+ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
+ &out_part_len, in, in_part_len))
+ return 0;
- out_len += out_part_len;
- in += in_part_len;
+ out_len += out_part_len;
+ in += in_part_len;
} while ((in_len -= limit) > 0);
if (out_len_ptr)
- *out_len_ptr = out_len;
+ *out_len_ptr = out_len;
return 1;
}
@@ -369,6 +362,9 @@ ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_p
*
* If _buffer_ is given, the encryption/decryption result will be written to
* it. _buffer_ will be resized automatically.
+ *
+ * *NOTE*: When decrypting using an AEAD cipher, the integrity of the output
+ * is not verified until #final has been called.
*/
static VALUE
ossl_cipher_update(int argc, VALUE *argv, VALUE self)
@@ -381,7 +377,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &data, &str);
if (!RTEST(rb_attr_get(self, id_key_set)))
- ossl_raise(eCipherError, "key not set");
+ ossl_raise(eCipherError, "key not set");
StringValue(data);
in = (unsigned char *)RSTRING_PTR(data);
@@ -400,14 +396,14 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
* currently implemented in OpenSSL, but this can change in the future.
*/
if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) {
- ossl_raise(rb_eRangeError,
- "data too big to make output buffer: %ld bytes", in_len);
+ ossl_raise(rb_eRangeError,
+ "data too big to make output buffer: %ld bytes", in_len);
}
out_len = in_len + EVP_MAX_BLOCK_LENGTH;
- if (NIL_P(str)) {
- str = rb_str_new(0, out_len);
- } else {
+ if (NIL_P(str))
+ str = rb_str_buf_new(out_len);
+ else {
StringValue(str);
if ((long)rb_str_capacity(str) >= out_len)
rb_str_modify(str);
@@ -415,9 +411,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_str_modify_expand(str, out_len - RSTRING_LEN(str));
}
- if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
- ossl_raise(eCipherError, NULL);
- assert(out_len <= RSTRING_LEN(str));
+ if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str),
+ &out_len, in, in_len))
+ ossl_raise(eCipherError, "EVP_CipherUpdate");
rb_str_set_len(str, out_len);
return str;
@@ -428,14 +424,17 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
* cipher.final -> string
*
* Returns the remaining data held in the cipher object. Further calls to
- * Cipher#update or Cipher#final will return garbage. This call should always
+ * Cipher#update or Cipher#final are invalid. This call should always
* be made as the last call of an encryption or decryption operation, after
* having fed the entire plaintext or ciphertext to the Cipher instance.
*
- * If an authenticated cipher was used, a CipherError is raised if the tag
- * could not be authenticated successfully. Only call this method after
- * setting the authentication tag and passing the entire contents of the
- * ciphertext into the cipher.
+ * When encrypting using an AEAD cipher, the authentication tag can be
+ * retrieved by #auth_tag after #final has been called.
+ *
+ * When decrypting using an AEAD cipher, this method will verify the integrity
+ * of the ciphertext and the associated data with the authentication tag,
+ * which must be set by #auth_tag= prior to calling this method.
+ * If the verification fails, CipherError will be raised.
*/
static VALUE
ossl_cipher_final(VALUE self)
@@ -446,9 +445,17 @@ ossl_cipher_final(VALUE self)
GetCipher(self, ctx);
str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
- if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len))
- ossl_raise(eCipherError, NULL);
- assert(out_len <= RSTRING_LEN(str));
+ if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len)) {
+ /* For AEAD ciphers, this is likely an authentication failure */
+ if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) {
+ /* For AEAD ciphers, EVP_CipherFinal_ex failures are authentication tag verification failures */
+ ossl_raise(eAuthTagError, "AEAD authentication tag verification failed");
+ }
+ else {
+ /* For non-AEAD ciphers */
+ ossl_raise(eCipherError, "cipher final failed");
+ }
+ }
rb_str_set_len(str, out_len);
return str;
@@ -473,7 +480,7 @@ ossl_cipher_name(VALUE self)
/*
* call-seq:
- * cipher.key = string -> string
+ * cipher.key = string
*
* Sets the cipher key. To generate a key, you should either use a secure
* random byte string or, if the key is to be derived from a password, you
@@ -481,6 +488,8 @@ ossl_cipher_name(VALUE self)
* generate a secure random-based key, Cipher#random_key may be used.
*
* Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ *
+ * See also the man page EVP_CipherInit_ex(3).
*/
static VALUE
ossl_cipher_set_key(VALUE self, VALUE key)
@@ -493,10 +502,10 @@ ossl_cipher_set_key(VALUE self, VALUE key)
key_len = EVP_CIPHER_CTX_key_length(ctx);
if (RSTRING_LEN(key) != key_len)
- ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
+ ossl_raise(rb_eArgError, "key must be %d bytes", key_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
rb_ivar_set(self, id_key_set, Qtrue);
@@ -505,15 +514,21 @@ ossl_cipher_set_key(VALUE self, VALUE key)
/*
* call-seq:
- * cipher.iv = string -> string
+ * cipher.iv = string
*
* Sets the cipher IV. Please note that since you should never be using ECB
* mode, an IV is always explicitly required and should be set prior to
- * encryption. The IV itself can be safely transmitted in public, but it
- * should be unpredictable to prevent certain kinds of attacks. You may use
- * Cipher#random_iv to create a secure random IV.
+ * encryption. The IV itself can be safely transmitted in public.
*
- * Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ * This method expects the String to have the length equal to #iv_len. To use
+ * a different IV length with an AEAD cipher, #iv_len= must be set prior to
+ * calling this method.
+ *
+ * *NOTE*: In OpenSSL API conventions, the IV value may correspond to the
+ * "nonce" instead in some cipher modes. Refer to the OpenSSL man pages for
+ * details.
+ *
+ * See also the man page EVP_CipherInit_ex(3).
*/
static VALUE
ossl_cipher_set_iv(VALUE self, VALUE iv)
@@ -525,14 +540,14 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
- iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
+ iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!iv_len)
- iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx);
if (RSTRING_LEN(iv) != iv_len)
- ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
+ ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return iv;
}
@@ -541,8 +556,7 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
* call-seq:
* cipher.authenticated? -> true | false
*
- * Indicated whether this Cipher instance uses an Authenticated Encryption
- * mode.
+ * Indicates whether this Cipher instance uses an AEAD mode.
*/
static VALUE
ossl_cipher_is_authenticated(VALUE self)
@@ -556,21 +570,23 @@ ossl_cipher_is_authenticated(VALUE self)
/*
* call-seq:
- * cipher.auth_data = string -> string
+ * cipher.auth_data = string
+ *
+ * Sets additional authenticated data (AAD), also called associated data, for
+ * this Cipher. This method is available for AEAD ciphers.
*
- * Sets the cipher's additional authenticated data. This field must be
- * set when using AEAD cipher modes such as GCM or CCM. If no associated
- * data shall be used, this method must *still* be called with a value of "".
* The contents of this field should be non-sensitive data which will be
* added to the ciphertext to generate the authentication tag which validates
* the contents of the ciphertext.
*
- * The AAD must be set prior to encryption or decryption. In encryption mode,
- * it must be set after calling Cipher#encrypt and setting Cipher#key= and
- * Cipher#iv=. When decrypting, the authenticated data must be set after key,
- * iv and especially *after* the authentication tag has been set. I.e. set it
- * only after calling Cipher#decrypt, Cipher#key=, Cipher#iv= and
- * Cipher#auth_tag= first.
+ * This method must be called after #key= and #iv= have been set, but before
+ * starting actual encryption or decryption with #update. In some cipher modes,
+ * #auth_tag_len= and #ccm_data_len= may also need to be called before this
+ * method.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CipherUpdate() with the output buffer
+ * set to NULL.
*/
static VALUE
ossl_cipher_set_auth_data(VALUE self, VALUE data)
@@ -586,7 +602,7 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "AEAD not supported by this cipher");
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
ossl_raise(eCipherError, "couldn't set additional authenticated data");
@@ -598,16 +614,17 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
* call-seq:
* cipher.auth_tag(tag_len = 16) -> String
*
- * Gets the authentication tag generated by Authenticated Encryption Cipher
- * modes (GCM for example). This tag may be stored along with the ciphertext,
- * then set on the decryption cipher to authenticate the contents of the
- * ciphertext against changes. If the optional integer parameter _tag_len_ is
- * given, the returned tag will be _tag_len_ bytes long. If the parameter is
- * omitted, the default length of 16 bytes or the length previously set by
- * #auth_tag_len= will be used. For maximum security, the longest possible
- * should be chosen.
+ * Gets the generated authentication tag. This method is available for AEAD
+ * ciphers, and should be called after encryption has been finalized by calling
+ * #final.
+ *
+ * The returned tag will be _tag_len_ bytes long. Some cipher modes require
+ * the desired length in advance using a separate call to #auth_tag_len=,
+ * before starting encryption.
*
- * The tag may only be retrieved after calling Cipher#final.
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_GET_TAG.
*/
static VALUE
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
@@ -618,34 +635,42 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &vtag_len);
if (NIL_P(vtag_len))
- vtag_len = rb_attr_get(self, id_auth_tag_len);
+ vtag_len = rb_attr_get(self, id_auth_tag_len);
if (!NIL_P(vtag_len))
- tag_len = NUM2INT(vtag_len);
+ tag_len = NUM2INT(vtag_len);
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "authentication tag not supported by this cipher");
+ ossl_raise(eCipherError, "authentication tag not supported by this cipher");
ret = rb_str_new(NULL, tag_len);
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))
- ossl_raise(eCipherError, "retrieving the authentication tag failed");
+ ossl_raise(eCipherError, "retrieving the authentication tag failed");
return ret;
}
/*
* call-seq:
- * cipher.auth_tag = string -> string
+ * cipher.auth_tag = string
*
* Sets the authentication tag to verify the integrity of the ciphertext.
- * This can be called only when the cipher supports AE. The tag must be set
- * after calling Cipher#decrypt, Cipher#key= and Cipher#iv=, but before
- * calling Cipher#final. After all decryption is performed, the tag is
- * verified automatically in the call to Cipher#final.
*
- * For OCB mode, the tag length must be supplied with #auth_tag_len=
- * beforehand.
+ * The authentication tag must be set before #final is called. The tag is
+ * verified during the #final call.
+ *
+ * Note that, for CCM mode and OCB mode, the expected length of the tag must
+ * be set before starting decryption by a separate call to #auth_tag_len=.
+ * The content of the tag can be provided at any time before #final is called.
+ *
+ * *NOTE*: The caller must ensure that the String passed to this method has
+ * the desired length. Some cipher modes support variable tag lengths, and
+ * this method may accept a truncated tag without raising an exception.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_TAG.
*/
static VALUE
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
@@ -660,24 +685,27 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "authentication tag not supported by this cipher");
+ ossl_raise(eCipherError, "authentication tag not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
- ossl_raise(eCipherError, "unable to set AEAD tag");
+ ossl_raise(eCipherError, "unable to set AEAD tag");
return vtag;
}
/*
* call-seq:
- * cipher.auth_tag_len = Integer -> Integer
+ * cipher.auth_tag_len = integer
+ *
+ * Sets the length of the expected authentication tag for this Cipher. This
+ * method is available for some of AEAD ciphers that require the length to be
+ * set before starting encryption or decryption, such as CCM mode or OCB mode.
*
- * Sets the length of the authentication tag to be generated or to be given for
- * AEAD ciphers that requires it as in input parameter. Note that not all AEAD
- * ciphers support this method.
+ * For CCM mode and OCB mode, the tag length must be set before #iv= is set.
*
- * In OCB mode, the length must be supplied both when encrypting and when
- * decrypting, and must be before specifying an IV.
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_TAG and a NULL buffer.
*/
static VALUE
ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
@@ -687,10 +715,10 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "AEAD not supported by this cipher");
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
- ossl_raise(eCipherError, "unable to set authentication tag length");
+ ossl_raise(eCipherError, "unable to set authentication tag length");
/* for #auth_tag */
rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));
@@ -700,11 +728,16 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
/*
* call-seq:
- * cipher.iv_len = integer -> integer
+ * cipher.iv_len = integer
*
- * Sets the IV/nonce length of the Cipher. Normally block ciphers don't allow
- * changing the IV length, but some make use of IV for 'nonce'. You may need
- * this for interoperability with other applications.
+ * Sets the IV/nonce length for this Cipher. This method is available for AEAD
+ * ciphers that support variable IV lengths. This method can be called if a
+ * different IV length than OpenSSL's default is desired, prior to calling
+ * #iv=.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
+ * This method internally calls EVP_CIPHER_CTX_ctrl() with
+ * EVP_CTRL_AEAD_SET_IVLEN.
*/
static VALUE
ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
@@ -714,10 +747,10 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
GetCipher(self, ctx);
if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
- ossl_raise(eCipherError, "cipher does not support AEAD");
+ ossl_raise(eCipherError, "cipher does not support AEAD");
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
- ossl_raise(eCipherError, "unable to set IV length");
+ ossl_raise(eCipherError, "unable to set IV length");
/*
* EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save
@@ -730,13 +763,14 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
/*
* call-seq:
- * cipher.key_len = integer -> integer
+ * cipher.key_len = integer
*
* Sets the key length of the cipher. If the cipher is a fixed length cipher
* then attempting to set the key length to any value other than the fixed
* value is an error.
*
- * Under normal circumstances you do not need to call this method (and probably shouldn't).
+ * Under normal circumstances you do not need to call this method (and
+ * probably shouldn't).
*
* See EVP_CIPHER_CTX_set_key_length for further information.
*/
@@ -753,13 +787,16 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length)
return key_length;
}
+// TODO: Should #padding= take a boolean value instead?
/*
* call-seq:
- * cipher.padding = integer -> integer
+ * cipher.padding = 1 or 0
*
- * Enables or disables padding. By default encryption operations are padded using standard block padding and the
- * padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the
- * total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur.
+ * Enables or disables padding. By default encryption operations are padded
+ * using standard block padding and the padding is checked and removed when
+ * decrypting. If the pad parameter is zero then no padding is performed, the
+ * total amount of data encrypted or decrypted must then be a multiple of the
+ * block size or an error will occur.
*
* See EVP_CIPHER_CTX_set_padding for further information.
*/
@@ -771,7 +808,7 @@ ossl_cipher_set_padding(VALUE self, VALUE padding)
GetCipher(self, ctx);
if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
- ossl_raise(eCipherError, NULL);
+ ossl_raise(eCipherError, NULL);
return padding;
}
@@ -805,9 +842,9 @@ ossl_cipher_iv_length(VALUE self)
GetCipher(self, ctx);
if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
- len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
+ len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
if (!len)
- len = EVP_CIPHER_CTX_iv_length(ctx);
+ len = EVP_CIPHER_CTX_iv_length(ctx);
return INT2NUM(len);
}
@@ -830,13 +867,17 @@ ossl_cipher_block_size(VALUE self)
/*
* call-seq:
- * cipher.ccm_data_len = integer -> integer
+ * cipher.ccm_data_len = integer
*
- * Sets the length of the plaintext / ciphertext message that will be
- * processed in CCM mode. Make sure to call this method after #key= and
- * #iv= have been set, and before #auth_data=.
+ * Sets the total length of the plaintext / ciphertext message that will be
+ * processed by #update in CCM mode.
*
- * Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ * Make sure to call this method after #key= and #iv= have been set, and
+ * before #auth_data= or #update are called.
+ *
+ * This method is only available for CCM mode ciphers.
+ *
+ * See also the "AEAD Interface" section of the man page EVP_EncryptInit(3).
*/
static VALUE
ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
@@ -859,11 +900,6 @@ ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
void
Init_ossl_cipher(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Cipher
*
* Provides symmetric algorithms for encryption and decryption. The
@@ -1019,24 +1055,28 @@ Init_ossl_cipher(void)
* could otherwise be exploited to modify ciphertexts in ways beneficial to
* potential attackers.
*
- * An associated data is used where there is additional information, such as
+ * Associated data, also called additional authenticated data (AAD), is
+ * optionally used where there is additional information, such as
* headers or some metadata, that must be also authenticated but not
- * necessarily need to be encrypted. If no associated data is needed for
- * encryption and later decryption, the OpenSSL library still requires a
- * value to be set - "" may be used in case none is available.
+ * necessarily need to be encrypted.
*
* An example using the GCM (Galois/Counter Mode). You have 16 bytes _key_,
* 12 bytes (96 bits) _nonce_ and the associated data _auth_data_. Be sure
* not to reuse the _key_ and _nonce_ pair. Reusing an nonce ruins the
* security guarantees of GCM mode.
*
+ * key = OpenSSL::Random.random_bytes(16)
+ * nonce = OpenSSL::Random.random_bytes(12)
+ * auth_data = "authenticated but unencrypted data"
+ * data = "encrypted data"
+ *
* cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt
* cipher.key = key
* cipher.iv = nonce
* cipher.auth_data = auth_data
*
* encrypted = cipher.update(data) + cipher.final
- * tag = cipher.auth_tag # produces 16 bytes tag by default
+ * tag = cipher.auth_tag(16)
*
* Now you are the receiver. You know the _key_ and have received _nonce_,
* _auth_data_, _encrypted_ and _tag_ through an untrusted network. Note
@@ -1049,23 +1089,29 @@ Init_ossl_cipher(void)
* decipher = OpenSSL::Cipher.new('aes-128-gcm').decrypt
* decipher.key = key
* decipher.iv = nonce
- * decipher.auth_tag = tag
+ * decipher.auth_tag = tag # could be called at any time before #final
* decipher.auth_data = auth_data
*
* decrypted = decipher.update(encrypted) + decipher.final
*
* puts data == decrypted #=> true
+ *
+ * Note that other AEAD ciphers may require additional steps, such as
+ * setting the expected tag length (#auth_tag_len=) or the total data
+ * length (#ccm_data_len=) in advance. Make sure to read the relevant man
+ * page for details.
*/
cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
+ eAuthTagError = rb_define_class_under(cCipher, "AuthTagError", eCipherError);
rb_define_alloc_func(cCipher, ossl_cipher_alloc);
rb_define_method(cCipher, "initialize_copy", ossl_cipher_copy, 1);
rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0);
rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1);
rb_define_method(cCipher, "reset", ossl_cipher_reset, 0);
- rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1);
- rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1);
+ rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, 0);
+ rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, 0);
rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1);
rb_define_method(cCipher, "update", ossl_cipher_update, -1);
rb_define_method(cCipher, "final", ossl_cipher_final, 0);
@@ -1087,4 +1133,5 @@ Init_ossl_cipher(void)
id_auth_tag_len = rb_intern_const("auth_tag_len");
id_key_set = rb_intern_const("key_set");
+ id_cipher_holder = rb_intern_const("EVP_CIPHER_holder");
}
diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h
index 12da68ca3e..fba63a140f 100644
--- a/ext/openssl/ossl_cipher.h
+++ b/ext/openssl/ossl_cipher.h
@@ -10,7 +10,16 @@
#if !defined(_OSSL_CIPHER_H_)
#define _OSSL_CIPHER_H_
-const EVP_CIPHER *ossl_evp_get_cipherbyname(VALUE);
+/*
+ * Gets EVP_CIPHER from a String or an OpenSSL::Digest instance (discouraged,
+ * but still supported for compatibility). A holder object is created if the
+ * EVP_CIPHER is a "fetched" algorithm.
+ */
+const EVP_CIPHER *ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder);
+/*
+ * This is meant for OpenSSL::Engine#cipher. EVP_CIPHER must not be a fetched
+ * one.
+ */
VALUE ossl_cipher_new(const EVP_CIPHER *);
void Init_ossl_cipher(void);
diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c
index ee2ff6786f..274875a978 100644
--- a/ext/openssl/ossl_config.c
+++ b/ext/openssl/ossl_config.c
@@ -413,11 +413,6 @@ Init_ossl_config(void)
char *path;
VALUE path_str;
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Config
*
* Configuration for the openssl library.
@@ -426,7 +421,7 @@ Init_ossl_config(void)
* configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for
* the location of the file for your host.
*
- * See also http://www.openssl.org/docs/apps/config.html
+ * See also https://docs.openssl.org/master/man5/config/
*/
cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject);
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index 329de6c1ba..e23968b1e3 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -12,7 +12,7 @@
#define GetDigest(obj, ctx) do { \
TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
} \
} while (0)
@@ -21,6 +21,7 @@
*/
static VALUE cDigest;
static VALUE eDigestError;
+static ID id_md_holder;
static VALUE ossl_digest_alloc(VALUE klass);
@@ -33,39 +34,67 @@ ossl_digest_free(void *ctx)
static const rb_data_type_t ossl_digest_type = {
"OpenSSL/Digest",
{
- 0, ossl_digest_free,
+ 0, ossl_digest_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
+#ifdef OSSL_USE_PROVIDER
+static void
+ossl_evp_md_free(void *ptr)
+{
+ // This is safe to call against const EVP_MD * returned by
+ // EVP_get_digestbyname()
+ EVP_MD_free(ptr);
+}
+
+static const rb_data_type_t ossl_evp_md_holder_type = {
+ "OpenSSL/EVP_MD",
+ {
+ .dfree = ossl_evp_md_free,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+};
+#endif
+
/*
* Public
*/
const EVP_MD *
-ossl_evp_get_digestbyname(VALUE obj)
+ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder)
{
- const EVP_MD *md;
- ASN1_OBJECT *oid = NULL;
-
- if (RB_TYPE_P(obj, T_STRING)) {
- const char *name = StringValueCStr(obj);
-
- md = EVP_get_digestbyname(name);
- if (!md) {
- oid = OBJ_txt2obj(name, 0);
- md = EVP_get_digestbyobj(oid);
- ASN1_OBJECT_free(oid);
- }
- if(!md)
- ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%"PRIsVALUE").", obj);
- } else {
+ *holder = Qnil;
+ if (rb_obj_is_kind_of(obj, cDigest)) {
EVP_MD_CTX *ctx;
-
GetDigest(obj, ctx);
-
- md = EVP_MD_CTX_get0_md(ctx);
+ EVP_MD *md = (EVP_MD *)EVP_MD_CTX_get0_md(ctx);
+#ifdef OSSL_USE_PROVIDER
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
+ if (!EVP_MD_up_ref(md))
+ ossl_raise(eDigestError, "EVP_MD_up_ref");
+ RTYPEDDATA_DATA(*holder) = md;
+#endif
+ return md;
}
+ const char *name = StringValueCStr(obj);
+ EVP_MD *md = (EVP_MD *)EVP_get_digestbyname(name);
+ if (!md) {
+ ASN1_OBJECT *oid = OBJ_txt2obj(name, 0);
+ md = (EVP_MD *)EVP_get_digestbyobj(oid);
+ ASN1_OBJECT_free(oid);
+ }
+#ifdef OSSL_USE_PROVIDER
+ if (!md) {
+ ossl_clear_error();
+ *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);
+ md = EVP_MD_fetch(NULL, name, NULL);
+ RTYPEDDATA_DATA(*holder) = md;
+ }
+#endif
+ if (!md)
+ ossl_raise(eDigestError, "unsupported digest algorithm: %"PRIsVALUE,
+ obj);
return md;
}
@@ -75,14 +104,17 @@ ossl_digest_new(const EVP_MD *md)
VALUE ret;
EVP_MD_CTX *ctx;
+ // NOTE: This does not set id_md_holder because this function should
+ // only be called from ossl_engine.c, which will not use any
+ // reference-counted digests.
ret = ossl_digest_alloc(cDigest);
ctx = EVP_MD_CTX_new();
if (!ctx)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
RTYPEDDATA_DATA(ret) = ctx;
if (!EVP_DigestInit_ex(ctx, md, NULL))
- ossl_raise(eDigestError, "Digest initialization failed");
+ ossl_raise(eDigestError, "Digest initialization failed");
return ret;
}
@@ -121,21 +153,22 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
{
EVP_MD_CTX *ctx;
const EVP_MD *md;
- VALUE type, data;
+ VALUE type, data, md_holder;
rb_scan_args(argc, argv, "11", &type, &data);
- md = ossl_evp_get_digestbyname(type);
+ md = ossl_evp_md_fetch(type, &md_holder);
if (!NIL_P(data)) StringValue(data);
TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx);
if (!ctx) {
- RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
- if (!ctx)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
}
if (!EVP_DigestInit_ex(ctx, md, NULL))
- ossl_raise(eDigestError, "Digest initialization failed");
+ ossl_raise(eDigestError, "Digest initialization failed");
+ rb_ivar_set(self, id_md_holder, md_holder);
if (!NIL_P(data)) return ossl_digest_update(self, data);
return self;
@@ -152,14 +185,14 @@ ossl_digest_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1);
if (!ctx1) {
- RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
- if (!ctx1)
- ossl_raise(eDigestError, "EVP_MD_CTX_new");
+ RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
+ if (!ctx1)
+ ossl_raise(eDigestError, "EVP_MD_CTX_new");
}
GetDigest(other, ctx2);
if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
- ossl_raise(eDigestError, NULL);
+ ossl_raise(eDigestError, NULL);
}
return self;
}
@@ -184,8 +217,8 @@ ossl_s_digests(VALUE self)
ary = rb_ary_new();
OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
- add_digest_name_to_ary,
- (void*)ary);
+ add_digest_name_to_ary,
+ (void*)ary);
return ary;
}
@@ -205,7 +238,7 @@ ossl_digest_reset(VALUE self)
GetDigest(self, ctx);
if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) {
- ossl_raise(eDigestError, "Digest initialization failed.");
+ ossl_raise(eDigestError, "Digest initialization failed.");
}
return self;
@@ -235,7 +268,7 @@ ossl_digest_update(VALUE self, VALUE data)
GetDigest(self, ctx);
if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)))
- ossl_raise(eDigestError, "EVP_DigestUpdate");
+ ossl_raise(eDigestError, "EVP_DigestUpdate");
return self;
}
@@ -254,7 +287,7 @@ ossl_digest_finish(VALUE self)
GetDigest(self, ctx);
str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL))
- ossl_raise(eDigestError, "EVP_DigestFinal_ex");
+ ossl_raise(eDigestError, "EVP_DigestFinal_ex");
return str;
}
@@ -332,11 +365,6 @@ ossl_digest_block_length(VALUE self)
void
Init_ossl_digest(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-class: OpenSSL::Digest
*
* OpenSSL::Digest allows you to compute message digests (sometimes
@@ -442,4 +470,6 @@ Init_ossl_digest(void)
rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
rb_define_method(cDigest, "name", ossl_digest_name, 0);
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
}
diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h
index 588a0c6f57..9c3bb2b149 100644
--- a/ext/openssl/ossl_digest.h
+++ b/ext/openssl/ossl_digest.h
@@ -10,7 +10,15 @@
#if !defined(_OSSL_DIGEST_H_)
#define _OSSL_DIGEST_H_
-const EVP_MD *ossl_evp_get_digestbyname(VALUE);
+/*
+ * Gets EVP_MD from a String or an OpenSSL::Digest instance (discouraged, but
+ * still supported for compatibility). A holder object is created if the EVP_MD
+ * is a "fetched" algorithm.
+ */
+const EVP_MD *ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder);
+/*
+ * This is meant for OpenSSL::Engine#digest. EVP_MD must not be a fetched one.
+ */
VALUE ossl_digest_new(const EVP_MD *);
void Init_ossl_digest(void);
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index cb08049a82..a2bcb07ea4 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -16,7 +16,7 @@
TypedData_Wrap_Struct((klass), &ossl_engine_type, 0)
#define SetEngine(obj, engine) do { \
if (!(engine)) { \
- ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (engine); \
} while(0)
@@ -49,12 +49,12 @@ static VALUE eEngineError;
*/
#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \
do{\
- if(!strcmp(#engine_name, RSTRING_PTR(name))){\
- if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
- return Qtrue;\
- else\
- ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
- }\
+ if(!strcmp(#engine_name, RSTRING_PTR(name))){\
+ if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\
+ return Qtrue;\
+ else\
+ ossl_raise(eEngineError, "OPENSSL_init_crypto"); \
+ }\
}while(0)
static void
@@ -66,7 +66,7 @@ ossl_engine_free(void *engine)
static const rb_data_type_t ossl_engine_type = {
"OpenSSL/Engine",
{
- 0, ossl_engine_free,
+ 0, ossl_engine_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -130,12 +130,12 @@ ossl_engine_s_engines(VALUE klass)
ary = rb_ary_new();
for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
- obj = NewEngine(klass);
- /* Need a ref count of two here because of ENGINE_free being
- * called internally by OpenSSL when moving to the next ENGINE
- * and by us when releasing the ENGINE reference */
- ENGINE_up_ref(e);
- SetEngine(obj, e);
+ obj = NewEngine(klass);
+ /* Need a ref count of two here because of ENGINE_free being
+ * called internally by OpenSSL when moving to the next ENGINE
+ * and by us when releasing the ENGINE reference */
+ ENGINE_up_ref(e);
+ SetEngine(obj, e);
rb_ary_push(ary, obj);
}
@@ -163,13 +163,13 @@ ossl_engine_s_by_id(VALUE klass, VALUE id)
ossl_engine_s_load(1, &id, klass);
obj = NewEngine(klass);
if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
- ossl_raise(eEngineError, NULL);
+ ossl_raise(eEngineError, NULL);
SetEngine(obj, e);
if(rb_block_given_p()) rb_yield(obj);
if(!ENGINE_init(e))
- ossl_raise(eEngineError, NULL);
+ ossl_raise(eEngineError, NULL);
ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
- 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
+ 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
ossl_clear_error();
return obj;
@@ -184,7 +184,7 @@ ossl_engine_s_by_id(VALUE klass, VALUE id)
* OpenSSL::Engine.load
* OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
* OpenSSL::Engine.engines.first.id
- * #=> "rsax"
+ * #=> "rsax"
*/
static VALUE
ossl_engine_get_id(VALUE self)
@@ -203,7 +203,7 @@ ossl_engine_get_id(VALUE self)
* OpenSSL::Engine.load
* OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
* OpenSSL::Engine.engines.first.name
- * #=> "RSAX engine support"
+ * #=> "RSAX engine support"
*
*/
static VALUE
@@ -274,11 +274,11 @@ ossl_engine_get_cipher(VALUE self, VALUE name)
* Will raise an EngineError if the digest is unavailable.
*
* e = OpenSSL::Engine.by_id("openssl")
- * #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
+ * #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
* e.digest("SHA1")
- * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
+ * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
* e.digest("zomg")
- * #=> OpenSSL::Engine::EngineError: no such digest `zomg'
+ * #=> OpenSSL::Engine::EngineError: no such digest `zomg'
*/
static VALUE
ossl_engine_get_digest(VALUE self, VALUE name)
@@ -320,7 +320,7 @@ ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
GetEngine(self, e);
pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
if (!pkey) ossl_raise(eEngineError, NULL);
- obj = ossl_pkey_new(pkey);
+ obj = ossl_pkey_wrap(pkey);
OSSL_PKEY_SET_PRIVATE(obj);
return obj;
@@ -350,7 +350,7 @@ ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
if (!pkey) ossl_raise(eEngineError, NULL);
- return ossl_pkey_new(pkey);
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -365,7 +365,7 @@ ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
* your OS.
*
* [All flags] 0xFFFF
- * [No flags] 0x0000
+ * [No flags] 0x0000
*
* See also <openssl/engine.h>
*/
@@ -399,7 +399,7 @@ ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
GetEngine(self, e);
rb_scan_args(argc, argv, "11", &cmd, &val);
ret = ENGINE_ctrl_cmd_string(e, StringValueCStr(cmd),
- NIL_P(val) ? NULL : StringValueCStr(val), 0);
+ NIL_P(val) ? NULL : StringValueCStr(val), 0);
if (!ret) ossl_raise(eEngineError, NULL);
return self;
@@ -409,11 +409,11 @@ static VALUE
ossl_engine_cmd_flag_to_name(int flag)
{
switch(flag){
- case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
- case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
- case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
- case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
- default: return rb_str_new2("UNKNOWN");
+ case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
+ case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
+ case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
+ case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
+ default: return rb_str_new2("UNKNOWN");
}
}
@@ -433,13 +433,13 @@ ossl_engine_get_cmds(VALUE self)
GetEngine(self, e);
ary = rb_ary_new();
if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
- for (p = defn; p->cmd_num > 0; p++){
- tmp = rb_ary_new();
- rb_ary_push(tmp, rb_str_new2(p->cmd_name));
- rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
- rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
- rb_ary_push(ary, tmp);
- }
+ for (p = defn; p->cmd_num > 0; p++){
+ tmp = rb_ary_new();
+ rb_ary_push(tmp, rb_str_new2(p->cmd_name));
+ rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
+ rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
+ rb_ary_push(ary, tmp);
+ }
}
return ary;
@@ -458,7 +458,7 @@ ossl_engine_inspect(VALUE self)
GetEngine(self, e);
return rb_sprintf("#<%"PRIsVALUE" id=\"%s\" name=\"%s\">",
- rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
+ rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
}
#define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
@@ -466,11 +466,6 @@ ossl_engine_inspect(VALUE self)
void
Init_ossl_engine(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index b304827579..ddcc6a5f8d 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -14,7 +14,7 @@
#define GetHMAC(obj, ctx) do { \
TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
+ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
} \
} while (0)
@@ -23,6 +23,7 @@
*/
static VALUE cHMAC;
static VALUE eHMACError;
+static ID id_md_holder;
/*
* Public
@@ -40,7 +41,7 @@ ossl_hmac_free(void *ctx)
static const rb_data_type_t ossl_hmac_type = {
"OpenSSL/HMAC",
{
- 0, ossl_hmac_free,
+ 0, ossl_hmac_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -73,17 +74,17 @@ ossl_hmac_alloc(VALUE klass)
*
* === Example
*
- * key = 'key'
- * instance = OpenSSL::HMAC.new(key, 'SHA1')
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
- * instance.class
- * #=> OpenSSL::HMAC
+ * key = 'key'
+ * instance = OpenSSL::HMAC.new(key, 'SHA1')
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * instance.class
+ * #=> OpenSSL::HMAC
*
* === A note about comparisons
*
* Two instances can be securely compared with #== in constant time:
*
- * other_instance = OpenSSL::HMAC.new('key', 'SHA1')
+ * other_instance = OpenSSL::HMAC.new('key', 'SHA1')
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
* instance == other_instance
* #=> true
@@ -94,19 +95,22 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
{
EVP_MD_CTX *ctx;
EVP_PKEY *pkey;
+ const EVP_MD *md;
+ VALUE md_holder;
GetHMAC(self, ctx);
StringValue(key);
+ md = ossl_evp_md_fetch(digest, &md_holder);
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
(unsigned char *)RSTRING_PTR(key),
RSTRING_LENINT(key));
if (!pkey)
ossl_raise(eHMACError, "EVP_PKEY_new_raw_private_key");
- if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest),
- NULL, pkey) != 1) {
+ if (EVP_DigestSignInit(ctx, NULL, md, NULL, pkey) != 1) {
EVP_PKEY_free(pkey);
ossl_raise(eHMACError, "EVP_DigestSignInit");
}
+ rb_ivar_set(self, id_md_holder, md_holder);
/* Decrement reference counter; EVP_MD_CTX still keeps it */
EVP_PKEY_free(pkey);
@@ -138,13 +142,13 @@ ossl_hmac_copy(VALUE self, VALUE other)
*
* === Example
*
- * first_chunk = 'The quick brown fox jumps '
- * second_chunk = 'over the lazy dog'
+ * first_chunk = 'The quick brown fox jumps '
+ * second_chunk = 'over the lazy dog'
*
- * instance.update(first_chunk)
- * #=> 5b9a8038a65d571076d97fe783989e52278a492a
- * instance.update(second_chunk)
- * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
+ * instance.update(first_chunk)
+ * #=> 5b9a8038a65d571076d97fe783989e52278a492a
+ * instance.update(second_chunk)
+ * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
*
*/
static VALUE
@@ -222,14 +226,14 @@ ossl_hmac_hexdigest(VALUE self)
*
* === Example
*
- * data = "The quick brown fox jumps over the lazy dog"
- * instance = OpenSSL::HMAC.new('key', 'SHA1')
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * data = "The quick brown fox jumps over the lazy dog"
+ * instance = OpenSSL::HMAC.new('key', 'SHA1')
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
*
- * instance.update(data)
- * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
- * instance.reset
- * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
+ * instance.update(data)
+ * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
+ * instance.reset
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
*
*/
static VALUE
@@ -252,11 +256,6 @@ ossl_hmac_reset(VALUE self)
void
Init_ossl_hmac(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Document-class: OpenSSL::HMAC
*
@@ -300,4 +299,6 @@ Init_ossl_hmac(void)
rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
rb_define_alias(cHMAC, "inspect", "hexdigest");
rb_define_alias(cHMAC, "to_s", "hexdigest");
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
}
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index f349939a80..1f28016440 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -35,16 +35,16 @@ static VALUE mKDF, eKDF;
static VALUE
kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
{
- VALUE pass, salt, opts, kwargs[4], str;
+ VALUE pass, salt, opts, kwargs[4], str, md_holder;
static ID kwargs_ids[4];
int iters, len;
const EVP_MD *md;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("iterations");
- kwargs_ids[2] = rb_intern_const("length");
- kwargs_ids[3] = rb_intern_const("hash");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("iterations");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
}
rb_scan_args(argc, argv, "1:", &pass, &opts);
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
@@ -53,14 +53,14 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
salt = StringValue(kwargs[0]);
iters = NUM2INT(kwargs[1]);
len = NUM2INT(kwargs[2]);
- md = ossl_evp_get_digestbyname(kwargs[3]);
+ md = ossl_evp_md_fetch(kwargs[3], &md_holder);
str = rb_str_new(0, len);
if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
- (unsigned char *)RSTRING_PTR(salt),
- RSTRING_LENINT(salt), iters, md, len,
- (unsigned char *)RSTRING_PTR(str)))
- ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
+ (unsigned char *)RSTRING_PTR(salt),
+ RSTRING_LENINT(salt), iters, md, len,
+ (unsigned char *)RSTRING_PTR(str)))
+ ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
return str;
}
@@ -107,11 +107,11 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
uint64_t N, r, p, maxmem;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("N");
- kwargs_ids[2] = rb_intern_const("r");
- kwargs_ids[3] = rb_intern_const("p");
- kwargs_ids[4] = rb_intern_const("length");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("N");
+ kwargs_ids[2] = rb_intern_const("r");
+ kwargs_ids[3] = rb_intern_const("p");
+ kwargs_ids[4] = rb_intern_const("length");
}
rb_scan_args(argc, argv, "1:", &pass, &opts);
rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);
@@ -131,9 +131,9 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
str = rb_str_new(0, len);
if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
- (unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
- N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
- ossl_raise(eKDF, "EVP_PBE_scrypt");
+ (unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
+ N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
+ ossl_raise(eKDF, "EVP_PBE_scrypt");
return str;
}
@@ -172,7 +172,7 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_hkdf(int argc, VALUE *argv, VALUE self)
{
- VALUE ikm, salt, info, opts, kwargs[4], str;
+ VALUE ikm, salt, info, opts, kwargs[4], str, md_holder;
static ID kwargs_ids[4];
int saltlen, ikmlen, infolen;
size_t len;
@@ -180,10 +180,10 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
EVP_PKEY_CTX *pctx;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt");
- kwargs_ids[1] = rb_intern_const("info");
- kwargs_ids[2] = rb_intern_const("length");
- kwargs_ids[3] = rb_intern_const("hash");
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("info");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
}
rb_scan_args(argc, argv, "1:", &ikm, &opts);
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
@@ -196,39 +196,39 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
infolen = RSTRING_LENINT(info);
len = (size_t)NUM2LONG(kwargs[2]);
if (len > LONG_MAX)
- rb_raise(rb_eArgError, "length must be non-negative");
- md = ossl_evp_get_digestbyname(kwargs[3]);
+ rb_raise(rb_eArgError, "length must be non-negative");
+ md = ossl_evp_md_fetch(kwargs[3], &md_holder);
str = rb_str_new(NULL, (long)len);
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
if (!pctx)
- ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
+ ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
if (EVP_PKEY_derive_init(pctx) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_derive_init");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive_init");
}
if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
}
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
- saltlen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
+ saltlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
}
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
- ikmlen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
+ ikmlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
}
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
- infolen) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
+ infolen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
}
if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
- EVP_PKEY_CTX_free(pctx);
- ossl_raise(eKDF, "EVP_PKEY_derive");
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive");
}
rb_str_set_len(str, (long)len);
EVP_PKEY_CTX_free(pctx);
@@ -239,11 +239,6 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
void
Init_ossl_kdf(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Document-module: OpenSSL::KDF
*
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index 445aeeba15..8440c2ee82 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, 0)
#define SetSPKI(obj, spki) do { \
if (!(spki)) { \
- ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (spki); \
} while (0)
#define GetSPKI(obj, spki) do { \
TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \
if (!(spki)) { \
- ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
} \
} while (0)
@@ -48,7 +48,7 @@ ossl_netscape_spki_free(void *spki)
static const rb_data_type_t ossl_netscape_spki_type = {
"OpenSSL/NETSCAPE_SPKI",
{
- 0, ossl_netscape_spki_free,
+ 0, ossl_netscape_spki_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -61,7 +61,7 @@ ossl_spki_alloc(VALUE klass)
obj = NewSPKI(klass);
if (!(spki = NETSCAPE_SPKI_new())) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
SetSPKI(obj, spki);
@@ -83,15 +83,15 @@ ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
const unsigned char *p;
if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
- return self;
+ return self;
}
StringValue(buffer);
if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), RSTRING_LENINT(buffer)))) {
- ossl_clear_error();
- p = (unsigned char *)RSTRING_PTR(buffer);
- if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
- ossl_raise(eSPKIError, NULL);
- }
+ ossl_clear_error();
+ p = (unsigned char *)RSTRING_PTR(buffer);
+ if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
+ ossl_raise(eSPKIError, NULL);
+ }
}
NETSCAPE_SPKI_free(DATA_PTR(self));
SetSPKI(self, spki);
@@ -140,7 +140,7 @@ ossl_spki_to_pem(VALUE self)
GetSPKI(self, spki);
if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
str = ossl_buf2str(data, rb_long2int(strlen(data)));
@@ -162,11 +162,11 @@ ossl_spki_print(VALUE self)
GetSPKI(self, spki);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
if (!NETSCAPE_SPKI_print(out, spki)) {
- BIO_free(out);
- ossl_raise(eSPKIError, NULL);
+ BIO_free(out);
+ ossl_raise(eSPKIError, NULL);
}
return ossl_membio2str(out);
@@ -187,10 +187,10 @@ ossl_spki_get_public_key(VALUE self)
GetSPKI(self, spki);
if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */
- ossl_raise(eSPKIError, NULL);
+ ossl_raise(eSPKIError, NULL);
}
- return ossl_pkey_new(pkey); /* NO DUP - OK */
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -214,7 +214,7 @@ ossl_spki_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!NETSCAPE_SPKI_set_pubkey(spki, pkey))
- ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_set_pubkey");
return key;
}
@@ -230,13 +230,12 @@ ossl_spki_get_challenge(VALUE self)
NETSCAPE_SPKI *spki;
GetSPKI(self, spki);
- if (spki->spkac->challenge->length <= 0) {
- OSSL_Debug("Challenge.length <= 0?");
- return rb_str_new(0, 0);
+ if (ASN1_STRING_length(spki->spkac->challenge) <= 0) {
+ OSSL_Debug("Challenge.length <= 0?");
+ return rb_str_new(0, 0);
}
- return rb_str_new((const char *)spki->spkac->challenge->data,
- spki->spkac->challenge->length);
+ return asn1str_to_str(spki->spkac->challenge);
}
/*
@@ -257,8 +256,8 @@ ossl_spki_set_challenge(VALUE self, VALUE str)
StringValue(str);
GetSPKI(self, spki);
if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str),
- RSTRING_LENINT(str))) {
- ossl_raise(eSPKIError, NULL);
+ RSTRING_LENINT(str))) {
+ ossl_raise(eSPKIError, NULL);
}
return str;
@@ -283,13 +282,13 @@ ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
NETSCAPE_SPKI *spki;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
GetSPKI(self, spki);
- if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
- ossl_raise(eSPKIError, NULL);
- }
+ if (!NETSCAPE_SPKI_sign(spki, pkey, md))
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_sign");
return self;
}
@@ -315,12 +314,12 @@ ossl_spki_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (NETSCAPE_SPKI_verify(spki, pkey)) {
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
case 1:
- return Qtrue;
+ return Qtrue;
default:
- ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
+ ossl_raise(eSPKIError, "NETSCAPE_SPKI_verify");
}
}
@@ -378,11 +377,6 @@ ossl_spki_verify(VALUE self, VALUE key)
void
Init_ossl_ns_spki(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
mNetscape = rb_define_module_under(mOSSL, "Netscape");
eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError);
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c
index cb2f1a62d0..93d8bc8567 100644
--- a/ext/openssl/ossl_ocsp.c
+++ b/ext/openssl/ossl_ocsp.c
@@ -84,7 +84,7 @@ ossl_ocsp_request_free(void *ptr)
static const rb_data_type_t ossl_ocsp_request_type = {
"OpenSSL/OCSP/REQUEST",
{
- 0, ossl_ocsp_request_free,
+ 0, ossl_ocsp_request_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -98,7 +98,7 @@ ossl_ocsp_response_free(void *ptr)
static const rb_data_type_t ossl_ocsp_response_type = {
"OpenSSL/OCSP/RESPONSE",
{
- 0, ossl_ocsp_response_free,
+ 0, ossl_ocsp_response_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -112,7 +112,7 @@ ossl_ocsp_basicresp_free(void *ptr)
static const rb_data_type_t ossl_ocsp_basicresp_type = {
"OpenSSL/OCSP/BASICRESP",
{
- 0, ossl_ocsp_basicresp_free,
+ 0, ossl_ocsp_basicresp_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -126,7 +126,7 @@ ossl_ocsp_singleresp_free(void *ptr)
static const rb_data_type_t ossl_ocsp_singleresp_type = {
"OpenSSL/OCSP/SINGLERESP",
{
- 0, ossl_ocsp_singleresp_free,
+ 0, ossl_ocsp_singleresp_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -140,7 +140,7 @@ ossl_ocsp_certid_free(void *ptr)
static const rb_data_type_t ossl_ocsp_certid_type = {
"OpenSSL/OCSP/CERTID",
{
- 0, ossl_ocsp_certid_free,
+ 0, ossl_ocsp_certid_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -149,10 +149,14 @@ static const rb_data_type_t ossl_ocsp_certid_type = {
* Public
*/
static VALUE
-ossl_ocspcertid_new(OCSP_CERTID *cid)
+ossl_ocspcid_new(const OCSP_CERTID *cid)
{
VALUE obj = NewOCSPCertId(cOCSPCertId);
- SetOCSPCertId(obj, cid);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ OCSP_CERTID *cid_new = OCSP_CERTID_dup((OCSP_CERTID *)cid);
+ if (!cid_new)
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ SetOCSPCertId(obj, cid_new);
return obj;
}
@@ -167,7 +171,7 @@ ossl_ocspreq_alloc(VALUE klass)
obj = NewOCSPReq(klass);
if (!(req = OCSP_REQUEST_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPReq(obj, req);
return obj;
@@ -185,7 +189,7 @@ ossl_ocspreq_initialize_copy(VALUE self, VALUE other)
req_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_REQUEST), req);
if (!req_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPReq(self, req_new);
OCSP_REQUEST_free(req_old);
@@ -211,15 +215,15 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- GetOCSPReq(self, req);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg));
- if (!req_new)
- ossl_raise(eOCSPError, "d2i_OCSP_REQUEST");
- SetOCSPReq(self, req_new);
- OCSP_REQUEST_free(req);
+ GetOCSPReq(self, req);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg));
+ if (!req_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_REQUEST");
+ SetOCSPReq(self, req_new);
+ OCSP_REQUEST_free(req);
}
return self;
@@ -245,13 +249,13 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &val);
if(NIL_P(val)) {
- GetOCSPReq(self, req);
- ret = OCSP_request_add1_nonce(req, NULL, -1);
+ GetOCSPReq(self, req);
+ ret = OCSP_request_add1_nonce(req, NULL, -1);
}
else{
- StringValue(val);
- GetOCSPReq(self, req);
- ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+ StringValue(val);
+ GetOCSPReq(self, req);
+ ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -308,10 +312,10 @@ ossl_ocspreq_add_certid(VALUE self, VALUE certid)
GetOCSPCertId(certid, id);
if (!(id_new = OCSP_CERTID_dup(id)))
- ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
if (!OCSP_request_add0_id(req, id_new)) {
- OCSP_CERTID_free(id_new);
- ossl_raise(eOCSPError, "OCSP_request_add0_id");
+ OCSP_CERTID_free(id_new);
+ ossl_raise(eOCSPError, "OCSP_request_add0_id");
}
return self;
@@ -328,21 +332,19 @@ static VALUE
ossl_ocspreq_get_certid(VALUE self)
{
OCSP_REQUEST *req;
- OCSP_ONEREQ *one;
- OCSP_CERTID *id;
- VALUE ary, tmp;
- int i, count;
GetOCSPReq(self, req);
- count = OCSP_request_onereq_count(req);
- ary = (count > 0) ? rb_ary_new() : Qnil;
- for(i = 0; i < count; i++){
- one = OCSP_request_onereq_get0(req, i);
- tmp = NewOCSPCertId(cOCSPCertId);
- if(!(id = OCSP_CERTID_dup(OCSP_onereq_get0_id(one))))
- ossl_raise(eOCSPError, NULL);
- SetOCSPCertId(tmp, id);
- rb_ary_push(ary, tmp);
+ int count = OCSP_request_onereq_count(req);
+ if (count < 0)
+ ossl_raise(eOCSPError, "OCSP_request_onereq_count");
+ if (count == 0)
+ return Qnil;
+
+ VALUE ary = rb_ary_new_capa(count);
+ for (int i = 0; i < count; i++) {
+ OCSP_ONEREQ *one = OCSP_request_onereq_get0(req, i);
+ OCSP_CERTID *cid = OCSP_onereq_get0_id(one);
+ rb_ary_push(ary, ossl_ocspcid_new(cid));
}
return ary;
@@ -367,7 +369,7 @@ ossl_ocspreq_get_certid(VALUE self)
static VALUE
ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags, digest;
+ VALUE signer_cert, signer_key, certs, flags, digest, md_holder;
OCSP_REQUEST *req;
X509 *signer;
EVP_PKEY *key;
@@ -381,19 +383,17 @@ ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
if (!NIL_P(flags))
- flg = NUM2INT(flags);
- if (NIL_P(digest))
- md = NULL;
- else
- md = ossl_evp_get_digestbyname(digest);
+ flg = NUM2INT(flags);
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
if (NIL_P(certs))
- flg |= OCSP_NOCERTS;
+ flg |= OCSP_NOCERTS;
else
- x509s = ossl_x509_ary2sk(certs);
+ x509s = ossl_x509_ary2sk(certs);
ret = OCSP_request_sign(req, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if (!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret)
+ ossl_raise(eOCSPError, "OCSP_request_sign");
return self;
}
@@ -427,7 +427,7 @@ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
result = OCSP_request_verify(req, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
if (result <= 0)
- ossl_clear_error();
+ ossl_clear_error();
return result > 0 ? Qtrue : Qfalse;
}
@@ -446,11 +446,11 @@ ossl_ocspreq_to_der(VALUE self)
GetOCSPReq(self, req);
if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_OCSP_REQUEST(req, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -494,7 +494,7 @@ ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)
else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */
obj = NewOCSPRes(klass);
if(!(res = OCSP_response_create(st, bs)))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPRes(obj, res);
return obj;
@@ -508,7 +508,7 @@ ossl_ocspres_alloc(VALUE klass)
obj = NewOCSPRes(klass);
if(!(res = OCSP_RESPONSE_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPRes(obj, res);
return obj;
@@ -526,7 +526,7 @@ ossl_ocspres_initialize_copy(VALUE self, VALUE other)
res_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_RESPONSE), res);
if (!res_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPRes(self, res_new);
OCSP_RESPONSE_free(res_old);
@@ -552,15 +552,15 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if(!NIL_P(arg)){
- GetOCSPRes(self, res);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg));
- if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_RESPONSE");
- SetOCSPRes(self, res_new);
- OCSP_RESPONSE_free(res);
+ GetOCSPRes(self, res);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg));
+ if (!res_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_RESPONSE");
+ SetOCSPRes(self, res_new);
+ OCSP_RESPONSE_free(res);
}
return self;
@@ -621,7 +621,7 @@ ossl_ocspres_get_basic(VALUE self)
GetOCSPRes(self, res);
ret = NewOCSPBasicRes(cOCSPBasicRes);
if(!(bs = OCSP_response_get1_basic(res)))
- return Qnil;
+ return Qnil;
SetOCSPBasicRes(ret, bs);
return ret;
@@ -644,11 +644,11 @@ ossl_ocspres_to_der(VALUE self)
GetOCSPRes(self, res);
if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_OCSP_RESPONSE(res, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -665,7 +665,7 @@ ossl_ocspbres_alloc(VALUE klass)
obj = NewOCSPBasicRes(klass);
if(!(bs = OCSP_BASICRESP_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPBasicRes(obj, bs);
return obj;
@@ -683,7 +683,7 @@ ossl_ocspbres_initialize_copy(VALUE self, VALUE other)
bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs);
if (!bs_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPBasicRes(self, bs_new);
OCSP_BASICRESP_free(bs_old);
@@ -708,15 +708,15 @@ ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &arg);
if (!NIL_P(arg)) {
- GetOCSPBasicRes(self, res);
- arg = ossl_to_der_if_possible(arg);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg));
- if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
- SetOCSPBasicRes(self, res_new);
- OCSP_BASICRESP_free(res);
+ GetOCSPBasicRes(self, res);
+ arg = ossl_to_der_if_possible(arg);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg));
+ if (!res_new)
+ ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
+ SetOCSPBasicRes(self, res_new);
+ OCSP_BASICRESP_free(res);
}
return self;
@@ -761,13 +761,13 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "01", &val);
if(NIL_P(val)) {
- GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_add1_nonce(bs, NULL, -1);
+ GetOCSPBasicRes(self, bs);
+ ret = OCSP_basic_add1_nonce(bs, NULL, -1);
}
else{
- StringValue(val);
- GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+ StringValue(val);
+ GetOCSPBasicRes(self, bs);
+ ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -780,12 +780,12 @@ add_status_convert_time(VALUE obj)
ASN1_TIME *time;
if (RB_INTEGER_TYPE_P(obj))
- time = X509_gmtime_adj(NULL, NUM2INT(obj));
+ time = X509_gmtime_adj(NULL, NUM2INT(obj));
else
- time = ossl_x509_time_adjust(NULL, obj);
+ time = ossl_x509_time_adjust(NULL, obj);
if (!time)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
return (VALUE)time;
}
@@ -819,8 +819,8 @@ add_status_convert_time(VALUE obj)
*/
static VALUE
ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
- VALUE reason, VALUE revtime,
- VALUE thisupd, VALUE nextupd, VALUE ext)
+ VALUE reason, VALUE revtime,
+ VALUE thisupd, VALUE nextupd, VALUE ext)
{
OCSP_BASICRESP *bs;
OCSP_SINGLERESP *single;
@@ -834,16 +834,16 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
GetOCSPCertId(cid, id);
st = NUM2INT(status);
if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */
- ext = rb_check_array_type(ext);
- for (i = 0; i < RARRAY_LEN(ext); i++)
- OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);
+ ext = rb_check_array_type(ext);
+ for (i = 0; i < RARRAY_LEN(ext); i++)
+ OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);
}
if (st == V_OCSP_CERTSTATUS_REVOKED) {
- rsn = NUM2INT(reason);
- tmp = rb_protect(add_status_convert_time, revtime, &rstatus);
- if (rstatus) goto err;
- rev = (ASN1_TIME *)tmp;
+ rsn = NUM2INT(reason);
+ tmp = rb_protect(add_status_convert_time, revtime, &rstatus);
+ if (rstatus) goto err;
+ rev = (ASN1_TIME *)tmp;
}
tmp = rb_protect(add_status_convert_time, thisupd, &rstatus);
@@ -851,29 +851,29 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
ths = (ASN1_TIME *)tmp;
if (!NIL_P(nextupd)) {
- tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);
- if (rstatus) goto err;
- nxt = (ASN1_TIME *)tmp;
+ tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);
+ if (rstatus) goto err;
+ nxt = (ASN1_TIME *)tmp;
}
if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){
- error = 1;
- goto err;
+ error = 1;
+ goto err;
}
if(!NIL_P(ext)){
- X509_EXTENSION *x509ext;
-
- for(i = 0; i < RARRAY_LEN(ext); i++){
- x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i));
- if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
- error = 1;
- goto err;
- }
- }
+ X509_EXTENSION *x509ext;
+
+ for(i = 0; i < RARRAY_LEN(ext); i++){
+ x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i));
+ if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
+ error = 1;
+ goto err;
+ }
+ }
}
- err:
+ err:
ASN1_TIME_free(ths);
ASN1_TIME_free(nxt);
ASN1_TIME_free(rev);
@@ -899,48 +899,40 @@ static VALUE
ossl_ocspbres_get_status(VALUE self)
{
OCSP_BASICRESP *bs;
- OCSP_SINGLERESP *single;
- OCSP_CERTID *cid;
- ASN1_TIME *revtime, *thisupd, *nextupd;
- int status, reason;
- X509_EXTENSION *x509ext;
- VALUE ret, ary, ext;
- int count, ext_count, i, j;
GetOCSPBasicRes(self, bs);
- ret = rb_ary_new();
- count = OCSP_resp_count(bs);
- for(i = 0; i < count; i++){
- single = OCSP_resp_get0(bs, i);
- if(!single) continue;
-
- revtime = thisupd = nextupd = NULL;
- status = OCSP_single_get0_status(single, &reason, &revtime,
- &thisupd, &nextupd);
- if(status < 0) continue;
- if(!(cid = OCSP_CERTID_dup((OCSP_CERTID *)OCSP_SINGLERESP_get0_id(single)))) /* FIXME */
- ossl_raise(eOCSPError, NULL);
- ary = rb_ary_new();
- rb_ary_push(ary, ossl_ocspcertid_new(cid));
- rb_ary_push(ary, INT2NUM(status));
- rb_ary_push(ary, INT2NUM(reason));
- rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
- rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
- rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
- ext = rb_ary_new();
- ext_count = OCSP_SINGLERESP_get_ext_count(single);
- for(j = 0; j < ext_count; j++){
- x509ext = OCSP_SINGLERESP_get_ext(single, j);
- rb_ary_push(ext, ossl_x509ext_new(x509ext));
- }
- rb_ary_push(ary, ext);
- rb_ary_push(ret, ary);
+ VALUE ret = rb_ary_new();
+ int count = OCSP_resp_count(bs);
+ for (int i = 0; i < count; i++) {
+ OCSP_SINGLERESP *single = OCSP_resp_get0(bs, i);
+ ASN1_TIME *revtime, *thisupd, *nextupd;
+ int reason;
+
+ int status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd);
+ if (status < 0)
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
+
+ VALUE ary = rb_ary_new();
+ rb_ary_push(ary, ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(single)));
+ rb_ary_push(ary, INT2NUM(status));
+ rb_ary_push(ary, INT2NUM(reason));
+ rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
+ rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
+ rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
+ VALUE ext = rb_ary_new();
+ int ext_count = OCSP_SINGLERESP_get_ext_count(single);
+ for (int j = 0; j < ext_count; j++) {
+ X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j);
+ rb_ary_push(ext, ossl_x509ext_new(x509ext));
+ }
+ rb_ary_push(ary, ext);
+ rb_ary_push(ret, ary);
}
return ret;
}
-static VALUE ossl_ocspsres_new(OCSP_SINGLERESP *);
+static VALUE ossl_ocspsres_new(const OCSP_SINGLERESP *);
/*
* call-seq:
@@ -958,17 +950,10 @@ ossl_ocspbres_get_responses(VALUE self)
GetOCSPBasicRes(self, bs);
count = OCSP_resp_count(bs);
- ret = rb_ary_new2(count);
+ ret = rb_ary_new_capa(count);
for (i = 0; i < count; i++) {
- OCSP_SINGLERESP *sres, *sres_new;
-
- sres = OCSP_resp_get0(bs, i);
- sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
- if (!sres_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
-
- rb_ary_push(ret, ossl_ocspsres_new(sres_new));
+ rb_ary_push(ret, ossl_ocspsres_new(OCSP_resp_get0(bs, i)));
}
return ret;
@@ -986,7 +971,6 @@ static VALUE
ossl_ocspbres_find_response(VALUE self, VALUE target)
{
OCSP_BASICRESP *bs;
- OCSP_SINGLERESP *sres, *sres_new;
OCSP_CERTID *id;
int n;
@@ -994,14 +978,8 @@ ossl_ocspbres_find_response(VALUE self, VALUE target)
GetOCSPBasicRes(self, bs);
if ((n = OCSP_resp_find(bs, id, -1)) == -1)
- return Qnil;
-
- sres = OCSP_resp_get0(bs, n);
- sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
- if (!sres_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
-
- return ossl_ocspsres_new(sres_new);
+ return Qnil;
+ return ossl_ocspsres_new(OCSP_resp_get0(bs, n));
}
/*
@@ -1020,7 +998,7 @@ ossl_ocspbres_find_response(VALUE self, VALUE target)
static VALUE
ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
{
- VALUE signer_cert, signer_key, certs, flags, digest;
+ VALUE signer_cert, signer_key, certs, flags, digest, md_holder;
OCSP_BASICRESP *bs;
X509 *signer;
EVP_PKEY *key;
@@ -1034,19 +1012,17 @@ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
signer = GetX509CertPtr(signer_cert);
key = GetPrivPKeyPtr(signer_key);
if (!NIL_P(flags))
- flg = NUM2INT(flags);
- if (NIL_P(digest))
- md = NULL;
- else
- md = ossl_evp_get_digestbyname(digest);
+ flg = NUM2INT(flags);
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
if (NIL_P(certs))
- flg |= OCSP_NOCERTS;
+ flg |= OCSP_NOCERTS;
else
- x509s = ossl_x509_ary2sk(certs);
+ x509s = ossl_x509_ary2sk(certs);
ret = OCSP_basic_sign(bs, signer, key, md, x509s, flg);
sk_X509_pop_free(x509s, X509_free);
- if (!ret) ossl_raise(eOCSPError, NULL);
+ if (!ret)
+ ossl_raise(eOCSPError, "OCSP_basic_sign");
return self;
}
@@ -1075,7 +1051,7 @@ ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
result = OCSP_basic_verify(bs, x509s, x509st, flg);
sk_X509_pop_free(x509s, X509_free);
if (result <= 0)
- ossl_clear_error();
+ ossl_clear_error();
return result > 0 ? Qtrue : Qfalse;
}
@@ -1096,11 +1072,11 @@ ossl_ocspbres_to_der(VALUE self)
GetOCSPBasicRes(self, res);
if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_BASICRESP(res, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1110,12 +1086,18 @@ ossl_ocspbres_to_der(VALUE self)
* OCSP::SingleResponse
*/
static VALUE
-ossl_ocspsres_new(OCSP_SINGLERESP *sres)
+ossl_ocspsres_new(const OCSP_SINGLERESP *sres)
{
VALUE obj;
+ OCSP_SINGLERESP *sres_new;
obj = NewOCSPSingleRes(cOCSPSingleRes);
- SetOCSPSingleRes(obj, sres);
+ /* OpenSSL 1.1.1 takes a non-const pointer */
+ sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP),
+ (OCSP_SINGLERESP *)sres);
+ if (!sres_new)
+ ossl_raise(eOCSPError, "ASN1_item_dup");
+ SetOCSPSingleRes(obj, sres_new);
return obj;
}
@@ -1128,7 +1110,7 @@ ossl_ocspsres_alloc(VALUE klass)
obj = NewOCSPSingleRes(klass);
if (!(sres = OCSP_SINGLERESP_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPSingleRes(obj, sres);
return obj;
@@ -1153,7 +1135,7 @@ ossl_ocspsres_initialize(VALUE self, VALUE arg)
p = (unsigned char*)RSTRING_PTR(arg);
res_new = d2i_OCSP_SINGLERESP(NULL, &p, RSTRING_LEN(arg));
if (!res_new)
- ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
+ ossl_raise(eOCSPError, "d2i_OCSP_SINGLERESP");
SetOCSPSingleRes(self, res_new);
OCSP_SINGLERESP_free(res);
@@ -1172,7 +1154,7 @@ ossl_ocspsres_initialize_copy(VALUE self, VALUE other)
sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);
if (!sres_new)
- ossl_raise(eOCSPError, "ASN1_item_dup");
+ ossl_raise(eOCSPError, "ASN1_item_dup");
SetOCSPSingleRes(self, sres_new);
OCSP_SINGLERESP_free(sres_old);
@@ -1211,15 +1193,15 @@ ossl_ocspsres_check_validity(int argc, VALUE *argv, VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, &this_update, &next_update);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
ret = OCSP_check_validity(this_update, next_update, nsec, maxsec);
if (ret)
- return Qtrue;
+ return Qtrue;
else {
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
}
}
@@ -1233,12 +1215,9 @@ static VALUE
ossl_ocspsres_get_certid(VALUE self)
{
OCSP_SINGLERESP *sres;
- OCSP_CERTID *id;
GetOCSPSingleRes(self, sres);
- id = OCSP_CERTID_dup((OCSP_CERTID *)OCSP_SINGLERESP_get0_id(sres)); /* FIXME */
-
- return ossl_ocspcertid_new(id);
+ return ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(sres));
}
/*
@@ -1264,7 +1243,7 @@ ossl_ocspsres_get_cert_status(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
return INT2NUM(status);
}
@@ -1283,9 +1262,9 @@ ossl_ocspsres_get_this_update(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, &time, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1304,9 +1283,9 @@ ossl_ocspsres_get_next_update(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, NULL, NULL, &time);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1325,11 +1304,11 @@ ossl_ocspsres_get_revocation_time(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, NULL, &time, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (status != V_OCSP_CERTSTATUS_REVOKED)
- ossl_raise(eOCSPError, "certificate is not revoked");
+ ossl_raise(eOCSPError, "certificate is not revoked");
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -1347,9 +1326,9 @@ ossl_ocspsres_get_revocation_reason(VALUE self)
GetOCSPSingleRes(self, sres);
status = OCSP_single_get0_status(sres, &reason, NULL, NULL, NULL);
if (status < 0)
- ossl_raise(eOCSPError, "OCSP_single_get0_status");
+ ossl_raise(eOCSPError, "OCSP_single_get0_status");
if (status != V_OCSP_CERTSTATUS_REVOKED)
- ossl_raise(eOCSPError, "certificate is not revoked");
+ ossl_raise(eOCSPError, "certificate is not revoked");
return INT2NUM(reason);
}
@@ -1371,8 +1350,8 @@ ossl_ocspsres_get_extensions(VALUE self)
count = OCSP_SINGLERESP_get_ext_count(sres);
ary = rb_ary_new2(count);
for (i = 0; i < count; i++) {
- ext = OCSP_SINGLERESP_get_ext(sres, i);
- rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
+ ext = OCSP_SINGLERESP_get_ext(sres, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */
}
return ary;
@@ -1394,11 +1373,11 @@ ossl_ocspsres_to_der(VALUE self)
GetOCSPSingleRes(self, sres);
if ((len = i2d_OCSP_SINGLERESP(sres, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_SINGLERESP(sres, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1416,7 +1395,7 @@ ossl_ocspcid_alloc(VALUE klass)
obj = NewOCSPCertId(klass);
if(!(id = OCSP_CERTID_new()))
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
SetOCSPCertId(obj, id);
return obj;
@@ -1434,7 +1413,7 @@ ossl_ocspcid_initialize_copy(VALUE self, VALUE other)
cid_new = OCSP_CERTID_dup(cid);
if (!cid_new)
- ossl_raise(eOCSPError, "OCSP_CERTID_dup");
+ ossl_raise(eOCSPError, "OCSP_CERTID_dup");
SetOCSPCertId(self, cid_new);
OCSP_CERTID_free(cid_old);
@@ -1464,27 +1443,28 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
GetOCSPCertId(self, id);
if (rb_scan_args(argc, argv, "12", &subject, &issuer, &digest) == 1) {
- VALUE arg;
- const unsigned char *p;
-
- arg = ossl_to_der_if_possible(subject);
- StringValue(arg);
- p = (unsigned char *)RSTRING_PTR(arg);
- newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg));
- if (!newid)
- ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
+ VALUE arg;
+ const unsigned char *p;
+
+ arg = ossl_to_der_if_possible(subject);
+ StringValue(arg);
+ p = (unsigned char *)RSTRING_PTR(arg);
+ newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg));
+ if (!newid)
+ ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
}
else {
- X509 *x509s, *x509i;
- const EVP_MD *md;
+ X509 *x509s, *x509i;
+ const EVP_MD *md;
+ VALUE md_holder;
- x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
- x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
- md = !NIL_P(digest) ? ossl_evp_get_digestbyname(digest) : NULL;
+ x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
+ x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
- newid = OCSP_cert_to_id(md, x509s, x509i);
- if (!newid)
- ossl_raise(eOCSPError, "OCSP_cert_to_id");
+ newid = OCSP_cert_to_id(md, x509s, x509i);
+ if (!newid)
+ ossl_raise(eOCSPError, "OCSP_cert_to_id");
}
SetOCSPCertId(self, newid);
@@ -1570,8 +1550,9 @@ ossl_ocspcid_get_issuer_name_hash(VALUE self)
GetOCSPCertId(self, id);
OCSP_id_get0_info(&name_hash, NULL, NULL, NULL, id);
- ret = rb_str_new(NULL, name_hash->length * 2);
- ossl_bin2hex(name_hash->data, RSTRING_PTR(ret), name_hash->length);
+ ret = rb_str_new(NULL, ASN1_STRING_length(name_hash) * 2);
+ ossl_bin2hex(ASN1_STRING_get0_data(name_hash), RSTRING_PTR(ret),
+ ASN1_STRING_length(name_hash));
return ret;
}
@@ -1593,8 +1574,9 @@ ossl_ocspcid_get_issuer_key_hash(VALUE self)
GetOCSPCertId(self, id);
OCSP_id_get0_info(NULL, NULL, &key_hash, NULL, id);
- ret = rb_str_new(NULL, key_hash->length * 2);
- ossl_bin2hex(key_hash->data, RSTRING_PTR(ret), key_hash->length);
+ ret = rb_str_new(NULL, ASN1_STRING_length(key_hash) * 2);
+ ossl_bin2hex(ASN1_STRING_get0_data(key_hash), RSTRING_PTR(ret),
+ ASN1_STRING_length(key_hash));
return ret;
}
@@ -1611,19 +1593,10 @@ ossl_ocspcid_get_hash_algorithm(VALUE self)
{
OCSP_CERTID *id;
ASN1_OBJECT *oid;
- BIO *out;
GetOCSPCertId(self, id);
OCSP_id_get0_info(NULL, &oid, NULL, NULL, id);
-
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eOCSPError, "BIO_new");
-
- if (!i2a_ASN1_OBJECT(out, oid)) {
- BIO_free(out);
- ossl_raise(eOCSPError, "i2a_ASN1_OBJECT");
- }
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(oid);
}
/*
@@ -1642,11 +1615,11 @@ ossl_ocspcid_to_der(VALUE self)
GetOCSPCertId(self, id);
if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_OCSP_CERTID(id, &p) <= 0)
- ossl_raise(eOCSPError, NULL);
+ ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -1655,11 +1628,6 @@ ossl_ocspcid_to_der(VALUE self)
void
Init_ossl_ocsp(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* OpenSSL::OCSP implements Online Certificate Status Protocol requests
* and responses.
diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c
index be09eb2071..32b82a881c 100644
--- a/ext/openssl/ossl_pkcs12.c
+++ b/ext/openssl/ossl_pkcs12.c
@@ -42,7 +42,7 @@ ossl_pkcs12_free(void *ptr)
static const rb_data_type_t ossl_pkcs12_type = {
"OpenSSL/PKCS12",
{
- 0, ossl_pkcs12_free,
+ 0, ossl_pkcs12_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -72,7 +72,7 @@ ossl_pkcs12_initialize_copy(VALUE self, VALUE other)
p12_new = ASN1_dup((i2d_of_void *)i2d_PKCS12, (d2i_of_void *)d2i_PKCS12, (char *)p12);
if (!p12_new)
- ossl_raise(ePKCS12Error, "ASN1_dup");
+ ossl_raise(ePKCS12Error, "ASN1_dup");
SetPKCS12(self, p12_new);
PKCS12_free(p12_old);
@@ -122,11 +122,11 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
/* TODO: make a VALUE to nid function */
if (!NIL_P(key_nid)) {
if ((nkey = OBJ_txt2nid(StringValueCStr(key_nid))) == NID_undef)
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, key_nid);
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, key_nid);
}
if (!NIL_P(cert_nid)) {
if ((ncert = OBJ_txt2nid(StringValueCStr(cert_nid))) == NID_undef)
- ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, cert_nid);
+ ossl_raise(rb_eArgError, "Unknown PBE algorithm %"PRIsVALUE, cert_nid);
}
if (!NIL_P(key_iter))
kiter = NUM2INT(key_iter);
@@ -161,9 +161,9 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
}
static VALUE
-ossl_pkey_new_i(VALUE arg)
+ossl_pkey_wrap_i(VALUE arg)
{
- return ossl_pkey_new((EVP_PKEY *)arg);
+ return ossl_pkey_wrap((EVP_PKEY *)arg);
}
static VALUE
@@ -209,18 +209,18 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
pkey = cert = ca = Qnil;
if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s))
- ossl_raise(ePKCS12Error, "PKCS12_parse");
+ ossl_raise(ePKCS12Error, "PKCS12_parse");
if (key) {
- pkey = rb_protect(ossl_pkey_new_i, (VALUE)key, &st);
- if (st) goto err;
+ pkey = rb_protect(ossl_pkey_wrap_i, (VALUE)key, &st);
+ if (st) goto err;
}
if (x509) {
- cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st);
- if (st) goto err;
+ cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st);
+ if (st) goto err;
}
if (x509s) {
- ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st);
- if (st) goto err;
+ ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st);
+ if (st) goto err;
}
err:
@@ -244,11 +244,11 @@ ossl_pkcs12_to_der(VALUE self)
GetPKCS12(self, p12);
if((len = i2d_PKCS12(p12, NULL)) <= 0)
- ossl_raise(ePKCS12Error, NULL);
+ ossl_raise(ePKCS12Error, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_PKCS12(p12, &p) <= 0)
- ossl_raise(ePKCS12Error, NULL);
+ ossl_raise(ePKCS12Error, NULL);
ossl_str_adjust(str, p);
return str;
@@ -271,7 +271,7 @@ static VALUE
pkcs12_set_mac(int argc, VALUE *argv, VALUE self)
{
PKCS12 *p12;
- VALUE pass, salt, iter, md_name;
+ VALUE pass, salt, iter, md_name, md_holder = Qnil;
int iter_i = 0;
const EVP_MD *md_type = NULL;
@@ -285,7 +285,7 @@ pkcs12_set_mac(int argc, VALUE *argv, VALUE self)
if (!NIL_P(iter))
iter_i = NUM2INT(iter);
if (!NIL_P(md_name))
- md_type = ossl_evp_get_digestbyname(md_name);
+ md_type = ossl_evp_md_fetch(md_name, &md_holder);
if (!PKCS12_set_mac(p12, RSTRING_PTR(pass), RSTRING_LENINT(pass),
!NIL_P(salt) ? (unsigned char *)RSTRING_PTR(salt) : NULL,
@@ -300,11 +300,6 @@ void
Init_ossl_pkcs12(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/*
* Defines a file format commonly used to store private keys with
* accompanying public key certificates, protected with a password-based
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c
index 4d719c96da..6e51fd42b9 100644
--- a/ext/openssl/ossl_pkcs7.c
+++ b/ext/openssl/ossl_pkcs7.c
@@ -28,14 +28,14 @@
TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, 0)
#define SetPKCS7si(obj, p7si) do { \
if (!(p7si)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (p7si); \
} while (0)
#define GetPKCS7si(obj, p7si) do { \
TypedData_Get_Struct((obj), PKCS7_SIGNER_INFO, &ossl_pkcs7_signer_info_type, (p7si)); \
if (!(p7si)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
} \
} while (0)
@@ -43,14 +43,14 @@
TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, 0)
#define SetPKCS7ri(obj, p7ri) do { \
if (!(p7ri)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (p7ri); \
} while (0)
#define GetPKCS7ri(obj, p7ri) do { \
TypedData_Get_Struct((obj), PKCS7_RECIP_INFO, &ossl_pkcs7_recip_info_type, (p7ri)); \
if (!(p7ri)) { \
- ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
} \
} while (0)
@@ -68,6 +68,7 @@ static VALUE cPKCS7;
static VALUE cPKCS7Signer;
static VALUE cPKCS7Recipient;
static VALUE ePKCS7Error;
+static ID id_md_holder, id_cipher_holder;
static void
ossl_pkcs7_free(void *ptr)
@@ -78,7 +79,7 @@ ossl_pkcs7_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_type = {
"OpenSSL/PKCS7",
{
- 0, ossl_pkcs7_free,
+ 0, ossl_pkcs7_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -106,7 +107,7 @@ ossl_pkcs7_signer_info_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_signer_info_type = {
"OpenSSL/PKCS7/SIGNER_INFO",
{
- 0, ossl_pkcs7_signer_info_free,
+ 0, ossl_pkcs7_signer_info_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -120,7 +121,7 @@ ossl_pkcs7_recip_info_free(void *ptr)
static const rb_data_type_t ossl_pkcs7_recip_info_type = {
"OpenSSL/PKCS7/RECIP_INFO",
{
- 0, ossl_pkcs7_recip_info_free,
+ 0, ossl_pkcs7_recip_info_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -143,23 +144,32 @@ ossl_PKCS7_SIGNER_INFO_dup(PKCS7_SIGNER_INFO *si)
}
static PKCS7_RECIP_INFO *
-ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *si)
+ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *ri)
{
- return ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
- (d2i_of_void *)d2i_PKCS7_RECIP_INFO,
- si);
+ PKCS7_RECIP_INFO *ri_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
+ (d2i_of_void *)d2i_PKCS7_RECIP_INFO,
+ ri);
+ if (ri_new && ri->cert) {
+ if (!X509_up_ref(ri->cert)) {
+ PKCS7_RECIP_INFO_free(ri_new);
+ return NULL;
+ }
+ ri_new->cert = ri->cert;
+ }
+ return ri_new;
}
static VALUE
ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
{
- PKCS7_SIGNER_INFO *pkcs7;
+ PKCS7_SIGNER_INFO *p7si_new;
VALUE obj;
obj = NewPKCS7si(cPKCS7Signer);
- pkcs7 = p7si ? ossl_PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new();
- if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
- SetPKCS7si(obj, pkcs7);
+ p7si_new = ossl_PKCS7_SIGNER_INFO_dup(p7si);
+ if (!p7si_new)
+ ossl_raise(ePKCS7Error, "ASN1_dup");
+ SetPKCS7si(obj, p7si_new);
return obj;
}
@@ -167,13 +177,14 @@ ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
static VALUE
ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri)
{
- PKCS7_RECIP_INFO *pkcs7;
+ PKCS7_RECIP_INFO *p7ri_new;
VALUE obj;
obj = NewPKCS7ri(cPKCS7Recipient);
- pkcs7 = p7ri ? ossl_PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new();
- if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
- SetPKCS7ri(obj, pkcs7);
+ p7ri_new = ossl_PKCS7_RECIP_INFO_dup(p7ri);
+ if (!p7ri_new)
+ ossl_raise(ePKCS7Error,"ASN1_dup");
+ SetPKCS7ri(obj, p7ri_new);
return obj;
}
@@ -227,7 +238,7 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);
GetPKCS7(pkcs7, p7);
if(!NIL_P(data) && PKCS7_is_detached(p7))
- flg |= PKCS7_DETACHED;
+ flg |= PKCS7_DETACHED;
in = NIL_P(data) ? NULL : ossl_obj2bio(&data);
if(!(out = BIO_new(BIO_s_mem()))){
BIO_free(in);
@@ -268,16 +279,16 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
in = ossl_obj2bio(&data);
if(NIL_P(certs)) x509s = NULL;
else{
- x509s = ossl_protect_x509_ary2sk(certs, &status);
- if(status){
- BIO_free(in);
- rb_jump_tag(status);
- }
+ x509s = ossl_protect_x509_ary2sk(certs, &status);
+ if(status){
+ BIO_free(in);
+ rb_jump_tag(status);
+ }
}
if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7(ret, pkcs7);
ossl_pkcs7_set_data(ret, data);
@@ -302,7 +313,7 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
static VALUE
ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
{
- VALUE certs, data, cipher, flags;
+ VALUE certs, data, cipher, flags, cipher_holder;
STACK_OF(X509) *x509s;
BIO *in;
const EVP_CIPHER *ciph;
@@ -316,23 +327,24 @@ ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
"cipher must be specified. Before version 3.3, " \
"the default cipher was RC2-40-CBC.");
}
- ciph = ossl_evp_get_cipherbyname(cipher);
+ ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
ret = NewPKCS7(cPKCS7);
in = ossl_obj2bio(&data);
x509s = ossl_protect_x509_ary2sk(certs, &status);
if(status){
- BIO_free(in);
- rb_jump_tag(status);
+ BIO_free(in);
+ rb_jump_tag(status);
}
if (!(p7 = PKCS7_encrypt(x509s, in, ciph, flg))) {
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
BIO_free(in);
SetPKCS7(ret, p7);
ossl_pkcs7_set_data(ret, data);
+ rb_ivar_set(ret, id_cipher_holder, cipher_holder);
sk_X509_pop_free(x509s, X509_free);
return ret;
@@ -346,7 +358,7 @@ ossl_pkcs7_alloc(VALUE klass)
obj = NewPKCS7(klass);
if (!(pkcs7 = PKCS7_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7(obj, pkcs7);
@@ -368,7 +380,7 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
VALUE arg;
if(rb_scan_args(argc, argv, "01", &arg) == 0)
- return self;
+ return self;
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
p7 = d2i_PKCS7_bio(in, NULL);
@@ -378,10 +390,10 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
}
BIO_free(in);
if (!p7)
- ossl_raise(rb_eArgError, "Could not parse the PKCS7");
+ ossl_raise(ePKCS7Error, "Could not parse the PKCS7");
if (!p7->d.ptr) {
PKCS7_free(p7);
- ossl_raise(rb_eArgError, "No content in PKCS7");
+ ossl_raise(ePKCS7Error, "No content in PKCS7");
}
RTYPEDDATA_DATA(self) = p7;
@@ -406,7 +418,7 @@ ossl_pkcs7_copy(VALUE self, VALUE other)
pkcs7 = PKCS7_dup(b);
if (!pkcs7) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
DATA_PTR(self) = pkcs7;
PKCS7_free(a);
@@ -438,13 +450,13 @@ ossl_pkcs7_sym2typeid(VALUE sym)
RSTRING_GETMEM(sym, s, l);
for(i = 0; ; i++){
- if(i == numberof(p7_type_tab))
- ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym);
- if(strlen(p7_type_tab[i].name) != l) continue;
- if(strcmp(p7_type_tab[i].name, s) == 0){
- ret = p7_type_tab[i].nid;
- break;
- }
+ if(i == numberof(p7_type_tab))
+ ossl_raise(ePKCS7Error, "unknown type \"%"PRIsVALUE"\"", sym);
+ if(strlen(p7_type_tab[i].name) != l) continue;
+ if(strcmp(p7_type_tab[i].name, s) == 0){
+ ret = p7_type_tab[i].nid;
+ break;
+ }
}
return ret;
@@ -461,7 +473,7 @@ ossl_pkcs7_set_type(VALUE self, VALUE type)
GetPKCS7(self, p7);
if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
return type;
}
@@ -477,15 +489,15 @@ ossl_pkcs7_get_type(VALUE self)
GetPKCS7(self, p7);
if(PKCS7_type_is_signed(p7))
- return ID2SYM(rb_intern("signed"));
+ return ID2SYM(rb_intern("signed"));
if(PKCS7_type_is_encrypted(p7))
- return ID2SYM(rb_intern("encrypted"));
+ return ID2SYM(rb_intern("encrypted"));
if(PKCS7_type_is_enveloped(p7))
- return ID2SYM(rb_intern("enveloped"));
+ return ID2SYM(rb_intern("enveloped"));
if(PKCS7_type_is_signedAndEnveloped(p7))
- return ID2SYM(rb_intern("signedAndEnveloped"));
+ return ID2SYM(rb_intern("signedAndEnveloped"));
if(PKCS7_type_is_data(p7))
- return ID2SYM(rb_intern("data"));
+ return ID2SYM(rb_intern("data"));
return Qnil;
}
@@ -496,9 +508,9 @@ ossl_pkcs7_set_detached(VALUE self, VALUE flag)
GetPKCS7(self, p7);
if(flag != Qtrue && flag != Qfalse)
- ossl_raise(ePKCS7Error, "must specify a boolean");
+ ossl_raise(ePKCS7Error, "must specify a boolean");
if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
return flag;
}
@@ -508,6 +520,8 @@ ossl_pkcs7_get_detached(VALUE self)
{
PKCS7 *p7;
GetPKCS7(self, p7);
+ if (!PKCS7_type_is_signed(p7))
+ return Qfalse;
return PKCS7_get_detached(p7) ? Qtrue : Qfalse;
}
@@ -523,11 +537,14 @@ static VALUE
ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
{
PKCS7 *pkcs7;
+ const EVP_CIPHER *ciph;
+ VALUE cipher_holder;
GetPKCS7(self, pkcs7);
- if (!PKCS7_set_cipher(pkcs7, ossl_evp_get_cipherbyname(cipher))) {
- ossl_raise(ePKCS7Error, NULL);
- }
+ ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ if (!PKCS7_set_cipher(pkcs7, ciph))
+ ossl_raise(ePKCS7Error, "PKCS7_set_cipher");
+ rb_ivar_set(self, id_cipher_holder, cipher_holder);
return cipher;
}
@@ -567,8 +584,8 @@ ossl_pkcs7_get_signer(VALUE self)
num = sk_PKCS7_SIGNER_INFO_num(sk);
ary = rb_ary_new_capa(num);
for (i=0; i<num; i++) {
- PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
- rb_ary_push(ary, ossl_pkcs7si_new(si));
+ PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
+ rb_ary_push(ary, ossl_pkcs7si_new(si));
}
return ary;
@@ -605,9 +622,9 @@ ossl_pkcs7_get_recipient(VALUE self)
GetPKCS7(self, pkcs7);
if (PKCS7_type_is_enveloped(pkcs7))
- sk = pkcs7->d.enveloped->recipientinfo;
+ sk = pkcs7->d.enveloped->recipientinfo;
else if (PKCS7_type_is_signedAndEnveloped(pkcs7))
- sk = pkcs7->d.signed_and_enveloped->recipientinfo;
+ sk = pkcs7->d.signed_and_enveloped->recipientinfo;
else sk = NULL;
if (!sk) return rb_ary_new();
num = sk_PKCS7_RECIP_INFO_num(sk);
@@ -629,7 +646,7 @@ ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
GetPKCS7(self, pkcs7);
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
if (!PKCS7_add_certificate(pkcs7, x509)){
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -645,13 +662,13 @@ pkcs7_get_certs(VALUE self)
GetPKCS7(self, pkcs7);
i = OBJ_obj2nid(pkcs7->type);
switch(i){
- case NID_pkcs7_signed:
+ case NID_pkcs7_signed:
certs = pkcs7->d.sign->cert;
break;
- case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_signedAndEnveloped:
certs = pkcs7->d.signed_and_enveloped->cert;
break;
- default:
+ default:
certs = NULL;
}
@@ -668,13 +685,13 @@ pkcs7_get_crls(VALUE self)
GetPKCS7(self, pkcs7);
i = OBJ_obj2nid(pkcs7->type);
switch(i){
- case NID_pkcs7_signed:
+ case NID_pkcs7_signed:
crls = pkcs7->d.sign->crl;
break;
- case NID_pkcs7_signedAndEnveloped:
+ case NID_pkcs7_signedAndEnveloped:
crls = pkcs7->d.signed_and_enveloped->crl;
break;
- default:
+ default:
crls = NULL;
}
@@ -721,7 +738,7 @@ ossl_pkcs7_add_crl(VALUE self, VALUE crl)
GetPKCS7(self, pkcs7); /* NO DUP needed! */
x509crl = GetX509CRLPtr(crl);
if (!PKCS7_add_crl(pkcs7, x509crl)) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -768,7 +785,6 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
BIO *in, *out;
PKCS7 *p7;
VALUE data;
- const char *msg;
GetPKCS7(self, p7);
rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags);
@@ -778,28 +794,30 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
in = NIL_P(indata) ? NULL : ossl_obj2bio(&indata);
if(NIL_P(certs)) x509s = NULL;
else{
- x509s = ossl_protect_x509_ary2sk(certs, &status);
- if(status){
- BIO_free(in);
- rb_jump_tag(status);
- }
+ x509s = ossl_protect_x509_ary2sk(certs, &status);
+ if(status){
+ BIO_free(in);
+ rb_jump_tag(status);
+ }
}
if(!(out = BIO_new(BIO_s_mem()))){
- BIO_free(in);
- sk_X509_pop_free(x509s, X509_free);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(in);
+ sk_X509_pop_free(x509s, X509_free);
+ ossl_raise(ePKCS7Error, NULL);
}
ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
BIO_free(in);
sk_X509_pop_free(x509s, X509_free);
- if (ok < 0) ossl_raise(ePKCS7Error, "PKCS7_verify");
- msg = ERR_reason_error_string(ERR_peek_error());
- ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
- ossl_clear_error();
data = ossl_membio2str(out);
ossl_pkcs7_set_data(self, data);
-
- return (ok == 1) ? Qtrue : Qfalse;
+ if (ok != 1) {
+ const char *msg = ERR_reason_error_string(ERR_peek_error());
+ ossl_pkcs7_set_err_string(self, msg ? rb_str_new_cstr(msg) : Qnil);
+ ossl_clear_error();
+ return Qfalse;
+ }
+ ossl_pkcs7_set_err_string(self, Qnil);
+ return Qtrue;
}
static VALUE
@@ -819,10 +837,10 @@ ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
GetPKCS7(self, p7);
if(!(out = BIO_new(BIO_s_mem())))
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
if(!PKCS7_decrypt(p7, key, x509, out, flg)){
- BIO_free(out);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(out);
+ ossl_raise(ePKCS7Error, NULL);
}
str = ossl_membio2str(out); /* out will be free */
@@ -835,30 +853,38 @@ ossl_pkcs7_add_data(VALUE self, VALUE data)
PKCS7 *pkcs7;
BIO *out, *in;
char buf[4096];
- int len;
+ int len, ret;
GetPKCS7(self, pkcs7);
- if(PKCS7_type_is_signed(pkcs7)){
- if(!PKCS7_content_new(pkcs7, NID_pkcs7_data))
- ossl_raise(ePKCS7Error, NULL);
+ if (PKCS7_type_is_signed(pkcs7)) {
+ if (!PKCS7_content_new(pkcs7, NID_pkcs7_data))
+ ossl_raise(ePKCS7Error, "PKCS7_content_new");
}
in = ossl_obj2bio(&data);
- if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err;
- for(;;){
- if((len = BIO_read(in, buf, sizeof(buf))) <= 0)
- break;
- if(BIO_write(out, buf, len) != len)
- goto err;
+ if (!(out = PKCS7_dataInit(pkcs7, NULL))) {
+ BIO_free(in);
+ ossl_raise(ePKCS7Error, "PKCS7_dataInit");
}
- if(!PKCS7_dataFinal(pkcs7, out)) goto err;
- ossl_pkcs7_set_data(self, Qnil);
-
- err:
+ for (;;) {
+ if ((len = BIO_read(in, buf, sizeof(buf))) <= 0)
+ break;
+ if (BIO_write(out, buf, len) != len) {
+ BIO_free_all(out);
+ BIO_free(in);
+ ossl_raise(ePKCS7Error, "BIO_write");
+ }
+ }
+ if (BIO_flush(out) <= 0) {
+ BIO_free_all(out);
+ BIO_free(in);
+ ossl_raise(ePKCS7Error, "BIO_flush");
+ }
+ ret = PKCS7_dataFinal(pkcs7, out);
BIO_free_all(out);
BIO_free(in);
- if(ERR_peek_error()){
- ossl_raise(ePKCS7Error, NULL);
- }
+ if (!ret)
+ ossl_raise(ePKCS7Error, "PKCS7_dataFinal");
+ ossl_pkcs7_set_data(self, Qnil);
return data;
}
@@ -873,11 +899,11 @@ ossl_pkcs7_to_der(VALUE self)
GetPKCS7(self, pkcs7);
if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_PKCS7(pkcs7, &p) <= 0)
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
ossl_str_adjust(str, p);
return str;
@@ -911,11 +937,11 @@ ossl_pkcs7_to_pem(VALUE self)
GetPKCS7(self, pkcs7);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
if (!PEM_write_bio_PKCS7(out, pkcs7)) {
- BIO_free(out);
- ossl_raise(ePKCS7Error, NULL);
+ BIO_free(out);
+ ossl_raise(ePKCS7Error, NULL);
}
str = ossl_membio2str(out);
@@ -933,7 +959,7 @@ ossl_pkcs7si_alloc(VALUE klass)
obj = NewPKCS7si(klass);
if (!(p7si = PKCS7_SIGNER_INFO_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7si(obj, p7si);
@@ -947,14 +973,15 @@ ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)
EVP_PKEY *pkey;
X509 *x509;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
GetPKCS7si(self, p7si);
- if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md))) {
- ossl_raise(ePKCS7Error, NULL);
- }
+ if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md)))
+ ossl_raise(ePKCS7Error, "PKCS7_SIGNER_INFO_set");
+ rb_ivar_set(self, id_md_holder, md_holder);
return self;
}
@@ -988,10 +1015,10 @@ ossl_pkcs7si_get_signed_time(VALUE self)
GetPKCS7si(self, p7si);
if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
if (asn1obj->type == V_ASN1_UTCTIME) {
- return asn1time_to_time(asn1obj->value.utctime);
+ return asn1time_to_time(asn1obj->value.utctime);
}
/*
* OR
@@ -1013,7 +1040,7 @@ ossl_pkcs7ri_alloc(VALUE klass)
obj = NewPKCS7ri(klass);
if (!(p7ri = PKCS7_RECIP_INFO_new())) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
SetPKCS7ri(obj, p7ri);
@@ -1029,7 +1056,7 @@ ossl_pkcs7ri_initialize(VALUE self, VALUE cert)
x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
GetPKCS7ri(self, p7ri);
if (!PKCS7_RECIP_INFO_set(p7ri, x509)) {
- ossl_raise(ePKCS7Error, NULL);
+ ossl_raise(ePKCS7Error, NULL);
}
return self;
@@ -1072,11 +1099,6 @@ void
Init_ossl_pkcs7(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
@@ -1140,4 +1162,7 @@ Init_ossl_pkcs7(void)
DefPKCS7Const(BINARY);
DefPKCS7Const(NOATTR);
DefPKCS7Const(NOSMIMECAP);
+
+ id_md_holder = rb_intern_const("EVP_MD_holder");
+ id_cipher_holder = rb_intern_const("EVP_CIPHER_holder");
}
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index dc83255f0e..d2fd5b29c3 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -33,13 +33,13 @@ ossl_evp_pkey_free(void *ptr)
const rb_data_type_t ossl_evp_pkey_type = {
"OpenSSL/EVP_PKEY",
{
- 0, ossl_evp_pkey_free,
+ 0, ossl_evp_pkey_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static VALUE
-pkey_new0(VALUE arg)
+pkey_wrap0(VALUE arg)
{
EVP_PKEY *pkey = (EVP_PKEY *)arg;
VALUE klass, obj;
@@ -65,15 +65,15 @@ pkey_new0(VALUE arg)
}
VALUE
-ossl_pkey_new(EVP_PKEY *pkey)
+ossl_pkey_wrap(EVP_PKEY *pkey)
{
VALUE obj;
int status;
- obj = rb_protect(pkey_new0, (VALUE)pkey, &status);
+ obj = rb_protect(pkey_wrap0, (VALUE)pkey, &status);
if (status) {
- EVP_PKEY_free(pkey);
- rb_jump_tag(status);
+ EVP_PKEY_free(pkey);
+ rb_jump_tag(status);
}
return obj;
@@ -94,7 +94,8 @@ ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
selection, NULL, NULL);
if (!dctx)
goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
+ if (selection == EVP_PKEY_KEYPAIR &&
+ OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
ppass) != 1)
goto out;
while (1) {
@@ -187,23 +188,23 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
EVP_PKEY *pkey;
if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
/* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
- goto out;
+ goto out;
OSSL_BIO_reset(bio);
if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
- goto out;
+ goto out;
out:
return pkey;
@@ -238,8 +239,8 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
BIO_free(bio);
if (!pkey)
- ossl_raise(ePKeyError, "Could not parse PKey");
- return ossl_pkey_new(pkey);
+ ossl_raise(ePKeyError, "Could not parse PKey");
+ return ossl_pkey_wrap(pkey);
}
static VALUE
@@ -443,7 +444,7 @@ pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
}
}
- return ossl_pkey_new(gen_arg.pkey);
+ return ossl_pkey_wrap(gen_arg.pkey);
}
/*
@@ -507,7 +508,7 @@ ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
void
ossl_pkey_check_public_key(const EVP_PKEY *pkey)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
if (EVP_PKEY_missing_parameters(pkey))
ossl_raise(ePKeyError, "parameters missing");
#else
@@ -515,34 +516,34 @@ ossl_pkey_check_public_key(const EVP_PKEY *pkey)
const BIGNUM *n, *e, *pubkey;
if (EVP_PKEY_missing_parameters(pkey))
- ossl_raise(ePKeyError, "parameters missing");
+ ossl_raise(ePKeyError, "parameters missing");
ptr = EVP_PKEY_get0(pkey);
switch (EVP_PKEY_base_id(pkey)) {
case EVP_PKEY_RSA:
- RSA_get0_key(ptr, &n, &e, NULL);
- if (n && e)
- return;
- break;
+ RSA_get0_key(ptr, &n, &e, NULL);
+ if (n && e)
+ return;
+ break;
case EVP_PKEY_DSA:
- DSA_get0_key(ptr, &pubkey, NULL);
- if (pubkey)
- return;
- break;
+ DSA_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
case EVP_PKEY_DH:
- DH_get0_key(ptr, &pubkey, NULL);
- if (pubkey)
- return;
- break;
+ DH_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
#if !defined(OPENSSL_NO_EC)
case EVP_PKEY_EC:
- if (EC_KEY_get0_public_key(ptr))
- return;
- break;
+ if (EC_KEY_get0_public_key(ptr))
+ return;
+ break;
#endif
default:
- /* unsupported type; assuming ok */
- return;
+ /* unsupported type; assuming ok */
+ return;
}
ossl_raise(ePKeyError, "public key missing");
#endif
@@ -609,7 +610,7 @@ static VALUE
ossl_pkey_initialize(VALUE self)
{
if (rb_obj_is_instance_of(self, cPKey)) {
- ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
+ ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
}
return self;
}
@@ -635,6 +636,29 @@ ossl_pkey_initialize_copy(VALUE self, VALUE other)
}
#endif
+#ifndef OSSL_USE_PROVIDER
+static int
+lookup_pkey_type(VALUE type)
+{
+ const EVP_PKEY_ASN1_METHOD *ameth;
+ int pkey_id;
+
+ StringValue(type);
+ /*
+ * XXX: EVP_PKEY_asn1_find_str() looks up a PEM type string. Should we use
+ * OBJ_txt2nid() instead (and then somehow check if the NID is an acceptable
+ * EVP_PKEY type)?
+ * It is probably fine, though, since it can handle all algorithms that
+ * support raw keys in 1.1.1: { X25519, X448, ED25519, ED448, HMAC }.
+ */
+ ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
+ if (!ameth)
+ ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
+ EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
+ return pkey_id;
+}
+#endif
+
/*
* call-seq:
* OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey
@@ -646,24 +670,25 @@ static VALUE
ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)
{
EVP_PKEY *pkey;
- const EVP_PKEY_ASN1_METHOD *ameth;
- int pkey_id;
size_t keylen;
- StringValue(type);
StringValue(key);
- ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
- if (!ameth)
- ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
- EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
-
keylen = RSTRING_LEN(key);
+#ifdef OSSL_USE_PROVIDER
+ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, StringValueCStr(type), NULL,
+ (unsigned char *)RSTRING_PTR(key),
+ keylen);
+ if (!pkey)
+ ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key_ex");
+#else
+ int pkey_id = lookup_pkey_type(type);
pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
if (!pkey)
ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key");
+#endif
- return ossl_pkey_new(pkey);
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -677,24 +702,25 @@ static VALUE
ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)
{
EVP_PKEY *pkey;
- const EVP_PKEY_ASN1_METHOD *ameth;
- int pkey_id;
size_t keylen;
- StringValue(type);
StringValue(key);
- ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
- if (!ameth)
- ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
- EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
-
keylen = RSTRING_LEN(key);
+#ifdef OSSL_USE_PROVIDER
+ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, StringValueCStr(type), NULL,
+ (unsigned char *)RSTRING_PTR(key),
+ keylen);
+ if (!pkey)
+ ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key_ex");
+#else
+ int pkey_id = lookup_pkey_type(type);
pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
if (!pkey)
ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key");
+#endif
- return ossl_pkey_new(pkey);
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -711,6 +737,10 @@ ossl_pkey_oid(VALUE self)
GetPKey(self, pkey);
nid = EVP_PKEY_id(pkey);
+#ifdef OSSL_USE_PROVIDER
+ if (nid == EVP_PKEY_KEYMGMT)
+ ossl_raise(ePKeyError, "EVP_PKEY_id");
+#endif
return rb_str_new_cstr(OBJ_nid2sn(nid));
}
@@ -724,13 +754,23 @@ static VALUE
ossl_pkey_inspect(VALUE self)
{
EVP_PKEY *pkey;
- int nid;
GetPKey(self, pkey);
- nid = EVP_PKEY_id(pkey);
- return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>",
- rb_class_name(CLASS_OF(self)), (void *)self,
- OBJ_nid2sn(nid));
+ VALUE str = rb_sprintf("#<%"PRIsVALUE":%p",
+ rb_obj_class(self), (void *)self);
+ int nid = EVP_PKEY_id(pkey);
+#ifdef OSSL_USE_PROVIDER
+ if (nid != EVP_PKEY_KEYMGMT)
+#endif
+ rb_str_catf(str, " oid=%s", OBJ_nid2sn(nid));
+#ifdef OSSL_USE_PROVIDER
+ rb_str_catf(str, " type_name=%s", EVP_PKEY_get0_type_name(pkey));
+ const OSSL_PROVIDER *prov = EVP_PKEY_get0_provider(pkey);
+ if (prov)
+ rb_str_catf(str, " provider=%s", OSSL_PROVIDER_get0_name(prov));
+#endif
+ rb_str_catf(str, ">");
+ return str;
}
/*
@@ -774,33 +814,33 @@ VALUE
ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
{
EVP_PKEY *pkey;
- VALUE cipher, pass;
+ VALUE cipher, pass, cipher_holder;
const EVP_CIPHER *enc = NULL;
BIO *bio;
GetPKey(self, pkey);
rb_scan_args(argc, argv, "02", &cipher, &pass);
if (!NIL_P(cipher)) {
- enc = ossl_evp_get_cipherbyname(cipher);
- pass = ossl_pem_passwd_value(pass);
+ enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ pass = ossl_pem_passwd_value(pass);
}
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PrivateKey_bio(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
- }
+ if (!i2d_PrivateKey_bio(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
+ }
}
else {
- if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb,
- (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
- }
+ if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb,
+ (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
+ }
}
return ossl_membio2str(bio);
}
@@ -809,37 +849,37 @@ static VALUE
do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
{
EVP_PKEY *pkey;
- VALUE cipher, pass;
+ VALUE cipher, pass, cipher_holder;
const EVP_CIPHER *enc = NULL;
BIO *bio;
GetPKey(self, pkey);
rb_scan_args(argc, argv, "02", &cipher, &pass);
if (argc > 0) {
- /*
- * TODO: EncryptedPrivateKeyInfo actually has more options.
- * Should they be exposed?
- */
- enc = ossl_evp_get_cipherbyname(cipher);
- pass = ossl_pem_passwd_value(pass);
+ /*
+ * TODO: EncryptedPrivateKeyInfo actually has more options.
+ * Should they be exposed?
+ */
+ enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);
+ pass = ossl_pem_passwd_value(pass);
}
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb, (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
- }
+ if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb, (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PKCS8PrivateKey_bio");
+ }
}
else {
- if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
- ossl_pem_passwd_cb, (void *)pass)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
- }
+ if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,
+ ossl_pem_passwd_cb, (void *)pass)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PKCS8PrivateKey");
+ }
}
return ossl_membio2str(bio);
}
@@ -923,18 +963,18 @@ ossl_pkey_export_spki(VALUE self, int to_der)
ossl_pkey_check_public_key(pkey);
bio = BIO_new(BIO_s_mem());
if (!bio)
- ossl_raise(ePKeyError, "BIO_new");
+ ossl_raise(ePKeyError, "BIO_new");
if (to_der) {
- if (!i2d_PUBKEY_bio(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
- }
+ if (!i2d_PUBKEY_bio(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "i2d_PUBKEY_bio");
+ }
}
else {
- if (!PEM_write_bio_PUBKEY(bio, pkey)) {
- BIO_free(bio);
- ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
- }
+ if (!PEM_write_bio_PUBKEY(bio, pkey)) {
+ BIO_free(bio);
+ ossl_raise(ePKeyError, "PEM_write_bio_PUBKEY");
+ }
}
return ossl_membio2str(bio);
}
@@ -1071,7 +1111,7 @@ static VALUE
ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, data, options, sig;
+ VALUE digest, data, options, sig, md_holder;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
EVP_PKEY_CTX *pctx;
@@ -1081,7 +1121,7 @@ ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
pkey = GetPrivPKeyPtr(self);
rb_scan_args(argc, argv, "21", &digest, &data, &options);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
ctx = EVP_MD_CTX_new();
@@ -1150,7 +1190,7 @@ static VALUE
ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, data, options;
+ VALUE digest, sig, data, options, md_holder;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx;
EVP_PKEY_CTX *pctx;
@@ -1160,7 +1200,7 @@ ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
StringValue(data);
@@ -1229,7 +1269,7 @@ static VALUE
ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, data, options, sig;
+ VALUE digest, data, options, sig, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
size_t outlen;
@@ -1238,7 +1278,7 @@ ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
GetPKey(self, pkey);
rb_scan_args(argc, argv, "21", &digest, &data, &options);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
@@ -1305,7 +1345,7 @@ static VALUE
ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, data, options;
+ VALUE digest, sig, data, options, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
int state, ret;
@@ -1314,7 +1354,7 @@ ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
StringValue(data);
@@ -1368,7 +1408,7 @@ static VALUE
ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
{
EVP_PKEY *pkey;
- VALUE digest, sig, options, out;
+ VALUE digest, sig, options, out, md_holder;
const EVP_MD *md = NULL;
EVP_PKEY_CTX *ctx;
int state;
@@ -1378,7 +1418,7 @@ ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "21", &digest, &sig, &options);
ossl_pkey_check_public_key(pkey);
if (!NIL_P(digest))
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(sig);
ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
@@ -1618,11 +1658,6 @@ void
Init_ossl_pkey(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
/* Document-module: OpenSSL::PKey
*
* == Asymmetric Public Key Algorithms
@@ -1678,7 +1713,16 @@ Init_ossl_pkey(void)
/* Document-class: OpenSSL::PKey::PKeyError
*
- *Raised when errors occur during PKey#sign or PKey#verify.
+ * Raised when errors occur during PKey#sign or PKey#verify.
+ *
+ * Before version 4.0.0, OpenSSL::PKey::PKeyError had the following
+ * subclasses. These subclasses have been removed and the constants are
+ * now defined as aliases of OpenSSL::PKey::PKeyError.
+ *
+ * * OpenSSL::PKey::DHError
+ * * OpenSSL::PKey::DSAError
+ * * OpenSSL::PKey::ECError
+ * * OpenSSL::PKey::RSAError
*/
ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index fdc5e94aed..023361b90f 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -22,12 +22,12 @@ extern const rb_data_type_t ossl_evp_pkey_type;
#define GetPKey(obj, pkey) do {\
TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
if (!(pkey)) { \
- rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
+ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
} \
} while (0)
/* Takes ownership of the EVP_PKEY */
-VALUE ossl_pkey_new(EVP_PKEY *);
+VALUE ossl_pkey_wrap(EVP_PKEY *);
void ossl_pkey_check_public_key(const EVP_PKEY *);
EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
EVP_PKEY *GetPKeyPtr(VALUE);
@@ -45,7 +45,7 @@ VALUE ossl_pkey_export_spki(VALUE self, int to_der);
* #to_der.
*/
VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self,
- int to_der);
+ int to_der);
void Init_ossl_pkey(void);
@@ -74,120 +74,120 @@ extern VALUE cEC;
VALUE ossl_ec_new(EVP_PKEY *);
void Init_ossl_ec(void);
-#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \
-/* \
- * call-seq: \
- * _keytype##.##_name -> aBN \
- */ \
-static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
-{ \
- const _type *obj; \
- const BIGNUM *bn; \
- \
- Get##_type(self, obj); \
- _get; \
- if (bn == NULL) \
- return Qnil; \
- return ossl_bn_new(bn); \
+#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get) \
+/* \
+ * call-seq: \
+ * _keytype##.##_name -> aBN \
+ */ \
+static VALUE ossl_##_keytype##_get_##_name(VALUE self) \
+{ \
+ const _type *obj; \
+ const BIGNUM *bn; \
+ \
+ Get##_type(self, obj); \
+ _get; \
+ if (bn == NULL) \
+ return Qnil; \
+ return ossl_bn_new(bn); \
}
-#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
- _type##_get0_##_group(obj, &bn, NULL, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
- _type##_get0_##_group(obj, NULL, &bn, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3, \
- _type##_get0_##_group(obj, NULL, NULL, &bn))
-
-#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
- _type##_get0_##_group(obj, &bn, NULL)) \
- OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
- _type##_get0_##_group(obj, NULL, &bn))
-
-#if !OSSL_OPENSSL_PREREQ(3, 0, 0)
-#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
-/* \
- * call-seq: \
- * _keytype##.set_##_group(a1, a2, a3) -> self \
- */ \
+#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
+ _type##_get0_##_group(obj, &bn, NULL, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
+ _type##_get0_##_group(obj, NULL, &bn, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3, \
+ _type##_get0_##_group(obj, NULL, NULL, &bn))
+
+#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1, \
+ _type##_get0_##_group(obj, &bn, NULL)) \
+ OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2, \
+ _type##_get0_##_group(obj, NULL, &bn))
+
+#ifndef OSSL_HAVE_IMMUTABLE_PKEY
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
+/* \
+ * call-seq: \
+ * _keytype##.set_##_group(a1, a2, a3) -> self \
+ */ \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
-{ \
- _type *obj; \
- BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
- BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
- BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\
- \
- Get##_type(self, obj); \
- if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
- (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \
- (orig_bn3 && !(bn3 = BN_dup(orig_bn3)))) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- BN_clear_free(bn3); \
- ossl_raise(ePKeyError, "BN_dup"); \
- } \
- \
- if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- BN_clear_free(bn3); \
- ossl_raise(ePKeyError, #_type"_set0_"#_group); \
- } \
- return self; \
+{ \
+ _type *obj; \
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
+ BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\
+ \
+ Get##_type(self, obj); \
+ if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
+ (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) || \
+ (orig_bn3 && !(bn3 = BN_dup(orig_bn3)))) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ BN_clear_free(bn3); \
+ ossl_raise(ePKeyError, "BN_dup"); \
+ } \
+ \
+ if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ BN_clear_free(bn3); \
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \
+ } \
+ return self; \
}
-#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
-/* \
- * call-seq: \
- * _keytype##.set_##_group(a1, a2) -> self \
- */ \
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
+/* \
+ * call-seq: \
+ * _keytype##.set_##_group(a1, a2) -> self \
+ */ \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
-{ \
- _type *obj; \
- BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
- BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
- \
- Get##_type(self, obj); \
- if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
- (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- ossl_raise(ePKeyError, "BN_dup"); \
- } \
- \
- if (!_type##_set0_##_group(obj, bn1, bn2)) { \
- BN_clear_free(bn1); \
- BN_clear_free(bn2); \
- ossl_raise(ePKeyError, #_type"_set0_"#_group); \
- } \
- return self; \
+{ \
+ _type *obj; \
+ BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
+ BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
+ \
+ Get##_type(self, obj); \
+ if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) || \
+ (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ ossl_raise(ePKeyError, "BN_dup"); \
+ } \
+ \
+ if (!_type##_set0_##_group(obj, bn1, bn2)) { \
+ BN_clear_free(bn1); \
+ BN_clear_free(bn2); \
+ ossl_raise(ePKeyError, #_type"_set0_"#_group); \
+ } \
+ return self; \
}
#else
-#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
+#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3) \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \
-{ \
- rb_raise(ePKeyError, \
+{ \
+ rb_raise(ePKeyError, \
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
}
-#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
+#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2) \
static VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \
-{ \
- rb_raise(ePKeyError, \
+{ \
+ rb_raise(ePKeyError, \
#_keytype"#set_"#_group"= is incompatible with OpenSSL 3.0"); \
}
#endif
-#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
- OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)
+#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3) \
+ OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)
-#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
- OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)
+#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2) \
+ OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)
-#define DEF_OSSL_PKEY_BN(class, keytype, name) \
- rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)
+#define DEF_OSSL_PKEY_BN(class, keytype, name) \
+ rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)
#endif /* OSSL_PKEY_H */
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 118d29f04f..3f2975c5a3 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -14,20 +14,21 @@
#define GetPKeyDH(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
} \
} while (0)
#define GetDH(obj, dh) do { \
EVP_PKEY *_pkey; \
GetPKeyDH((obj), _pkey); \
(dh) = EVP_PKEY_get0_DH(_pkey); \
+ if ((dh) == NULL) \
+ ossl_raise(ePKeyError, "failed to get DH from EVP_PKEY"); \
} while (0)
/*
* Classes
*/
VALUE cDH;
-static VALUE eDHError;
/*
* Private
@@ -43,6 +44,7 @@ static VALUE eDHError;
* If called without arguments, an empty instance without any parameter or key
* components is created. Use #set_pqg to manually set the parameters afterwards
* (and optionally #set_key to set private and public key components).
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* If a String is given, tries to parse it as a DER- or PEM- encoded parameters.
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -58,14 +60,15 @@ static VALUE eDHError;
*
* Examples:
* # Creating an instance from scratch
- * # Note that this is deprecated and will not work on OpenSSL 3.0 or later.
+ * # Note that this is deprecated and will result in ArgumentError when
+ * # using OpenSSL 3.0 or later.
* dh = OpenSSL::PKey::DH.new
* dh.set_pqg(bn_p, nil, bn_g)
*
* # Generating a parameters and a key pair
* dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048)
*
- * # Reading DH parameters
+ * # Reading DH parameters from a PEM-encoded string
* dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only
* dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair
*/
@@ -84,10 +87,15 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
/* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::DH.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
dh = DH_new();
if (!dh)
- ossl_raise(eDHError, "DH_new");
+ ossl_raise(ePKeyError, "DH_new");
goto legacy;
+#endif
}
arg = ossl_to_der_if_possible(arg);
@@ -105,12 +113,12 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, Qnil);
BIO_free(in);
if (!pkey)
- ossl_raise(eDHError, "could not parse pkey");
+ ossl_raise(ePKeyError, "could not parse pkey");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_DH) {
EVP_PKEY_free(pkey);
- rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -121,7 +129,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
EVP_PKEY_free(pkey);
DH_free(dh);
- ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DH");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -143,26 +151,26 @@ ossl_dh_initialize_copy(VALUE self, VALUE other)
dh = DHparams_dup(dh_other);
if (!dh)
- ossl_raise(eDHError, "DHparams_dup");
+ ossl_raise(ePKeyError, "DHparams_dup");
DH_get0_key(dh_other, &pub, &priv);
if (pub) {
- BIGNUM *pub2 = BN_dup(pub);
- BIGNUM *priv2 = BN_dup(priv);
+ BIGNUM *pub2 = BN_dup(pub);
+ BIGNUM *priv2 = BN_dup(priv);
if (!pub2 || (priv && !priv2)) {
- BN_clear_free(pub2);
- BN_clear_free(priv2);
- ossl_raise(eDHError, "BN_dup");
- }
- DH_set0_key(dh, pub2, priv2);
+ BN_clear_free(pub2);
+ BN_clear_free(priv2);
+ ossl_raise(ePKeyError, "BN_dup");
+ }
+ DH_set0_key(dh, pub2, priv2);
}
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
EVP_PKEY_free(pkey);
DH_free(dh);
- ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DH");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -241,11 +249,11 @@ ossl_dh_export(VALUE self)
GetDH(self, dh);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
if (!PEM_write_bio_DHparams(out, dh)) {
- BIO_free(out);
- ossl_raise(eDHError, NULL);
+ BIO_free(out);
+ ossl_raise(ePKeyError, NULL);
}
str = ossl_membio2str(out);
@@ -275,11 +283,11 @@ ossl_dh_to_der(VALUE self)
GetDH(self, dh);
if((len = i2d_DHparams(dh, NULL)) <= 0)
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_DHparams(dh, &p) < 0)
- ossl_raise(eDHError, NULL);
+ ossl_raise(ePKeyError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -306,7 +314,7 @@ ossl_dh_check_params(VALUE self)
GetPKey(self, pkey);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
- ossl_raise(eDHError, "EVP_PKEY_CTX_new");
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
ret = EVP_PKEY_param_check(pctx);
EVP_PKEY_CTX_free(pctx);
#else
@@ -349,19 +357,6 @@ OSSL_PKEY_BN_DEF2(dh, DH, key, pub_key, priv_key)
void
Init_ossl_dh(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::DHError
- *
- * Generic exception that is raised if an operation on a DH PKey
- * fails unexpectedly or in case an instantiation of an instance of DH
- * fails due to non-conformant input data.
- */
- eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
/* Document-class: OpenSSL::PKey::DH
*
* An implementation of the Diffie-Hellman key exchange protocol based on
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 9f4f012cfe..041646a058 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -14,13 +14,15 @@
#define GetPKeyDSA(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
} \
} while (0)
#define GetDSA(obj, dsa) do { \
EVP_PKEY *_pkey; \
GetPKeyDSA((obj), _pkey); \
(dsa) = EVP_PKEY_get0_DSA(_pkey); \
+ if ((dsa) == NULL) \
+ ossl_raise(ePKeyError, "failed to get DSA from EVP_PKEY"); \
} while (0)
static inline int
@@ -41,7 +43,6 @@ DSA_PRIVATE(VALUE obj, OSSL_3_const DSA *dsa)
* Classes
*/
VALUE cDSA;
-static VALUE eDSAError;
/*
* Private
@@ -56,6 +57,7 @@ static VALUE eDSAError;
*
* If called without arguments, creates a new instance with no key components
* set. They can be set individually by #set_pqg and #set_key.
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* If called with a String, tries to parse as DER or PEM encoding of a \DSA key.
* See also OpenSSL::PKey.read which can parse keys of any kinds.
@@ -96,10 +98,15 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
/* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::DSA.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
dsa = DSA_new();
if (!dsa)
- ossl_raise(eDSAError, "DSA_new");
+ ossl_raise(ePKeyError, "DSA_new");
goto legacy;
+#endif
}
pass = ossl_pem_passwd_value(pass);
@@ -117,12 +124,12 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, pass);
BIO_free(in);
if (!pkey)
- ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
+ ossl_raise(ePKeyError, "Neither PUB key nor PRIV key");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_DSA) {
EVP_PKEY_free(pkey);
- rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -133,7 +140,7 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
EVP_PKEY_free(pkey);
DSA_free(dsa);
- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -156,13 +163,13 @@ ossl_dsa_initialize_copy(VALUE self, VALUE other)
(d2i_of_void *)d2i_DSAPrivateKey,
(char *)dsa);
if (!dsa_new)
- ossl_raise(eDSAError, "ASN1_dup");
+ ossl_raise(ePKeyError, "ASN1_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
EVP_PKEY_free(pkey);
DSA_free(dsa_new);
- ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_DSA");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -327,20 +334,6 @@ OSSL_PKEY_BN_DEF2(dsa, DSA, key, pub_key, priv_key)
void
Init_ossl_dsa(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::DSAError
- *
- * Generic exception that is raised if an operation on a DSA PKey
- * fails unexpectedly or in case an instantiation of an instance of DSA
- * fails due to non-conformant input data.
- */
- eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
-
/* Document-class: OpenSSL::PKey::DSA
*
* DSA, the Digital Signature Algorithm, is specified in NIST's
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index 4687cf8c9d..35f031819d 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -15,25 +15,27 @@ static const rb_data_type_t ossl_ec_point_type;
#define GetPKeyEC(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
} \
} while (0)
#define GetEC(obj, key) do { \
EVP_PKEY *_pkey; \
GetPKeyEC(obj, _pkey); \
(key) = EVP_PKEY_get0_EC_KEY(_pkey); \
+ if ((key) == NULL) \
+ ossl_raise(ePKeyError, "failed to get EC_KEY from EVP_PKEY"); \
} while (0)
#define GetECGroup(obj, group) do { \
TypedData_Get_Struct(obj, EC_GROUP, &ossl_ec_group_type, group); \
if ((group) == NULL) \
- ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
+ ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
} while (0)
#define GetECPoint(obj, point) do { \
TypedData_Get_Struct(obj, EC_POINT, &ossl_ec_point_type, point); \
if ((point) == NULL) \
- ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
+ ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
} while (0)
#define GetECPointGroup(obj, group) do { \
VALUE _group = rb_attr_get(obj, id_i_group); \
@@ -41,17 +43,13 @@ static const rb_data_type_t ossl_ec_point_type;
} while (0)
VALUE cEC;
-static VALUE eECError;
static VALUE cEC_GROUP;
static VALUE eEC_GROUP;
static VALUE cEC_POINT;
static VALUE eEC_POINT;
-static ID s_GFp, s_GF2m;
-
-static ID ID_uncompressed;
-static ID ID_compressed;
-static ID ID_hybrid;
+static VALUE sym_GFp, sym_GF2m;
+static VALUE sym_uncompressed, sym_compressed, sym_hybrid;
static ID id_i_group;
@@ -68,27 +66,27 @@ ec_key_new_from_group(VALUE arg)
EC_KEY *ec;
if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
- EC_GROUP *group;
+ EC_GROUP *group;
- GetECGroup(arg, group);
- if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, NULL);
+ GetECGroup(arg, group);
+ if (!(ec = EC_KEY_new()))
+ ossl_raise(ePKeyError, NULL);
- if (!EC_KEY_set_group(ec, group)) {
- EC_KEY_free(ec);
- ossl_raise(eECError, NULL);
- }
+ if (!EC_KEY_set_group(ec, group)) {
+ EC_KEY_free(ec);
+ ossl_raise(ePKeyError, NULL);
+ }
} else {
- int nid = OBJ_sn2nid(StringValueCStr(arg));
+ int nid = OBJ_sn2nid(StringValueCStr(arg));
- if (nid == NID_undef)
- ossl_raise(eECError, "invalid curve name");
+ if (nid == NID_undef)
+ ossl_raise(ePKeyError, "invalid curve name");
- if (!(ec = EC_KEY_new_by_curve_name(nid)))
- ossl_raise(eECError, NULL);
+ if (!(ec = EC_KEY_new_by_curve_name(nid)))
+ ossl_raise(ePKeyError, NULL);
- EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
- EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+ EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
+ EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
}
return ec;
@@ -115,12 +113,12 @@ ossl_ec_key_s_generate(VALUE klass, VALUE arg)
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(obj) = pkey;
if (!EC_KEY_generate_key(ec))
- ossl_raise(eECError, "EC_KEY_generate_key");
+ ossl_raise(ePKeyError, "EC_KEY_generate_key");
return obj;
}
@@ -150,9 +148,14 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "02", &arg, &pass);
if (NIL_P(arg)) {
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::EC.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
if (!(ec = EC_KEY_new()))
- ossl_raise(eECError, "EC_KEY_new");
+ ossl_raise(ePKeyError, "EC_KEY_new");
goto legacy;
+#endif
}
else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
ec = ec_key_new_from_group(arg);
@@ -174,7 +177,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_EC) {
EVP_PKEY_free(pkey);
- rb_raise(eECError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -184,7 +187,7 @@ static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
EVP_PKEY_free(pkey);
EC_KEY_free(ec);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -205,12 +208,12 @@ ossl_ec_key_initialize_copy(VALUE self, VALUE other)
ec_new = EC_KEY_dup(ec);
if (!ec_new)
- ossl_raise(eECError, "EC_KEY_dup");
+ ossl_raise(ePKeyError, "EC_KEY_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {
EC_KEY_free(ec_new);
- ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_EC_KEY");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -234,7 +237,7 @@ ossl_ec_key_get_group(VALUE self)
GetEC(self, ec);
group = EC_KEY_get0_group(ec);
if (!group)
- return Qnil;
+ return Qnil;
return ec_group_new(group);
}
@@ -249,7 +252,7 @@ ossl_ec_key_get_group(VALUE self)
static VALUE
ossl_ec_key_set_group(VALUE self, VALUE group_v)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -259,7 +262,7 @@ ossl_ec_key_set_group(VALUE self, VALUE group_v)
GetECGroup(group_v, group);
if (EC_KEY_set_group(ec, group) != 1)
- ossl_raise(eECError, "EC_KEY_set_group");
+ ossl_raise(ePKeyError, "EC_KEY_set_group");
return group_v;
#endif
@@ -291,7 +294,7 @@ static VALUE ossl_ec_key_get_private_key(VALUE self)
*/
static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -302,14 +305,14 @@ static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
bn = GetBNPtr(private_key);
switch (EC_KEY_set_private_key(ec, bn)) {
- case 1:
+ case 1:
break;
- case 0:
+ case 0:
if (bn == NULL)
break;
- /* fallthrough */
- default:
- ossl_raise(eECError, "EC_KEY_set_private_key");
+ /* fallthrough */
+ default:
+ ossl_raise(ePKeyError, "EC_KEY_set_private_key");
}
return private_key;
@@ -342,7 +345,7 @@ static VALUE ossl_ec_key_get_public_key(VALUE self)
*/
static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
@@ -353,14 +356,14 @@ static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
GetECPoint(public_key, point);
switch (EC_KEY_set_public_key(ec, point)) {
- case 1:
+ case 1:
break;
- case 0:
+ case 0:
if (point == NULL)
break;
- /* fallthrough */
- default:
- ossl_raise(eECError, "EC_KEY_set_public_key");
+ /* fallthrough */
+ default:
+ ossl_raise(ePKeyError, "EC_KEY_set_public_key");
}
return public_key;
@@ -464,7 +467,7 @@ ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
- ossl_raise(eECError, "can't export - no public key set");
+ ossl_raise(ePKeyError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(argc, argv, self, 0);
else
@@ -492,7 +495,7 @@ ossl_ec_key_to_der(VALUE self)
GetEC(self, ec);
if (EC_KEY_get0_public_key(ec) == NULL)
- ossl_raise(eECError, "can't export - no public key set");
+ ossl_raise(ePKeyError, "can't export - no public key set");
if (EC_KEY_get0_private_key(ec))
return ossl_pkey_export_traditional(0, NULL, self, 1);
else
@@ -514,14 +517,14 @@ ossl_ec_key_to_der(VALUE self)
*/
static VALUE ossl_ec_key_generate_key(VALUE self)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
EC_KEY *ec;
GetEC(self, ec);
if (EC_KEY_generate_key(ec) != 1)
- ossl_raise(eECError, "EC_KEY_generate_key");
+ ossl_raise(ePKeyError, "EC_KEY_generate_key");
return self;
#endif
@@ -546,18 +549,18 @@ static VALUE ossl_ec_key_check_key(VALUE self)
GetEC(self, ec);
pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
if (!pctx)
- ossl_raise(eECError, "EVP_PKEY_CTX_new");
+ ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
if (EC_KEY_get0_private_key(ec) != NULL) {
if (EVP_PKEY_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
- ossl_raise(eECError, "EVP_PKEY_check");
+ ossl_raise(ePKeyError, "EVP_PKEY_check");
}
}
else {
if (EVP_PKEY_public_check(pctx) != 1) {
EVP_PKEY_CTX_free(pctx);
- ossl_raise(eECError, "EVP_PKEY_public_check");
+ ossl_raise(ePKeyError, "EVP_PKEY_public_check");
}
}
@@ -567,7 +570,7 @@ static VALUE ossl_ec_key_check_key(VALUE self)
GetEC(self, ec);
if (EC_KEY_check_key(ec) != 1)
- ossl_raise(eECError, "EC_KEY_check_key");
+ ossl_raise(ePKeyError, "EC_KEY_check_key");
#endif
return Qtrue;
@@ -585,7 +588,7 @@ ossl_ec_group_free(void *ptr)
static const rb_data_type_t ossl_ec_group_type = {
"OpenSSL/ec_group",
{
- 0, ossl_ec_group_free,
+ 0, ossl_ec_group_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -605,7 +608,7 @@ ec_group_new(const EC_GROUP *group)
obj = ossl_ec_group_alloc(cEC_GROUP);
group_new = EC_GROUP_dup(group);
if (!group_new)
- ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
RTYPEDDATA_DATA(obj) = group_new;
return obj;
@@ -633,7 +636,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
- case 1:
+ case 1:
if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
const EC_GROUP *arg1_group;
@@ -645,7 +648,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
if (!group) {
- OSSL_BIO_reset(in);
+ OSSL_BIO_reset(in);
group = d2i_ECPKParameters_bio(in, NULL);
}
@@ -655,7 +658,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
const char *name = StringValueCStr(arg1);
int nid = OBJ_sn2nid(name);
- ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */
+ ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */
if (nid == NID_undef)
ossl_raise(eEC_GROUP, "unknown curve name (%"PRIsVALUE")", arg1);
#if !defined(OPENSSL_IS_AWSLC)
@@ -672,33 +675,34 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
}
break;
- case 4:
+ case 4:
if (SYMBOL_P(arg1)) {
- ID id = SYM2ID(arg1);
EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
const BIGNUM *p = GetBNPtr(arg2);
const BIGNUM *a = GetBNPtr(arg3);
const BIGNUM *b = GetBNPtr(arg4);
- if (id == s_GFp) {
+ if (arg1 == sym_GFp) {
new_curve = EC_GROUP_new_curve_GFp;
+ }
#if !defined(OPENSSL_NO_EC2M)
- } else if (id == s_GF2m) {
+ else if (arg1 == sym_GF2m) {
new_curve = EC_GROUP_new_curve_GF2m;
+ }
#endif
- } else {
+ else {
ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
}
if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
} else {
- ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
+ ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
}
break;
- default:
- ossl_raise(rb_eArgError, "wrong number of arguments");
+ default:
+ ossl_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1 or 4)", argc);
}
ASSUME(group);
@@ -715,12 +719,12 @@ ossl_ec_group_initialize_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group_new);
if (group_new)
- ossl_raise(eEC_GROUP, "EC::Group already initialized");
+ ossl_raise(eEC_GROUP, "EC::Group already initialized");
GetECGroup(other, group);
group_new = EC_GROUP_dup(group);
if (!group_new)
- ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
RTYPEDDATA_DATA(self) = group_new;
return self;
@@ -742,9 +746,9 @@ static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
GetECGroup(b, group2);
switch (EC_GROUP_cmp(group1, group2, ossl_bn_ctx)) {
- case 0: return Qtrue;
- case 1: return Qfalse;
- default: ossl_raise(eEC_GROUP, "EC_GROUP_cmp");
+ case 0: return Qtrue;
+ case 1: return Qfalse;
+ default: ossl_raise(eEC_GROUP, "EC_GROUP_cmp");
}
}
@@ -764,7 +768,7 @@ static VALUE ossl_ec_group_get_generator(VALUE self)
GetECGroup(self, group);
generator = EC_GROUP_get0_generator(group);
if (!generator)
- return Qnil;
+ return Qnil;
return ec_point_new(generator, group);
}
@@ -807,11 +811,10 @@ static VALUE ossl_ec_group_get_order(VALUE self)
{
VALUE bn_obj;
BIGNUM *bn;
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
GetECGroup(self, group);
-
- bn_obj = ossl_bn_new(NULL);
+ bn_obj = ossl_bn_new(BN_value_one());
bn = GetBNPtr(bn_obj);
if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
@@ -832,11 +835,10 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self)
{
VALUE bn_obj;
BIGNUM *bn;
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
GetECGroup(self, group);
-
- bn_obj = ossl_bn_new(NULL);
+ bn_obj = ossl_bn_new(BN_value_one());
bn = GetBNPtr(bn_obj);
if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
@@ -847,25 +849,23 @@ static VALUE ossl_ec_group_get_cofactor(VALUE self)
/*
* call-seq:
- * group.curve_name => String
+ * group.curve_name -> string or nil
*
- * Returns the curve name (sn).
+ * Returns the curve name (short name) corresponding to this group, or +nil+
+ * if \OpenSSL does not have an OID associated with the group.
*
* See the OpenSSL documentation for EC_GROUP_get_curve_name()
*/
static VALUE ossl_ec_group_get_curve_name(VALUE self)
{
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
int nid;
GetECGroup(self, group);
- if (group == NULL)
- return Qnil;
-
nid = EC_GROUP_get_curve_name(group);
-
-/* BUG: an nid or asn1 object should be returned, maybe. */
- return rb_str_new2(OBJ_nid2sn(nid));
+ if (nid == NID_undef)
+ return Qnil;
+ return rb_str_new_cstr(OBJ_nid2sn(nid));
}
/*
@@ -958,37 +958,36 @@ static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
*/
static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
{
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
point_conversion_form_t form;
- VALUE ret;
GetECGroup(self, group);
form = EC_GROUP_get_point_conversion_form(group);
switch (form) {
- case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
- case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break;
- case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break;
- default: ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
+ case POINT_CONVERSION_UNCOMPRESSED:
+ return sym_uncompressed;
+ case POINT_CONVERSION_COMPRESSED:
+ return sym_compressed;
+ case POINT_CONVERSION_HYBRID:
+ return sym_hybrid;
+ default:
+ ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, " \
+ "this module should be updated", form);
}
-
- return ID2SYM(ret);
}
static point_conversion_form_t
parse_point_conversion_form_symbol(VALUE sym)
{
- ID id = SYM2ID(sym);
-
- if (id == ID_uncompressed)
- return POINT_CONVERSION_UNCOMPRESSED;
- else if (id == ID_compressed)
- return POINT_CONVERSION_COMPRESSED;
- else if (id == ID_hybrid)
- return POINT_CONVERSION_HYBRID;
- else
- ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE
- " (expected :compressed, :uncompressed, or :hybrid)", sym);
+ if (sym == sym_uncompressed)
+ return POINT_CONVERSION_UNCOMPRESSED;
+ if (sym == sym_compressed)
+ return POINT_CONVERSION_COMPRESSED;
+ if (sym == sym_hybrid)
+ return POINT_CONVERSION_HYBRID;
+ ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE
+ " (expected :compressed, :uncompressed, or :hybrid)", sym);
}
/*
@@ -1093,20 +1092,20 @@ static VALUE ossl_ec_group_to_string(VALUE self, int format)
ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
switch(format) {
- case EXPORT_PEM:
+ case EXPORT_PEM:
i = PEM_write_bio_ECPKParameters(out, group);
- break;
- case EXPORT_DER:
+ break;
+ case EXPORT_DER:
i = i2d_ECPKParameters_bio(out, group);
- break;
- default:
+ break;
+ default:
BIO_free(out);
- ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
+ ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
}
if (i != 1) {
BIO_free(out);
- ossl_raise(eECError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
str = ossl_membio2str(out);
@@ -1150,11 +1149,11 @@ static VALUE ossl_ec_group_to_text(VALUE self)
GetECGroup(self, group);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
+ ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
}
if (!ECPKParameters_print(out, group, 0)) {
- BIO_free(out);
- ossl_raise(eEC_GROUP, NULL);
+ BIO_free(out);
+ ossl_raise(eEC_GROUP, NULL);
}
str = ossl_membio2str(out);
@@ -1174,7 +1173,7 @@ ossl_ec_point_free(void *ptr)
static const rb_data_type_t ossl_ec_point_type = {
"OpenSSL/EC_POINT",
{
- 0, ossl_ec_point_free,
+ 0, ossl_ec_point_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -1194,7 +1193,7 @@ ec_point_new(const EC_POINT *point, const EC_GROUP *group)
obj = ossl_ec_point_alloc(cEC_POINT);
point_new = EC_POINT_dup(point, group);
if (!point_new)
- ossl_raise(eEC_POINT, "EC_POINT_dup");
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
RTYPEDDATA_DATA(obj) = point_new;
rb_ivar_set(obj, id_i_group, ec_group_new(group));
@@ -1222,39 +1221,39 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point);
if (point)
- rb_raise(eEC_POINT, "EC_POINT already initialized");
+ rb_raise(eEC_POINT, "EC_POINT already initialized");
rb_scan_args(argc, argv, "11", &group_v, &arg2);
if (rb_obj_is_kind_of(group_v, cEC_POINT)) {
- if (argc != 1)
- rb_raise(rb_eArgError, "invalid second argument");
- return ossl_ec_point_initialize_copy(self, group_v);
+ if (argc != 1)
+ rb_raise(rb_eArgError, "invalid second argument");
+ return ossl_ec_point_initialize_copy(self, group_v);
}
GetECGroup(group_v, group);
if (argc == 1) {
- point = EC_POINT_new(group);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_new");
+ point = EC_POINT_new(group);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_new");
}
else {
- if (rb_obj_is_kind_of(arg2, cBN)) {
- point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_bn2point");
- }
- else {
- StringValue(arg2);
- point = EC_POINT_new(group);
- if (!point)
- ossl_raise(eEC_POINT, "EC_POINT_new");
- if (!EC_POINT_oct2point(group, point,
- (unsigned char *)RSTRING_PTR(arg2),
- RSTRING_LEN(arg2), ossl_bn_ctx)) {
- EC_POINT_free(point);
- ossl_raise(eEC_POINT, "EC_POINT_oct2point");
- }
- }
+ if (rb_obj_is_kind_of(arg2, cBN)) {
+ point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_bn2point");
+ }
+ else {
+ StringValue(arg2);
+ point = EC_POINT_new(group);
+ if (!point)
+ ossl_raise(eEC_POINT, "EC_POINT_new");
+ if (!EC_POINT_oct2point(group, point,
+ (unsigned char *)RSTRING_PTR(arg2),
+ RSTRING_LEN(arg2), ossl_bn_ctx)) {
+ EC_POINT_free(point);
+ ossl_raise(eEC_POINT, "EC_POINT_oct2point");
+ }
+ }
}
RTYPEDDATA_DATA(self) = point;
@@ -1273,7 +1272,7 @@ ossl_ec_point_initialize_copy(VALUE self, VALUE other)
TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point_new);
if (point_new)
- ossl_raise(eEC_POINT, "EC::Point already initialized");
+ ossl_raise(eEC_POINT, "EC::Point already initialized");
GetECPoint(other, point);
group_v = rb_obj_dup(rb_attr_get(other, id_i_group));
@@ -1281,7 +1280,7 @@ ossl_ec_point_initialize_copy(VALUE self, VALUE other)
point_new = EC_POINT_dup(point, group);
if (!point_new)
- ossl_raise(eEC_POINT, "EC_POINT_dup");
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
RTYPEDDATA_DATA(self) = point_new;
rb_ivar_set(self, id_i_group, group_v);
@@ -1308,9 +1307,9 @@ static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
GetECGroup(group_v1, group);
switch (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx)) {
- case 0: return Qtrue;
- case 1: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_cmp");
+ case 0: return Qtrue;
+ case 1: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_cmp");
}
UNREACHABLE;
@@ -1329,9 +1328,9 @@ static VALUE ossl_ec_point_is_at_infinity(VALUE self)
GetECPointGroup(self, group);
switch (EC_POINT_is_at_infinity(group, point)) {
- case 1: return Qtrue;
- case 0: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_is_at_infinity");
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_is_at_infinity");
}
UNREACHABLE;
@@ -1350,9 +1349,9 @@ static VALUE ossl_ec_point_is_on_curve(VALUE self)
GetECPointGroup(self, group);
switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
- case 1: return Qtrue;
- case 0: return Qfalse;
- default: ossl_raise(eEC_POINT, "EC_POINT_is_on_curve");
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(eEC_POINT, "EC_POINT_is_on_curve");
}
UNREACHABLE;
@@ -1373,7 +1372,7 @@ static VALUE ossl_ec_point_make_affine(VALUE self)
GetECPointGroup(self, group);
rb_warn("OpenSSL::PKey::EC::Point#make_affine! is deprecated");
-#if !OSSL_OPENSSL_PREREQ(3, 0, 0) && !defined(OPENSSL_IS_AWSLC)
+#if !defined(OSSL_HAVE_IMMUTABLE_PKEY) && !defined(OPENSSL_IS_AWSLC)
if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
ossl_raise(eEC_POINT, "EC_POINT_make_affine");
#endif
@@ -1444,12 +1443,12 @@ ossl_ec_point_to_octet_string(VALUE self, VALUE conversion_form)
len = EC_POINT_point2oct(group, point, form, NULL, 0, ossl_bn_ctx);
if (!len)
- ossl_raise(eEC_POINT, "EC_POINT_point2oct");
+ ossl_raise(eEC_POINT, "EC_POINT_point2oct");
str = rb_str_new(NULL, (long)len);
if (!EC_POINT_point2oct(group, point, form,
- (unsigned char *)RSTRING_PTR(str), len,
- ossl_bn_ctx))
- ossl_raise(eEC_POINT, "EC_POINT_point2oct");
+ (unsigned char *)RSTRING_PTR(str), len,
+ ossl_bn_ctx))
+ ossl_raise(eEC_POINT, "EC_POINT_point2oct");
return str;
}
@@ -1527,15 +1526,6 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)
void Init_ossl_ec(void)
{
#undef rb_intern
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
-
/*
* Document-class: OpenSSL::PKey::EC
*
@@ -1557,12 +1547,12 @@ void Init_ossl_ec(void)
eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
- s_GFp = rb_intern("GFp");
- s_GF2m = rb_intern("GF2m");
+ sym_GFp = ID2SYM(rb_intern_const("GFp"));
+ sym_GF2m = ID2SYM(rb_intern_const("GF2m"));
- ID_uncompressed = rb_intern("uncompressed");
- ID_compressed = rb_intern("compressed");
- ID_hybrid = rb_intern("hybrid");
+ sym_uncompressed = ID2SYM(rb_intern_const("uncompressed"));
+ sym_compressed = ID2SYM(rb_intern_const("compressed"));
+ sym_hybrid = ID2SYM(rb_intern_const("hybrid"));
rb_define_const(cEC, "NAMED_CURVE", INT2NUM(OPENSSL_EC_NAMED_CURVE));
rb_define_const(cEC, "EXPLICIT_CURVE", INT2NUM(OPENSSL_EC_EXPLICIT_CURVE));
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 185b47cbfb..039b2c6a34 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -14,13 +14,15 @@
#define GetPKeyRSA(obj, pkey) do { \
GetPKey((obj), (pkey)); \
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { /* PARANOIA? */ \
- ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
} \
} while (0)
#define GetRSA(obj, rsa) do { \
EVP_PKEY *_pkey; \
GetPKeyRSA((obj), _pkey); \
(rsa) = EVP_PKEY_get0_RSA(_pkey); \
+ if ((rsa) == NULL) \
+ ossl_raise(ePKeyError, "failed to get RSA from EVP_PKEY"); \
} while (0)
static inline int
@@ -42,7 +44,6 @@ RSA_PRIVATE(VALUE obj, OSSL_3_const RSA *rsa)
* Classes
*/
VALUE cRSA;
-static VALUE eRSAError;
/*
* Private
@@ -59,6 +60,7 @@ static VALUE eRSAError;
* If called without arguments, creates a new instance with no key components
* set. They can be set individually by #set_key, #set_factors, and
* #set_crt_params.
+ * This form is not compatible with OpenSSL 3.0 or later.
*
* If called with a String, tries to parse as DER or PEM encoding of an \RSA key.
* Note that if _password_ is not specified, but the key is encrypted with a
@@ -89,10 +91,15 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
/* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
rb_scan_args(argc, argv, "02", &arg, &pass);
if (argc == 0) {
- rsa = RSA_new();
+#ifdef OSSL_HAVE_IMMUTABLE_PKEY
+ rb_raise(rb_eArgError, "OpenSSL::PKey::RSA.new cannot be called " \
+ "without arguments; pkeys are immutable with OpenSSL 3.0");
+#else
+ rsa = RSA_new();
if (!rsa)
- ossl_raise(eRSAError, "RSA_new");
+ ossl_raise(ePKeyError, "RSA_new");
goto legacy;
+#endif
}
pass = ossl_pem_passwd_value(pass);
@@ -113,12 +120,12 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
pkey = ossl_pkey_read_generic(in, pass);
BIO_free(in);
if (!pkey)
- ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
+ ossl_raise(ePKeyError, "Neither PUB key nor PRIV key");
type = EVP_PKEY_base_id(pkey);
if (type != EVP_PKEY_RSA) {
EVP_PKEY_free(pkey);
- rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+ rb_raise(ePKeyError, "incorrect pkey type: %s", OBJ_nid2sn(type));
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -129,7 +136,7 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
EVP_PKEY_free(pkey);
RSA_free(rsa);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA");
}
RTYPEDDATA_DATA(self) = pkey;
return self;
@@ -152,12 +159,12 @@ ossl_rsa_initialize_copy(VALUE self, VALUE other)
(d2i_of_void *)d2i_RSAPrivateKey,
(char *)rsa);
if (!rsa_new)
- ossl_raise(eRSAError, "ASN1_dup");
+ ossl_raise(ePKeyError, "ASN1_dup");
pkey = EVP_PKEY_new();
if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) {
RSA_free(rsa_new);
- ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+ ossl_raise(ePKeyError, "EVP_PKEY_assign_RSA");
}
RTYPEDDATA_DATA(self) = pkey;
@@ -312,7 +319,7 @@ ossl_rsa_to_der(VALUE self)
* Signs _data_ using the Probabilistic Signature Scheme (RSA-PSS) and returns
* the calculated signature.
*
- * RSAError will be raised if an error occurs.
+ * PKeyError will be raised if an error occurs.
*
* See #verify_pss for the verification operation.
*
@@ -341,7 +348,7 @@ ossl_rsa_to_der(VALUE self)
static VALUE
ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
{
- VALUE digest, data, options, kwargs[2], signature;
+ VALUE digest, data, options, kwargs[2], signature, mgf1md_holder, md_holder;
static ID kwargs_ids[2];
EVP_PKEY *pkey;
EVP_PKEY_CTX *pkey_ctx;
@@ -351,46 +358,46 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
int salt_len;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt_length");
- kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
}
rb_scan_args(argc, argv, "2:", &digest, &data, &options);
rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
if (kwargs[0] == ID2SYM(rb_intern("max")))
- salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
+ salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */
else if (kwargs[0] == ID2SYM(rb_intern("digest")))
- salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
else
- salt_len = NUM2INT(kwargs[0]);
- mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);
pkey = GetPrivPKeyPtr(self);
buf_len = EVP_PKEY_size(pkey);
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(data);
signature = rb_str_new(NULL, (long)buf_len);
md_ctx = EVP_MD_CTX_new();
if (!md_ctx)
- goto err;
+ goto err;
if (EVP_DigestSignInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
- goto err;
+ goto err;
if (EVP_DigestSignUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
- goto err;
+ goto err;
if (EVP_DigestSignFinal(md_ctx, (unsigned char *)RSTRING_PTR(signature), &buf_len) != 1)
- goto err;
+ goto err;
rb_str_set_len(signature, (long)buf_len);
@@ -399,7 +406,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
err:
EVP_MD_CTX_free(md_ctx);
- ossl_raise(eRSAError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
/*
@@ -409,7 +416,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
* Verifies _data_ using the Probabilistic Signature Scheme (RSA-PSS).
*
* The return value is +true+ if the signature is valid, +false+ otherwise.
- * RSAError will be raised if an error occurs.
+ * PKeyError will be raised if an error occurs.
*
* See #sign_pss for the signing operation and an example code.
*
@@ -428,7 +435,7 @@ ossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)
static VALUE
ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
{
- VALUE digest, signature, data, options, kwargs[2];
+ VALUE digest, signature, data, options, kwargs[2], mgf1md_holder, md_holder;
static ID kwargs_ids[2];
EVP_PKEY *pkey;
EVP_PKEY_CTX *pkey_ctx;
@@ -437,62 +444,61 @@ ossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)
int result, salt_len;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("salt_length");
- kwargs_ids[1] = rb_intern_const("mgf1_hash");
+ kwargs_ids[0] = rb_intern_const("salt_length");
+ kwargs_ids[1] = rb_intern_const("mgf1_hash");
}
rb_scan_args(argc, argv, "3:", &digest, &signature, &data, &options);
rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);
if (kwargs[0] == ID2SYM(rb_intern("auto")))
- salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
+ salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */
else if (kwargs[0] == ID2SYM(rb_intern("digest")))
- salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
+ salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */
else
- salt_len = NUM2INT(kwargs[0]);
- mgf1md = ossl_evp_get_digestbyname(kwargs[1]);
+ salt_len = NUM2INT(kwargs[0]);
+ mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);
GetPKey(self, pkey);
- md = ossl_evp_get_digestbyname(digest);
+ md = ossl_evp_md_fetch(digest, &md_holder);
StringValue(signature);
StringValue(data);
md_ctx = EVP_MD_CTX_new();
if (!md_ctx)
- goto err;
+ goto err;
if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)
- goto err;
+ goto err;
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)
- goto err;
+ goto err;
if (EVP_DigestVerifyUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
- goto err;
+ goto err;
result = EVP_DigestVerifyFinal(md_ctx,
- (unsigned char *)RSTRING_PTR(signature),
- RSTRING_LEN(signature));
+ (unsigned char *)RSTRING_PTR(signature),
+ RSTRING_LEN(signature));
+ EVP_MD_CTX_free(md_ctx);
switch (result) {
case 0:
- ossl_clear_error();
- EVP_MD_CTX_free(md_ctx);
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
case 1:
- EVP_MD_CTX_free(md_ctx);
- return Qtrue;
+ return Qtrue;
default:
- goto err;
+ ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
}
err:
EVP_MD_CTX_free(md_ctx);
- ossl_raise(eRSAError, NULL);
+ ossl_raise(ePKeyError, NULL);
}
/*
@@ -530,20 +536,6 @@ OSSL_PKEY_BN_DEF3(rsa, RSA, crt_params, dmp1, dmq1, iqmp)
void
Init_ossl_rsa(void)
{
-#if 0
- mPKey = rb_define_module_under(mOSSL, "PKey");
- cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
- ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
-#endif
-
- /* Document-class: OpenSSL::PKey::RSAError
- *
- * Generic exception that is raised if an operation on an RSA PKey
- * fails unexpectedly or in case an instantiation of an instance of RSA
- * fails due to non-conformant input data.
- */
- eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
-
/* Document-class: OpenSSL::PKey::RSA
*
* RSA is an asymmetric public key algorithm that has been formalized in
diff --git a/ext/openssl/ossl_provider.c b/ext/openssl/ossl_provider.c
index d1f6c5d427..ea5abb8e48 100644
--- a/ext/openssl/ossl_provider.c
+++ b/ext/openssl/ossl_provider.c
@@ -5,8 +5,6 @@
#include "ossl.h"
#ifdef OSSL_USE_PROVIDER
-# include <openssl/provider.h>
-
#define NewProvider(klass) \
TypedData_Wrap_Struct((klass), &ossl_provider_type, 0)
#define SetProvider(obj, provider) do { \
@@ -187,11 +185,6 @@ ossl_provider_inspect(VALUE self)
void
Init_ossl_provider(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
cProvider = rb_define_class_under(mOSSL, "Provider", rb_cObject);
eProviderError = rb_define_class_under(cProvider, "ProviderError", eOSSLError);
diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c
index 764900dfc6..753f8b25f7 100644
--- a/ext/openssl/ossl_rand.c
+++ b/ext/openssl/ossl_rand.c
@@ -68,7 +68,7 @@ static VALUE
ossl_rand_load_file(VALUE self, VALUE filename)
{
if(!RAND_load_file(StringValueCStr(filename), -1)) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -85,14 +85,14 @@ static VALUE
ossl_rand_write_file(VALUE self, VALUE filename)
{
if (RAND_write_file(StringValueCStr(filename)) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
/*
* call-seq:
- * random_bytes(length) -> string
+ * random_bytes(length) -> string
*
* Generates a String with _length_ number of cryptographically strong
* pseudo-random bytes.
@@ -112,9 +112,9 @@ ossl_rand_bytes(VALUE self, VALUE len)
str = rb_str_new(0, n);
ret = RAND_bytes((unsigned char *)RSTRING_PTR(str), n);
if (ret == 0) {
- ossl_raise(eRandomError, "RAND_bytes");
+ ossl_raise(eRandomError, "RAND_bytes");
} else if (ret == -1) {
- ossl_raise(eRandomError, "RAND_bytes is not supported");
+ ossl_raise(eRandomError, "RAND_bytes is not supported");
}
return str;
@@ -131,7 +131,7 @@ static VALUE
ossl_rand_egd(VALUE self, VALUE filename)
{
if (RAND_egd(StringValueCStr(filename)) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -151,7 +151,7 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
int n = NUM2INT(len);
if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) {
- ossl_raise(eRandomError, NULL);
+ ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
@@ -175,11 +175,6 @@ ossl_rand_status(VALUE self)
void
Init_ossl_rand(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
mRandom = rb_define_module_under(mOSSL, "Random");
eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError);
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index a5b25e14de..c6dec32a9e 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -25,7 +25,7 @@
#endif
#define GetSSLCTX(obj, ctx) do { \
- TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \
+ TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \
} while (0)
VALUE mSSL;
@@ -36,19 +36,18 @@ VALUE cSSLSocket;
static VALUE eSSLErrorWaitReadable;
static VALUE eSSLErrorWaitWritable;
-static ID id_call, ID_callback_state, id_tmp_dh_callback,
- id_npn_protocols_encoded, id_each;
+static ID id_call, ID_callback_state, id_npn_protocols_encoded, id_each;
static VALUE sym_exception, sym_wait_readable, sym_wait_writable;
static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode,
- id_i_verify_depth, id_i_verify_callback, id_i_client_ca,
- id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,
- id_i_client_cert_cb, id_i_timeout,
- id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
- id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
- id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
- id_i_verify_hostname, id_i_keylog_cb;
-static ID id_i_io, id_i_context, id_i_hostname;
+ id_i_verify_depth, id_i_verify_callback, id_i_client_ca,
+ id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,
+ id_i_client_cert_cb, id_i_timeout,
+ id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
+ id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
+ id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
+ id_i_verify_hostname, id_i_keylog_cb, id_i_tmp_dh_callback;
+static ID id_i_io, id_i_context, id_i_hostname, id_i_sync_close;
static int ossl_ssl_ex_ptr_idx;
static int ossl_sslctx_ex_ptr_idx;
@@ -79,9 +78,9 @@ ossl_sslctx_s_alloc(VALUE klass)
{
SSL_CTX *ctx;
long mode = 0 |
- SSL_MODE_ENABLE_PARTIAL_WRITE |
- SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
- SSL_MODE_RELEASE_BUFFERS;
+ SSL_MODE_ENABLE_PARTIAL_WRITE |
+ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
+ SSL_MODE_RELEASE_BUFFERS;
VALUE obj;
obj = TypedData_Wrap_Struct(klass, &ossl_sslctx_type, 0);
@@ -90,6 +89,7 @@ ossl_sslctx_s_alloc(VALUE klass)
ossl_raise(eSSLError, "SSL_CTX_new");
}
SSL_CTX_set_mode(ctx, mode);
+ SSL_CTX_set_dh_auto(ctx, 1);
RTYPEDDATA_DATA(obj) = ctx;
SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj);
@@ -104,7 +104,7 @@ ossl_call_client_cert_cb(VALUE obj)
ctx_obj = rb_attr_get(obj, id_i_context);
cb = rb_attr_get(ctx_obj, id_i_client_cert_cb);
if (NIL_P(cb))
- return Qnil;
+ return Qnil;
ary = rb_funcallv(cb, id_call, 1, &obj);
Check_Type(ary, T_ARRAY);
@@ -122,7 +122,7 @@ ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
ret = rb_protect(ossl_call_client_cert_cb, obj, NULL);
if (NIL_P(ret))
- return 0;
+ return 0;
*x509 = DupX509CertPtr(RARRAY_AREF(ret, 0));
*pkey = DupPKeyPtr(RARRAY_AREF(ret, 1));
@@ -133,8 +133,6 @@ ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
#if !defined(OPENSSL_NO_DH)
struct tmp_dh_callback_args {
VALUE ssl_obj;
- ID id;
- int type;
int is_export;
int keylength;
};
@@ -143,48 +141,36 @@ static VALUE
ossl_call_tmp_dh_callback(VALUE arg)
{
struct tmp_dh_callback_args *args = (struct tmp_dh_callback_args *)arg;
- VALUE cb, dh;
- EVP_PKEY *pkey;
+ VALUE ctx_obj, cb, obj;
+ const DH *dh;
- cb = rb_funcall(args->ssl_obj, args->id, 0);
+ ctx_obj = rb_attr_get(args->ssl_obj, id_i_context);
+ cb = rb_attr_get(ctx_obj, id_i_tmp_dh_callback);
if (NIL_P(cb))
- return (VALUE)NULL;
- dh = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
- INT2NUM(args->keylength));
- pkey = GetPKeyPtr(dh);
- if (EVP_PKEY_base_id(pkey) != args->type)
- return (VALUE)NULL;
+ return (VALUE)NULL;
+
+ obj = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),
+ INT2NUM(args->keylength));
+ // TODO: We should riase if obj is not DH
+ dh = EVP_PKEY_get0_DH(GetPKeyPtr(obj));
+ if (!dh)
+ ossl_clear_error();
- return (VALUE)pkey;
+ return (VALUE)dh;
}
-#endif
-#if !defined(OPENSSL_NO_DH)
static DH *
ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
{
- VALUE rb_ssl;
- EVP_PKEY *pkey;
- struct tmp_dh_callback_args args;
int state;
-
- rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
- args.ssl_obj = rb_ssl;
- args.id = id_tmp_dh_callback;
- args.is_export = is_export;
- args.keylength = keylength;
- args.type = EVP_PKEY_DH;
-
- pkey = (EVP_PKEY *)rb_protect(ossl_call_tmp_dh_callback,
- (VALUE)&args, &state);
+ VALUE rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+ struct tmp_dh_callback_args args = {rb_ssl, is_export, keylength};
+ VALUE ret = rb_protect(ossl_call_tmp_dh_callback, (VALUE)&args, &state);
if (state) {
- rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state));
- return NULL;
+ rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state));
+ return NULL;
}
- if (!pkey)
- return NULL;
-
- return (DH *)EVP_PKEY_get0_DH(pkey);
+ return (DH *)ret;
}
#endif /* OPENSSL_NO_DH */
@@ -200,13 +186,13 @@ call_verify_certificate_identity(VALUE ctx_v)
hostname = rb_attr_get(ssl_obj, id_i_hostname);
if (!RTEST(hostname)) {
- rb_warning("verify_hostname requires hostname to be set");
- return Qtrue;
+ rb_warning("verify_hostname requires hostname to be set");
+ return Qtrue;
}
cert_obj = ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
return rb_funcall(mSSL, rb_intern("verify_certificate_identity"), 2,
- cert_obj, hostname);
+ cert_obj, hostname);
}
static int
@@ -223,12 +209,12 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
verify_hostname = rb_attr_get(sslctx_obj, id_i_verify_hostname);
if (preverify_ok && RTEST(verify_hostname) && !SSL_is_server(ssl) &&
- !X509_STORE_CTX_get_error_depth(ctx)) {
- ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status);
- if (status) {
- rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
- return 0;
- }
+ !X509_STORE_CTX_get_error_depth(ctx)) {
+ ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status);
+ if (status) {
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
+ return 0;
+ }
if (ret != Qtrue) {
preverify_ok = 0;
X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH);
@@ -399,7 +385,7 @@ ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
* when SSL_CTX_free() is called.
*/
if (rb_during_gc())
- return;
+ return;
OSSL_Debug("SSL SESSION remove callback entered");
@@ -430,8 +416,9 @@ ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
GetSSLCTX(arg, ctx);
x509 = DupX509CertPtr(i);
- if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){
- ossl_raise(eSSLError, NULL);
+ if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {
+ X509_free(x509);
+ ossl_raise(eSSLError, "SSL_CTX_add_extra_chain_cert");
}
return i;
@@ -461,8 +448,8 @@ ossl_call_servername_cb(VALUE arg)
ossl_raise(eSSLError, "SSL_set_SSL_CTX");
rb_ivar_set(ssl_obj, id_i_context, ret_obj);
} else if (!NIL_P(ret_obj)) {
- ossl_raise(rb_eArgError, "servername_cb must return an "
- "OpenSSL::SSL::SSLContext object or nil");
+ ossl_raise(rb_eArgError, "servername_cb must return an "
+ "OpenSSL::SSL::SSLContext object or nil");
}
return Qnil;
@@ -502,7 +489,7 @@ ssl_npn_encode_protocol_i(RB_BLOCK_CALL_FUNC_ARGLIST(cur, encoded))
int len = RSTRING_LENINT(cur);
char len_byte;
if (len < 1 || len > 255)
- ossl_raise(eSSLError, "Advertised protocol must have length 1..255");
+ ossl_raise(eSSLError, "Advertised protocol must have length 1..255");
/* Encode the length byte */
len_byte = len;
rb_str_buf_cat(encoded, &len_byte, 1);
@@ -536,16 +523,16 @@ npn_select_cb_common_i(VALUE tmp)
/* assume OpenSSL verifies this format */
/* The format is len_1|proto_1|...|len_n|proto_n */
while (in < in_end) {
- l = *in++;
- rb_ary_push(protocols, rb_str_new((const char *)in, l));
- in += l;
+ l = *in++;
+ rb_ary_push(protocols, rb_str_new((const char *)in, l));
+ in += l;
}
selected = rb_funcallv(args->cb, id_call, 1, &protocols);
StringValue(selected);
len = RSTRING_LEN(selected);
if (len < 1 || len >= 256) {
- ossl_raise(eSSLError, "Selected protocol name must have length 1..255");
+ ossl_raise(eSSLError, "Selected protocol name must have length 1..255");
}
return selected;
@@ -553,8 +540,8 @@ npn_select_cb_common_i(VALUE tmp)
static int
ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
- unsigned char *outlen, const unsigned char *in,
- unsigned int inlen)
+ unsigned char *outlen, const unsigned char *in,
+ unsigned int inlen)
{
VALUE selected;
int status;
@@ -566,10 +553,10 @@ ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
selected = rb_protect(npn_select_cb_common_i, (VALUE)&args, &status);
if (status) {
- VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+ VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
- rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
- return SSL_TLSEXT_ERR_ALERT_FATAL;
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}
*out = (unsigned char *)RSTRING_PTR(selected);
@@ -581,7 +568,7 @@ ssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,
#ifdef OSSL_USE_NEXTPROTONEG
static int
ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen,
- void *arg)
+ void *arg)
{
VALUE protocols = rb_attr_get((VALUE)arg, id_npn_protocols_encoded);
@@ -593,7 +580,7 @@ ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen,
static int
ssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
+ const unsigned char *in, unsigned int inlen, void *arg)
{
VALUE sslctx_obj, cb;
@@ -601,13 +588,13 @@ ssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
cb = rb_attr_get(sslctx_obj, id_i_npn_select_cb);
return ssl_npn_select_cb_common(ssl, cb, (const unsigned char **)out,
- outlen, in, inlen);
+ outlen, in, inlen);
}
#endif
static int
ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
+ const unsigned char *in, unsigned int inlen, void *arg)
{
VALUE sslctx_obj, cb;
@@ -624,7 +611,7 @@ ssl_info_cb(const SSL *ssl, int where, int val)
int is_server = SSL_is_server((SSL *)ssl);
if (is_server && where & SSL_CB_HANDSHAKE_START) {
- ssl_renegotiation_cb(ssl);
+ ssl_renegotiation_cb(ssl);
}
}
@@ -670,9 +657,9 @@ ossl_sslctx_set_options(VALUE self, VALUE options)
SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx));
if (NIL_P(options)) {
- SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ SSL_CTX_set_options(ctx, SSL_OP_ALL);
} else {
- SSL_CTX_set_options(ctx, NUM2ULONG(options));
+ SSL_CTX_set_options(ctx, NUM2ULONG(options));
}
return self;
@@ -702,7 +689,10 @@ ossl_sslctx_setup(VALUE self)
GetSSLCTX(self, ctx);
#if !defined(OPENSSL_NO_DH)
- SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
+ if (!NIL_P(rb_attr_get(self, id_i_tmp_dh_callback))) {
+ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
+ SSL_CTX_set_dh_auto(ctx, 0);
+ }
#endif
#if !defined(OPENSSL_IS_AWSLC) /* AWS-LC has no support for TLS 1.3 PHA. */
@@ -711,14 +701,14 @@ ossl_sslctx_setup(VALUE self)
val = rb_attr_get(self, id_i_cert_store);
if (!NIL_P(val)) {
- X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
- SSL_CTX_set_cert_store(ctx, store);
- X509_STORE_up_ref(store);
+ X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
+ SSL_CTX_set_cert_store(ctx, store);
+ X509_STORE_up_ref(store);
}
val = rb_attr_get(self, id_i_extra_chain_cert);
if(!NIL_P(val)){
- rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
+ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
}
/* private key may be bundled in certificate file. */
@@ -742,22 +732,22 @@ ossl_sslctx_setup(VALUE self)
val = rb_attr_get(self, id_i_client_ca);
if(!NIL_P(val)){
- if (RB_TYPE_P(val, T_ARRAY)) {
- for(i = 0; i < RARRAY_LEN(val); i++){
- client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
- if (!SSL_CTX_add_client_CA(ctx, client_ca)){
- /* Copies X509_NAME => FREE it. */
- ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
- }
- }
+ if (RB_TYPE_P(val, T_ARRAY)) {
+ for(i = 0; i < RARRAY_LEN(val); i++){
+ client_ca = GetX509CertPtr(RARRAY_AREF(val, i));
+ if (!SSL_CTX_add_client_CA(ctx, client_ca)){
+ /* Copies X509_NAME => FREE it. */
+ ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+ }
+ }
}
- else{
- client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
+ else{
+ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
- /* Copies X509_NAME => FREE it. */
- ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+ /* Copies X509_NAME => FREE it. */
+ ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
}
- }
+ }
}
val = rb_attr_get(self, id_i_ca_file);
@@ -780,7 +770,7 @@ ossl_sslctx_setup(VALUE self)
verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
if (RTEST(rb_attr_get(self, id_i_client_cert_cb)))
- SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
+ SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
val = rb_attr_get(self, id_i_timeout);
if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
@@ -791,60 +781,60 @@ ossl_sslctx_setup(VALUE self)
#ifdef OSSL_USE_NEXTPROTONEG
val = rb_attr_get(self, id_i_npn_protocols);
if (!NIL_P(val)) {
- VALUE encoded = ssl_encode_npn_protocols(val);
- rb_ivar_set(self, id_npn_protocols_encoded, encoded);
- SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self);
- OSSL_Debug("SSL NPN advertise callback added");
+ VALUE encoded = ssl_encode_npn_protocols(val);
+ rb_ivar_set(self, id_npn_protocols_encoded, encoded);
+ SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self);
+ OSSL_Debug("SSL NPN advertise callback added");
}
if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) {
- SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
- OSSL_Debug("SSL NPN select callback added");
+ SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);
+ OSSL_Debug("SSL NPN select callback added");
}
#endif
val = rb_attr_get(self, id_i_alpn_protocols);
if (!NIL_P(val)) {
- VALUE rprotos = ssl_encode_npn_protocols(val);
+ VALUE rprotos = ssl_encode_npn_protocols(val);
- /* returns 0 on success */
- if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
- RSTRING_LENINT(rprotos)))
- ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
- OSSL_Debug("SSL ALPN values added");
+ /* returns 0 on success */
+ if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),
+ RSTRING_LENINT(rprotos)))
+ ossl_raise(eSSLError, "SSL_CTX_set_alpn_protos");
+ OSSL_Debug("SSL ALPN values added");
}
if (RTEST(rb_attr_get(self, id_i_alpn_select_cb))) {
- SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
- OSSL_Debug("SSL ALPN select callback added");
+ SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
+ OSSL_Debug("SSL ALPN select callback added");
}
rb_obj_freeze(self);
val = rb_attr_get(self, id_i_session_id_context);
if (!NIL_P(val)){
- StringValue(val);
- if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
- RSTRING_LENINT(val))){
- ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
- }
+ StringValue(val);
+ if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
+ RSTRING_LENINT(val))){
+ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context");
+ }
}
if (RTEST(rb_attr_get(self, id_i_session_get_cb))) {
- SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
- OSSL_Debug("SSL SESSION get callback added");
+ SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
+ OSSL_Debug("SSL SESSION get callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_new_cb))) {
- SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
- OSSL_Debug("SSL SESSION new callback added");
+ SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
+ OSSL_Debug("SSL SESSION new callback added");
}
if (RTEST(rb_attr_get(self, id_i_session_remove_cb))) {
- SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
- OSSL_Debug("SSL SESSION remove callback added");
+ SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
+ OSSL_Debug("SSL SESSION remove callback added");
}
val = rb_attr_get(self, id_i_servername_cb);
if (!NIL_P(val)) {
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
- OSSL_Debug("SSL TLSEXT servername callback added");
+ OSSL_Debug("SSL TLSEXT servername callback added");
}
#if !OSSL_IS_LIBRESSL
@@ -867,28 +857,28 @@ parse_proto_version(VALUE str)
{
int i;
static const struct {
- const char *name;
- int version;
+ const char *name;
+ int version;
} map[] = {
- { "SSL2", SSL2_VERSION },
- { "SSL3", SSL3_VERSION },
- { "TLS1", TLS1_VERSION },
- { "TLS1_1", TLS1_1_VERSION },
- { "TLS1_2", TLS1_2_VERSION },
- { "TLS1_3", TLS1_3_VERSION },
+ { "SSL2", SSL2_VERSION },
+ { "SSL3", SSL3_VERSION },
+ { "TLS1", TLS1_VERSION },
+ { "TLS1_1", TLS1_1_VERSION },
+ { "TLS1_2", TLS1_2_VERSION },
+ { "TLS1_3", TLS1_3_VERSION },
};
if (NIL_P(str))
- return 0;
+ return 0;
if (RB_INTEGER_TYPE_P(str))
- return NUM2INT(str);
+ return NUM2INT(str);
if (SYMBOL_P(str))
- str = rb_sym2str(str);
+ str = rb_sym2str(str);
StringValue(str);
for (i = 0; i < numberof(map); i++)
- if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str)))
- return map[i].version;
+ if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str)))
+ return map[i].version;
rb_raise(rb_eArgError, "unrecognized version %+"PRIsVALUE, str);
}
@@ -998,11 +988,10 @@ static VALUE
build_cipher_string(VALUE v)
{
VALUE str, elem;
- int i;
if (RB_TYPE_P(v, T_ARRAY)) {
str = rb_str_new(0, 0);
- for (i = 0; i < RARRAY_LEN(v); i++) {
+ for (long i = 0; i < RARRAY_LEN(v); i++) {
elem = rb_ary_entry(v, i);
if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);
elem = rb_String(elem);
@@ -1023,9 +1012,14 @@ build_cipher_string(VALUE v)
* ctx.ciphers = [name, ...]
* ctx.ciphers = [[name, version, bits, alg_bits], ...]
*
- * Sets the list of available cipher suites for this context. Note in a server
- * context some ciphers require the appropriate certificates. For example, an
- * RSA cipher suite can only be chosen when an RSA certificate is available.
+ * Sets the list of available cipher suites for TLS 1.2 and below for this
+ * context.
+ *
+ * Note in a server context some ciphers require the appropriate certificates.
+ * For example, an RSA cipher suite can only be chosen when an RSA certificate
+ * is available.
+ *
+ * This method does not affect TLS 1.3 connections. See also #ciphersuites=.
*/
static VALUE
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
@@ -1034,6 +1028,7 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
VALUE str;
rb_check_frozen(self);
+ // Assigning nil is a no-op for compatibility
if (NIL_P(v))
return v;
@@ -1050,9 +1045,8 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
* call-seq:
* ctx.ciphersuites = "cipher1:cipher2:..."
* ctx.ciphersuites = [name, ...]
- * ctx.ciphersuites = [[name, version, bits, alg_bits], ...]
*
- * Sets the list of available TLSv1.3 cipher suites for this context.
+ * Sets the list of available TLS 1.3 cipher suites for this context.
*/
static VALUE
ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
@@ -1061,6 +1055,7 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
VALUE str;
rb_check_frozen(self);
+ // Assigning nil is a no-op for compatibility
if (NIL_P(v))
return v;
@@ -1073,6 +1068,63 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
return v;
}
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST
+/*
+ * call-seq:
+ * ctx.sigalgs = "sigalg1:sigalg2:..."
+ *
+ * Sets the list of "supported signature algorithms" for this context.
+ *
+ * For a TLS client, the list is used in the "signature_algorithms" extension
+ * in the ClientHello message. For a server, the list is used by OpenSSL to
+ * determine the set of shared signature algorithms. OpenSSL will pick the most
+ * appropriate one from it.
+ *
+ * See also #client_sigalgs= for the client authentication equivalent.
+ */
+static VALUE
+ossl_sslctx_set_sigalgs(VALUE self, VALUE v)
+{
+ SSL_CTX *ctx;
+
+ rb_check_frozen(self);
+ GetSSLCTX(self, ctx);
+
+ if (!SSL_CTX_set1_sigalgs_list(ctx, StringValueCStr(v)))
+ ossl_raise(eSSLError, "SSL_CTX_set1_sigalgs_list");
+
+ return v;
+}
+#endif
+
+#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST
+/*
+ * call-seq:
+ * ctx.client_sigalgs = "sigalg1:sigalg2:..."
+ *
+ * Sets the list of "supported signature algorithms" for client authentication
+ * for this context.
+ *
+ * For a TLS server, the list is sent to the client as part of the
+ * CertificateRequest message.
+ *
+ * See also #sigalgs= for the server authentication equivalent.
+ */
+static VALUE
+ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)
+{
+ SSL_CTX *ctx;
+
+ rb_check_frozen(self);
+ GetSSLCTX(self, ctx);
+
+ if (!SSL_CTX_set1_client_sigalgs_list(ctx, StringValueCStr(v)))
+ ossl_raise(eSSLError, "SSL_CTX_set1_client_sigalgs_list");
+
+ return v;
+}
+#endif
+
#ifndef OPENSSL_NO_DH
/*
* call-seq:
@@ -1085,7 +1137,7 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
* contained in the key object, if any, are ignored. The server will always
* generate a new key pair for each handshake.
*
- * Added in version 3.0. See also the man page SSL_set0_tmp_dh_pkey(3).
+ * Added in version 3.0. See also the man page SSL_CTX_set0_tmp_dh_pkey(3).
*
* Example:
* ctx = OpenSSL::SSL::SSLContext.new
@@ -1106,7 +1158,7 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH)
rb_raise(eSSLError, "invalid pkey type %s (expected DH)",
OBJ_nid2sn(EVP_PKEY_base_id(pkey)));
-#ifdef HAVE_SSL_SET0_TMP_DH_PKEY
+#ifdef HAVE_SSL_CTX_SET0_TMP_DH_PKEY
if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))
ossl_raise(eSSLError, "SSL_CTX_set0_tmp_dh_pkey");
EVP_PKEY_up_ref(pkey);
@@ -1115,29 +1167,36 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
ossl_raise(eSSLError, "SSL_CTX_set_tmp_dh");
#endif
+ // Turn off the "auto" DH parameters set by ossl_sslctx_s_alloc()
+ SSL_CTX_set_dh_auto(ctx, 0);
+
return arg;
}
#endif
-#if !defined(OPENSSL_NO_EC)
/*
* call-seq:
- * ctx.ecdh_curves = curve_list -> curve_list
+ * ctx.groups = groups_list
+ * ctx.ecdh_curves = groups_list
+ *
+ * Sets the list of supported groups for key agreement for this context.
*
- * Sets the list of "supported elliptic curves" for this context.
+ * For a TLS client, the list is directly used in the "supported_groups"
+ * extension. For a server, the list is used by OpenSSL to determine the set of
+ * shared supported groups. OpenSSL will pick the most appropriate one from it.
*
- * For a TLS client, the list is directly used in the Supported Elliptic Curves
- * Extension. For a server, the list is used by OpenSSL to determine the set of
- * shared curves. OpenSSL will pick the most appropriate one from it.
+ * #ecdh_curves= is a deprecated alias for #groups=.
+ *
+ * See also the man page SSL_CTX_set1_groups_list(3).
*
* === Example
* ctx1 = OpenSSL::SSL::SSLContext.new
- * ctx1.ecdh_curves = "X25519:P-256:P-224"
+ * ctx1.groups = "X25519:P-256:P-224"
* svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1)
* Thread.new { svr.accept }
*
* ctx2 = OpenSSL::SSL::SSLContext.new
- * ctx2.ecdh_curves = "P-256"
+ * ctx2.groups = "P-256"
* cli = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx2)
* cli.connect
*
@@ -1145,7 +1204,7 @@ ossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)
* # => "prime256v1" (is an alias for NIST P-256)
*/
static VALUE
-ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
+ossl_sslctx_set_groups(VALUE self, VALUE arg)
{
SSL_CTX *ctx;
@@ -1153,13 +1212,10 @@ ossl_sslctx_set_ecdh_curves(VALUE self, VALUE arg)
GetSSLCTX(self, ctx);
StringValueCStr(arg);
- if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg)))
- ossl_raise(eSSLError, NULL);
+ if (!SSL_CTX_set1_groups_list(ctx, RSTRING_PTR(arg)))
+ ossl_raise(eSSLError, "SSL_CTX_set1_groups_list");
return arg;
}
-#else
-#define ossl_sslctx_set_ecdh_curves rb_f_notimplement
-#endif
/*
* call-seq:
@@ -1288,20 +1344,20 @@ ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)
pub_pkey = X509_get_pubkey(x509);
EVP_PKEY_free(pub_pkey);
if (!pub_pkey)
- rb_raise(rb_eArgError, "certificate does not contain public key");
+ rb_raise(rb_eArgError, "certificate does not contain public key");
if (EVP_PKEY_eq(pub_pkey, pkey) != 1)
- rb_raise(rb_eArgError, "public key mismatch");
+ rb_raise(rb_eArgError, "public key mismatch");
if (argc >= 3)
- extra_chain = ossl_x509_ary2sk(extra_chain_ary);
+ extra_chain = ossl_x509_ary2sk(extra_chain_ary);
if (!SSL_CTX_use_certificate(ctx, x509)) {
- sk_X509_pop_free(extra_chain, X509_free);
- ossl_raise(eSSLError, "SSL_CTX_use_certificate");
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_certificate");
}
if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
- sk_X509_pop_free(extra_chain, X509_free);
- ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
+ sk_X509_pop_free(extra_chain, X509_free);
+ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
}
if (extra_chain && !SSL_CTX_set0_chain(ctx, extra_chain)) {
sk_X509_pop_free(extra_chain, X509_free);
@@ -1534,32 +1590,31 @@ ossl_ssl_s_alloc(VALUE klass)
}
static VALUE
-peer_ip_address(VALUE self)
+peer_ip_address(VALUE io)
{
- VALUE remote_address = rb_funcall(rb_attr_get(self, id_i_io), rb_intern("remote_address"), 0);
+ VALUE remote_address = rb_funcall(io, rb_intern("remote_address"), 0);
return rb_funcall(remote_address, rb_intern("inspect_sockaddr"), 0);
}
static VALUE
-fallback_peer_ip_address(VALUE self, VALUE args)
+fallback_peer_ip_address(VALUE self, VALUE exc)
{
return rb_str_new_cstr("(null)");
}
static VALUE
-peeraddr_ip_str(VALUE self)
+peeraddr_ip_str(VALUE io)
{
- VALUE rb_mErrno = rb_const_get(rb_cObject, rb_intern("Errno"));
- VALUE rb_eSystemCallError = rb_const_get(rb_mErrno, rb_intern("SystemCallError"));
-
- return rb_rescue2(peer_ip_address, self, fallback_peer_ip_address, (VALUE)0, rb_eSystemCallError, NULL);
+ return rb_rescue2(peer_ip_address, io, fallback_peer_ip_address, Qnil,
+ rb_eSystemCallError, (VALUE)0);
}
/*
* call-seq:
* SSLSocket.new(io) => aSSLSocket
* SSLSocket.new(io, ctx) => aSSLSocket
+ * SSLSocket.new(io, ctx, sync_close:) => aSSLSocket
*
* Creates a new SSL socket from _io_ which must be a real IO object (not an
* IO-like object that responds to read/write).
@@ -1567,6 +1622,10 @@ peeraddr_ip_str(VALUE self)
* If _ctx_ is provided the SSL Sockets initial params will be taken from
* the context.
*
+ * The optional _sync_close_ keyword parameter sets the _sync_close_ instance
+ * variable. Setting this to +true+ will cause the underlying socket to be
+ * closed when the SSL/TLS connection is shut down.
+ *
* The OpenSSL::Buffering module provides additional IO methods.
*
* This method will freeze the SSLContext if one is provided;
@@ -1575,29 +1634,42 @@ peeraddr_ip_str(VALUE self)
static VALUE
ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
{
+ static ID kw_ids[1];
+ VALUE kw_args[1];
+ VALUE opts;
+
VALUE io, v_ctx;
SSL *ssl;
SSL_CTX *ctx;
TypedData_Get_Struct(self, SSL, &ossl_ssl_type, ssl);
if (ssl)
- ossl_raise(eSSLError, "SSL already initialized");
+ ossl_raise(eSSLError, "SSL already initialized");
- if (rb_scan_args(argc, argv, "11", &io, &v_ctx) == 1)
- v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+ if (rb_scan_args(argc, argv, "11:", &io, &v_ctx, &opts) == 1)
+ v_ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+
+ if (!kw_ids[0]) {
+ kw_ids[0] = rb_intern_const("sync_close");
+ }
+
+ rb_get_kwargs(opts, kw_ids, 0, 1, kw_args);
+ if (kw_args[0] != Qundef) {
+ rb_ivar_set(self, id_i_sync_close, kw_args[0]);
+ }
GetSSLCTX(v_ctx, ctx);
rb_ivar_set(self, id_i_context, v_ctx);
ossl_sslctx_setup(v_ctx);
if (rb_respond_to(io, rb_intern("nonblock=")))
- rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
+ rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
Check_Type(io, T_FILE);
rb_ivar_set(self, id_i_io, io);
ssl = SSL_new(ctx);
if (!ssl)
- ossl_raise(eSSLError, NULL);
+ ossl_raise(eSSLError, NULL);
RTYPEDDATA_DATA(self) = ssl;
SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self);
@@ -1628,7 +1700,7 @@ ossl_ssl_setup(VALUE self)
GetSSL(self, ssl);
if (ssl_started(ssl))
- return Qtrue;
+ return Qtrue;
io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
@@ -1640,24 +1712,28 @@ ossl_ssl_setup(VALUE self)
return Qtrue;
}
+static int
+errno_mapped(void)
+{
#ifdef _WIN32
-#define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error((ssl), (ret)))
+ return rb_w32_map_errno(WSAGetLastError());
#else
-#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret))
+ return errno;
#endif
+}
static void
write_would_block(int nonblock)
{
if (nonblock)
- ossl_raise(eSSLErrorWaitWritable, "write would block");
+ ossl_raise(eSSLErrorWaitWritable, "write would block");
}
static void
read_would_block(int nonblock)
{
if (nonblock)
- ossl_raise(eSSLErrorWaitReadable, "read would block");
+ ossl_raise(eSSLErrorWaitReadable, "read would block");
}
static int
@@ -1665,7 +1741,7 @@ no_exception_p(VALUE opts)
{
if (RB_TYPE_P(opts, T_HASH) &&
rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse)
- return 1;
+ return 1;
return 0;
}
@@ -1685,13 +1761,13 @@ static void
io_wait_writable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ if (!rb_io_wait(io, INT2NUM(RUBY_IO_WRITABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
- rb_io_wait_writable(fptr->fd);
+ rb_thread_fd_writable(fptr->fd);
#endif
}
@@ -1699,13 +1775,13 @@ static void
io_wait_readable(VALUE io)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
+ if (!rb_io_wait(io, INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
}
#else
rb_io_t *fptr;
GetOpenFile(io, fptr);
- rb_io_wait_readable(fptr->fd);
+ rb_thread_wait_fd(fptr->fd);
#endif
}
@@ -1713,7 +1789,6 @@ static VALUE
ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
{
SSL *ssl;
- int ret, ret2;
VALUE cb_state;
int nonblock = opts != Qfalse;
@@ -1723,7 +1798,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
VALUE io = rb_attr_get(self, id_i_io);
for (;;) {
- ret = func(ssl);
+ int ret = func(ssl);
+ int saved_errno = errno_mapped();
cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
@@ -1735,7 +1811,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
if (ret > 0)
break;
- switch ((ret2 = ssl_get_error(ssl, ret))) {
+ int code = SSL_get_error(ssl, ret);
+ switch (code) {
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
@@ -1749,10 +1826,11 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
/* See ossl_ssl_write_internal() */
- if (errno == EPROTOTYPE)
+ if (saved_errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(funcname);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, funcname));
/* fallthrough */
default: {
VALUE error_append = Qnil;
@@ -1773,10 +1851,10 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
ossl_raise(eSSLError,
"%s%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s%"PRIsVALUE,
funcname,
- ret2 == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
- ret2,
- errno,
- peeraddr_ip_str(self),
+ code == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
+ code,
+ saved_errno,
+ peeraddr_ip_str(io),
SSL_state_string_long(ssl),
error_append);
}
@@ -1889,9 +1967,9 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
VALUE opts = Qnil;
if (nonblock) {
- rb_scan_args(argc, argv, "11:", &len, &str, &opts);
+ rb_scan_args(argc, argv, "11:", &len, &str, &opts);
} else {
- rb_scan_args(argc, argv, "11", &len, &str);
+ rb_scan_args(argc, argv, "11", &len, &str);
}
GetSSL(self, ssl);
if (!ssl_started(ssl))
@@ -1899,13 +1977,13 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
ilen = NUM2INT(len);
if (NIL_P(str))
- str = rb_str_new(0, ilen);
+ str = rb_str_new(0, ilen);
else {
- StringValue(str);
- if (RSTRING_LEN(str) >= ilen)
- rb_str_modify(str);
- else
- rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
+ StringValue(str);
+ if (RSTRING_LEN(str) >= ilen)
+ rb_str_modify(str);
+ else
+ rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
}
if (ilen == 0) {
@@ -1918,6 +1996,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
for (;;) {
rb_str_locktmp(str);
int nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
+ int saved_errno = errno_mapped();
rb_str_unlocktmp(str);
cb_state = rb_attr_get(self, ID_callback_state);
@@ -1927,7 +2006,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
rb_jump_tag(NUM2INT(cb_state));
}
- switch (ssl_get_error(ssl, nread)) {
+ switch (SSL_get_error(ssl, nread)) {
case SSL_ERROR_NONE:
rb_str_set_len(str, nread);
return str;
@@ -1950,8 +2029,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
break;
case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) {
- if (errno)
- rb_sys_fail(0);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, "SSL_read"));
else {
/*
* The underlying BIO returned 0. This is actually a
@@ -2036,6 +2115,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
for (;;) {
int nwritten = SSL_write(ssl, RSTRING_PTR(str), num);
+ int saved_errno = errno_mapped();
cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
@@ -2044,7 +2124,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
rb_jump_tag(NUM2INT(cb_state));
}
- switch (ssl_get_error(ssl, nwritten)) {
+ switch (SSL_get_error(ssl, nwritten)) {
case SSL_ERROR_NONE:
return INT2NUM(nwritten);
case SSL_ERROR_WANT_WRITE:
@@ -2065,10 +2145,11 @@ ossl_ssl_write_internal_safe(VALUE _args)
* make the error handling in line with the socket library.
* [Bug #14713] https://bugs.ruby-lang.org/issues/14713
*/
- if (errno == EPROTOTYPE)
+ if (saved_errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(0);
+ if (saved_errno)
+ rb_exc_raise(rb_syserr_new(saved_errno, "SSL_write"));
/* fallthrough */
default:
ossl_raise(eSSLError, "SSL_write");
@@ -2142,12 +2223,12 @@ ossl_ssl_stop(VALUE self)
GetSSL(self, ssl);
if (!ssl_started(ssl))
- return Qnil;
+ return Qnil;
ret = SSL_shutdown(ssl);
if (ret == 1) /* Have already received close_notify */
- return Qnil;
+ return Qnil;
if (ret == 0) /* Sent close_notify, but we don't wait for reply */
- return Qnil;
+ return Qnil;
/*
* XXX: Something happened. Possibly it failed because the underlying socket
@@ -2233,20 +2314,20 @@ ossl_ssl_get_peer_cert_chain(VALUE self)
num = sk_X509_num(chain);
ary = rb_ary_new2(num);
for (i = 0; i < num; i++){
- cert = sk_X509_value(chain, i);
- rb_ary_push(ary, ossl_x509_new(cert));
+ cert = sk_X509_value(chain, i);
+ rb_ary_push(ary, ossl_x509_new(cert));
}
return ary;
}
/*
-* call-seq:
-* ssl.ssl_version => String
-*
-* Returns a String representing the SSL/TLS version that was negotiated
-* for the connection, for example "TLSv1.2".
-*/
+ * call-seq:
+ * ssl.ssl_version => String
+ *
+ * Returns a String representing the SSL/TLS version that was negotiated
+ * for the connection, for example "TLSv1.2".
+ */
static VALUE
ossl_ssl_get_version(VALUE self)
{
@@ -2367,10 +2448,10 @@ ossl_ssl_set_hostname(VALUE self, VALUE arg)
GetSSL(self, ssl);
if (!NIL_P(arg))
- hostname = StringValueCStr(arg);
+ hostname = StringValueCStr(arg);
if (!SSL_set_tlsext_host_name(ssl, hostname))
- ossl_raise(eSSLError, NULL);
+ ossl_raise(eSSLError, NULL);
/* for SSLSocket#hostname */
rb_ivar_set(self, id_i_hostname, arg);
@@ -2491,9 +2572,9 @@ ossl_ssl_npn_protocol(VALUE self)
SSL_get0_next_proto_negotiated(ssl, &out, &outlen);
if (!outlen)
- return Qnil;
+ return Qnil;
else
- return rb_str_new((const char *) out, outlen);
+ return rb_str_new((const char *) out, outlen);
}
# endif
@@ -2515,9 +2596,9 @@ ossl_ssl_alpn_protocol(VALUE self)
SSL_get0_alpn_selected(ssl, &out, &outlen);
if (!outlen)
- return Qnil;
+ return Qnil;
else
- return rb_str_new((const char *) out, outlen);
+ return rb_str_new((const char *) out, outlen);
}
/*
@@ -2550,15 +2631,15 @@ ossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self)
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (!NIL_P(context)) {
- use_ctx = 1;
- StringValue(context);
- ctx = (unsigned char *)RSTRING_PTR(context);
- ctx_len = RSTRING_LEN(context);
+ use_ctx = 1;
+ StringValue(context);
+ ctx = (unsigned char *)RSTRING_PTR(context);
+ ctx_len = RSTRING_LEN(context);
}
ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label),
- RSTRING_LENINT(label), ctx, ctx_len, use_ctx);
+ RSTRING_LENINT(label), ctx, ctx_len, use_ctx);
if (ret == 0 || ret == -1) {
- ossl_raise(eSSLError, "SSL_export_keying_material");
+ ossl_raise(eSSLError, "SSL_export_keying_material");
}
return str;
}
@@ -2577,17 +2658,77 @@ ossl_ssl_tmp_key(VALUE self)
GetSSL(self, ssl);
if (!SSL_get_server_tmp_key(ssl, &key))
- return Qnil;
- return ossl_pkey_new(key);
+ return Qnil;
+ return ossl_pkey_wrap(key);
+}
+
+#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME
+/*
+ * call-seq:
+ * ssl.sigalg => String or nil
+ *
+ * Returns the signature algorithm name, the IANA name of the signature scheme
+ * used by the local to sign the TLS handshake.
+ */
+static VALUE
+ossl_ssl_get_sigalg(VALUE self)
+{
+ SSL *ssl;
+ const char *name;
+
+ GetSSL(self, ssl);
+ if (!SSL_get0_signature_name(ssl, &name))
+ return Qnil;
+ return rb_str_new_cstr(name);
+}
+
+/*
+ * call-seq:
+ * ssl.peer_sigalg => String or nil
+ *
+ * Returns the signature algorithm name, the IANA name of the signature scheme
+ * used by the peer to sign the TLS handshake.
+ */
+static VALUE
+ossl_ssl_get_peer_sigalg(VALUE self)
+{
+ SSL *ssl;
+ const char *name;
+
+ GetSSL(self, ssl);
+ if (!SSL_get0_peer_signature_name(ssl, &name))
+ return Qnil;
+ return rb_str_new_cstr(name);
+}
+#endif
+
+#ifdef HAVE_SSL_GET0_GROUP_NAME
+/*
+ * call-seq:
+ * ssl.group => String or nil
+ *
+ * Returns the name of the group that was used for the key agreement of the
+ * current TLS session establishment.
+ */
+static VALUE
+ossl_ssl_get_group(VALUE self)
+{
+ SSL *ssl;
+ const char *name;
+
+ GetSSL(self, ssl);
+ if (!(name = SSL_get0_group_name(ssl)))
+ return Qnil;
+ return rb_str_new_cstr(name);
}
+#endif
+
#endif /* !defined(OPENSSL_NO_SOCK) */
void
Init_ossl_ssl(void)
{
#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
#endif
@@ -2598,10 +2739,10 @@ Init_ossl_ssl(void)
ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_ptr_idx", 0, 0, 0);
if (ossl_ssl_ex_ptr_idx < 0)
- ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
+ ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
ossl_sslctx_ex_ptr_idx = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_ptr_idx", 0, 0, 0);
if (ossl_sslctx_ex_ptr_idx < 0)
- ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
+ ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
/* Document-module: OpenSSL::SSL
*
@@ -2739,6 +2880,23 @@ Init_ossl_ssl(void)
*/
rb_attr(cSSLContext, rb_intern_const("client_cert_cb"), 1, 1, Qfalse);
+#ifndef OPENSSL_NO_DH
+ /*
+ * A callback invoked when DH parameters are required for ephemeral DH key
+ * exchange.
+ *
+ * The callback is invoked with the SSLSocket, a
+ * flag indicating the use of an export cipher and the keylength
+ * required.
+ *
+ * The callback must return an OpenSSL::PKey::DH instance of the correct
+ * key length.
+ *
+ * <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.
+ */
+ rb_attr(cSSLContext, rb_intern_const("tmp_dh_callback"), 1, 1, Qfalse);
+#endif
+
/*
* Sets the context in which a session can be reused. This allows
* sessions for multiple applications to be distinguished, for example, by
@@ -2886,10 +3044,17 @@ Init_ossl_ssl(void)
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
rb_define_method(cSSLContext, "ciphersuites=", ossl_sslctx_set_ciphersuites, 1);
+#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST // Not in LibreSSL yet
+ rb_define_method(cSSLContext, "sigalgs=", ossl_sslctx_set_sigalgs, 1);
+#endif
+#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST // Not in LibreSSL or AWS-LC yet
+ rb_define_method(cSSLContext, "client_sigalgs=", ossl_sslctx_set_client_sigalgs, 1);
+#endif
#ifndef OPENSSL_NO_DH
rb_define_method(cSSLContext, "tmp_dh=", ossl_sslctx_set_tmp_dh, 1);
#endif
- rb_define_method(cSSLContext, "ecdh_curves=", ossl_sslctx_set_ecdh_curves, 1);
+ rb_define_method(cSSLContext, "groups=", ossl_sslctx_set_groups, 1);
+ rb_define_alias(cSSLContext, "ecdh_curves=", "groups=");
rb_define_method(cSSLContext, "security_level", ossl_sslctx_get_security_level, 0);
rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1);
#ifdef SSL_MODE_SEND_FALLBACK_SCSV
@@ -2996,6 +3161,13 @@ Init_ossl_ssl(void)
# ifdef OSSL_USE_NEXTPROTONEG
rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0);
# endif
+#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME
+ rb_define_method(cSSLSocket, "sigalg", ossl_ssl_get_sigalg, 0);
+ rb_define_method(cSSLSocket, "peer_sigalg", ossl_ssl_get_peer_sigalg, 0);
+#endif
+#ifdef HAVE_SSL_GET0_GROUP_NAME
+ rb_define_method(cSSLSocket, "group", ossl_ssl_get_group, 0);
+#endif
rb_define_const(mSSL, "VERIFY_NONE", INT2NUM(SSL_VERIFY_NONE));
rb_define_const(mSSL, "VERIFY_PEER", INT2NUM(SSL_VERIFY_PEER));
@@ -3118,7 +3290,6 @@ Init_ossl_ssl(void)
sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
- id_tmp_dh_callback = rb_intern_const("tmp_dh_callback");
id_npn_protocols_encoded = rb_intern_const("npn_protocols_encoded");
id_each = rb_intern_const("each");
@@ -3149,9 +3320,11 @@ Init_ossl_ssl(void)
DefIVarID(servername_cb);
DefIVarID(verify_hostname);
DefIVarID(keylog_cb);
+ DefIVarID(tmp_dh_callback);
DefIVarID(io);
DefIVarID(context);
DefIVarID(hostname);
+ DefIVarID(sync_close);
#endif /* !defined(OPENSSL_NO_SOCK) */
}
diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h
index a92985c601..a87e62d450 100644
--- a/ext/openssl/ossl_ssl.h
+++ b/ext/openssl/ossl_ssl.h
@@ -11,17 +11,17 @@
#define _OSSL_SSL_H_
#define GetSSL(obj, ssl) do { \
- TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
- if (!(ssl)) { \
- ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \
- } \
+ TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
+ if (!(ssl)) { \
+ ossl_raise(rb_eRuntimeError, "SSL is not initialized"); \
+ } \
} while (0)
#define GetSSLSession(obj, sess) do { \
- TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \
- if (!(sess)) { \
- ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
- } \
+ TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \
+ if (!(sess)) { \
+ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
+ } \
} while (0)
extern const rb_data_type_t ossl_ssl_type;
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c
index 55b9d6c6d5..8a2fbf4100 100644
--- a/ext/openssl/ossl_ssl_session.c
+++ b/ext/openssl/ossl_ssl_session.c
@@ -17,14 +17,14 @@ ossl_ssl_session_free(void *ptr)
const rb_data_type_t ossl_ssl_session_type = {
"OpenSSL/SSL/Session",
{
- 0, ossl_ssl_session_free,
+ 0, ossl_ssl_session_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static VALUE ossl_ssl_session_alloc(VALUE klass)
{
- return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);
+ return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);
}
/*
@@ -80,9 +80,9 @@ ossl_ssl_session_initialize_copy(VALUE self, VALUE other)
GetSSLSession(other, sess_other);
sess_new = ASN1_dup((i2d_of_void *)i2d_SSL_SESSION, (d2i_of_void *)d2i_SSL_SESSION,
- (char *)sess_other);
+ (char *)sess_other);
if (!sess_new)
- ossl_raise(eSSLSession, "ASN1_dup");
+ ossl_raise(eSSLSession, "ASN1_dup");
RTYPEDDATA_DATA(self) = sess_new;
SSL_SESSION_free(sess);
@@ -99,9 +99,9 @@ ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
const unsigned char *b_sid = SSL_SESSION_get_id(b, &b_len);
if (SSL_SESSION_get_protocol_version(a) != SSL_SESSION_get_protocol_version(b))
- return 1;
+ return 1;
if (a_len != b_len)
- return 1;
+ return 1;
return CRYPTO_memcmp(a_sid, b_sid, a_len);
}
@@ -114,15 +114,15 @@ ossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b)
*/
static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2)
{
- SSL_SESSION *ctx1, *ctx2;
+ SSL_SESSION *ctx1, *ctx2;
- GetSSLSession(val1, ctx1);
- GetSSLSession(val2, ctx2);
+ GetSSLSession(val1, ctx1);
+ GetSSLSession(val2, ctx2);
- switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) {
- case 0: return Qtrue;
- default: return Qfalse;
- }
+ switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) {
+ case 0: return Qtrue;
+ default: return Qfalse;
+ }
}
/*
@@ -140,7 +140,7 @@ ossl_ssl_session_get_time(VALUE self)
GetSSLSession(self, ctx);
t = SSL_SESSION_get_time(ctx);
if (t == 0)
- return Qnil;
+ return Qnil;
return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t));
}
@@ -175,16 +175,16 @@ ossl_ssl_session_get_timeout(VALUE self)
*/
static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)
{
- SSL_SESSION *ctx;
- long t;
-
- GetSSLSession(self, ctx);
- if (rb_obj_is_instance_of(time_v, rb_cTime)) {
- time_v = rb_funcall(time_v, rb_intern("to_i"), 0);
- }
- t = NUM2LONG(time_v);
- SSL_SESSION_set_time(ctx, t);
- return ossl_ssl_session_get_time(self);
+ SSL_SESSION *ctx;
+ long t;
+
+ GetSSLSession(self, ctx);
+ if (rb_obj_is_instance_of(time_v, rb_cTime)) {
+ time_v = rb_funcall(time_v, rb_intern("to_i"), 0);
+ }
+ t = NUM2LONG(time_v);
+ SSL_SESSION_set_time(ctx, t);
+ return ossl_ssl_session_get_time(self);
}
/*
@@ -195,13 +195,13 @@ static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)
*/
static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)
{
- SSL_SESSION *ctx;
- long t;
+ SSL_SESSION *ctx;
+ long t;
- GetSSLSession(self, ctx);
- t = NUM2LONG(time_v);
- SSL_SESSION_set_timeout(ctx, t);
- return ossl_ssl_session_get_timeout(self);
+ GetSSLSession(self, ctx);
+ t = NUM2LONG(time_v);
+ SSL_SESSION_set_timeout(ctx, t);
+ return ossl_ssl_session_get_timeout(self);
}
/*
@@ -209,18 +209,18 @@ static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)
* session.id -> String
*
* Returns the Session ID.
-*/
+ */
static VALUE ossl_ssl_session_get_id(VALUE self)
{
- SSL_SESSION *ctx;
- const unsigned char *p = NULL;
- unsigned int i = 0;
+ SSL_SESSION *ctx;
+ const unsigned char *p = NULL;
+ unsigned int i = 0;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- p = SSL_SESSION_get_id(ctx, &i);
+ p = SSL_SESSION_get_id(ctx, &i);
- return rb_str_new((const char *) p, i);
+ return rb_str_new((const char *) p, i);
}
/*
@@ -231,22 +231,22 @@ static VALUE ossl_ssl_session_get_id(VALUE self)
*/
static VALUE ossl_ssl_session_to_der(VALUE self)
{
- SSL_SESSION *ctx;
- unsigned char *p;
- int len;
- VALUE str;
-
- GetSSLSession(self, ctx);
- len = i2d_SSL_SESSION(ctx, NULL);
- if (len <= 0) {
- ossl_raise(eSSLSession, "i2d_SSL_SESSION");
- }
-
- str = rb_str_new(0, len);
- p = (unsigned char *)RSTRING_PTR(str);
- i2d_SSL_SESSION(ctx, &p);
- ossl_str_adjust(str, p);
- return str;
+ SSL_SESSION *ctx;
+ unsigned char *p;
+ int len;
+ VALUE str;
+
+ GetSSLSession(self, ctx);
+ len = i2d_SSL_SESSION(ctx, NULL);
+ if (len <= 0) {
+ ossl_raise(eSSLSession, "i2d_SSL_SESSION");
+ }
+
+ str = rb_str_new(0, len);
+ p = (unsigned char *)RSTRING_PTR(str);
+ i2d_SSL_SESSION(ctx, &p);
+ ossl_str_adjust(str, p);
+ return str;
}
/*
@@ -257,22 +257,22 @@ static VALUE ossl_ssl_session_to_der(VALUE self)
*/
static VALUE ossl_ssl_session_to_pem(VALUE self)
{
- SSL_SESSION *ctx;
- BIO *out;
+ SSL_SESSION *ctx;
+ BIO *out;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSSLSession, "BIO_s_mem()");
- }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
- if (!PEM_write_bio_SSL_SESSION(out, ctx)) {
- BIO_free(out);
- ossl_raise(eSSLSession, "SSL_SESSION_print()");
- }
+ if (!PEM_write_bio_SSL_SESSION(out, ctx)) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
- return ossl_membio2str(out);
+ return ossl_membio2str(out);
}
@@ -284,49 +284,44 @@ static VALUE ossl_ssl_session_to_pem(VALUE self)
*/
static VALUE ossl_ssl_session_to_text(VALUE self)
{
- SSL_SESSION *ctx;
- BIO *out;
+ SSL_SESSION *ctx;
+ BIO *out;
- GetSSLSession(self, ctx);
+ GetSSLSession(self, ctx);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eSSLSession, "BIO_s_mem()");
- }
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
- if (!SSL_SESSION_print(out, ctx)) {
- BIO_free(out);
- ossl_raise(eSSLSession, "SSL_SESSION_print()");
- }
+ if (!SSL_SESSION_print(out, ctx)) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
- return ossl_membio2str(out);
+ return ossl_membio2str(out);
}
#endif /* !defined(OPENSSL_NO_SOCK) */
void Init_ossl_ssl_session(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- mSSL = rb_define_module_under(mOSSL, "SSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
#ifndef OPENSSL_NO_SOCK
- cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
- eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
-
- rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
- rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
- rb_define_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1);
-
- rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
-
- rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
- rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
- rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
- rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
- rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
- rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
- rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
- rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
+ cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
+ eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
+
+ rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
+ rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
+ rb_define_method(cSSLSession, "initialize_copy", ossl_ssl_session_initialize_copy, 1);
+
+ rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
+
+ rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
+ rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
+ rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
+ rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
+ rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
+ rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
+ rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
+ rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
#endif /* !defined(OPENSSL_NO_SOCK) */
}
diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c
index c7d2bd271b..b31a854a63 100644
--- a/ext/openssl/ossl_ts.c
+++ b/ext/openssl/ossl_ts.c
@@ -103,7 +103,7 @@ static const rb_data_type_t ossl_ts_resp_type = {
static void
ossl_ts_token_info_free(void *ptr)
{
- TS_TST_INFO_free(ptr);
+ TS_TST_INFO_free(ptr);
}
static const rb_data_type_t ossl_ts_token_info_type = {
@@ -132,44 +132,10 @@ asn1_to_der(void *template, int (*i2d)(void *template, unsigned char **pp))
return str;
}
-static ASN1_OBJECT*
-obj_to_asn1obj(VALUE obj)
-{
- ASN1_OBJECT *a1obj;
-
- StringValue(obj);
- a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0);
- if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1);
- if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID");
-
- return a1obj;
-}
-
static VALUE
obj_to_asn1obj_i(VALUE obj)
{
- return (VALUE)obj_to_asn1obj(obj);
-}
-
-static VALUE
-get_asn1obj(const ASN1_OBJECT *obj)
-{
- BIO *out;
- VALUE ret;
- int nid;
- if ((nid = OBJ_obj2nid(obj)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eTimestampError, "BIO_new(BIO_s_mem())");
- if (i2a_ASN1_OBJECT(out, obj) <= 0) {
- BIO_free(out);
- ossl_raise(eTimestampError, "i2a_ASN1_OBJECT");
- }
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return (VALUE)ossl_to_asn1obj(obj);
}
static VALUE
@@ -242,7 +208,7 @@ ossl_ts_req_get_algorithm(VALUE self)
mi = TS_REQ_get_msg_imprint(req);
algor = TS_MSG_IMPRINT_get_algo(mi);
X509_ALGOR_get0(&obj, NULL, NULL, algor);
- return get_asn1obj(obj);
+ return ossl_asn1obj_to_string(obj);
}
/*
@@ -264,7 +230,7 @@ ossl_ts_req_set_algorithm(VALUE self, VALUE algo)
X509_ALGOR *algor;
GetTSRequest(self, req);
- obj = obj_to_asn1obj(algo);
+ obj = ossl_to_asn1obj(algo);
mi = TS_REQ_get_msg_imprint(req);
algor = TS_MSG_IMPRINT_get_algo(mi);
if (!X509_ALGOR_set0(algor, obj, V_ASN1_NULL, NULL)) {
@@ -293,7 +259,7 @@ ossl_ts_req_get_msg_imprint(VALUE self)
mi = TS_REQ_get_msg_imprint(req);
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length);
+ ret = asn1str_to_str(hashed_msg);
return ret;
}
@@ -371,7 +337,7 @@ ossl_ts_req_get_policy_id(VALUE self)
GetTSRequest(self, req);
if (!TS_REQ_get_policy_id(req))
return Qnil;
- return get_asn1obj(TS_REQ_get_policy_id(req));
+ return ossl_asn1obj_to_string(TS_REQ_get_policy_id(req));
}
/*
@@ -394,7 +360,7 @@ ossl_ts_req_set_policy_id(VALUE self, VALUE oid)
int ok;
GetTSRequest(self, req);
- obj = obj_to_asn1obj(oid);
+ obj = ossl_to_asn1obj(oid);
ok = TS_REQ_set_policy_id(req, obj);
ASN1_OBJECT_free(obj);
if (!ok)
@@ -504,7 +470,7 @@ ossl_ts_req_to_der(VALUE self)
ossl_raise(eTimestampError, "Message imprint missing algorithm");
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- if (!hashed_msg->length)
+ if (!ASN1_STRING_length(hashed_msg))
ossl_raise(eTimestampError, "Message imprint missing hashed message");
return asn1_to_der((void *)req, (int (*)(void *, unsigned char **))i2d_TS_REQ);
@@ -961,7 +927,7 @@ ossl_ts_token_info_get_policy_id(VALUE self)
TS_TST_INFO *info;
GetTSTokenInfo(self, info);
- return get_asn1obj(TS_TST_INFO_get_policy_id(info));
+ return ossl_asn1obj_to_string(TS_TST_INFO_get_policy_id(info));
}
/*
@@ -989,7 +955,7 @@ ossl_ts_token_info_get_algorithm(VALUE self)
mi = TS_TST_INFO_get_msg_imprint(info);
algo = TS_MSG_IMPRINT_get_algo(mi);
X509_ALGOR_get0(&obj, NULL, NULL, algo);
- return get_asn1obj(obj);
+ return ossl_asn1obj_to_string(obj);
}
/*
@@ -1015,7 +981,7 @@ ossl_ts_token_info_get_msg_imprint(VALUE self)
GetTSTokenInfo(self, info);
mi = TS_TST_INFO_get_msg_imprint(info);
hashed_msg = TS_MSG_IMPRINT_get_msg(mi);
- ret = rb_str_new((const char *)hashed_msg->data, hashed_msg->length);
+ ret = asn1str_to_str(hashed_msg);
return ret;
}
@@ -1155,9 +1121,14 @@ ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, time_t *sec, long *usec)
}
static VALUE
-ossl_evp_get_digestbyname_i(VALUE arg)
+ossl_evp_md_fetch_i(VALUE args_)
{
- return (VALUE)ossl_evp_get_digestbyname(arg);
+ VALUE *args = (VALUE *)args_, md_holder;
+ const EVP_MD *md;
+
+ md = ossl_evp_md_fetch(args[1], &md_holder);
+ rb_ary_push(args[0], md_holder);
+ return (VALUE)md;
}
static VALUE
@@ -1193,7 +1164,8 @@ ossl_obj2bio_i(VALUE arg)
static VALUE
ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
{
- VALUE serial_number, def_policy_id, gen_time, additional_certs, allowed_digests;
+ VALUE serial_number, def_policy_id, gen_time, additional_certs,
+ allowed_digests, allowed_digests_tmp = Qnil;
VALUE str;
STACK_OF(X509) *inter_certs;
VALUE tsresp, ret = Qnil;
@@ -1254,7 +1226,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
if (rb_obj_is_kind_of(additional_certs, rb_cArray)) {
inter_certs = ossl_protect_x509_ary2sk(additional_certs, &status);
if (status)
- goto end;
+ goto end;
/* this dups the sk_X509 and ups each cert's ref count */
TS_RESP_CTX_set_certs(ctx, inter_certs);
@@ -1270,16 +1242,18 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
allowed_digests = ossl_tsfac_get_allowed_digests(self);
if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) {
- int i;
- VALUE rbmd;
- const EVP_MD *md;
-
- for (i = 0; i < RARRAY_LEN(allowed_digests); i++) {
- rbmd = rb_ary_entry(allowed_digests, i);
- md = (const EVP_MD *)rb_protect(ossl_evp_get_digestbyname_i, rbmd, &status);
+ allowed_digests_tmp = rb_ary_new_capa(RARRAY_LEN(allowed_digests));
+ for (long i = 0; i < RARRAY_LEN(allowed_digests); i++) {
+ VALUE args[] = {
+ allowed_digests_tmp,
+ rb_ary_entry(allowed_digests, i),
+ };
+ const EVP_MD *md = (const EVP_MD *)rb_protect(ossl_evp_md_fetch_i,
+ (VALUE)args, &status);
if (status)
goto end;
- TS_RESP_CTX_add_md(ctx, md);
+ if (!TS_RESP_CTX_add_md(ctx, md))
+ goto end;
}
}
@@ -1293,6 +1267,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
response = TS_RESP_create_response(ctx, req_bio);
BIO_free(req_bio);
+ RB_GC_GUARD(allowed_digests_tmp);
if (!response) {
err_msg = "Error during response generation";
@@ -1306,7 +1281,7 @@ ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
SetTSResponse(tsresp, response);
ret = tsresp;
-end:
+ end:
ASN1_INTEGER_free(asn1_serial);
ASN1_OBJECT_free(def_policy_id_obj);
TS_RESP_CTX_free(ctx);
@@ -1323,10 +1298,6 @@ end:
void
Init_ossl_ts(void)
{
- #if 0
- mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
- #endif
-
/*
* Possible return value for +Response#failure_info+. Indicates that the
* timestamp server rejects the message imprint algorithm used in the
@@ -1536,65 +1507,39 @@ Init_ossl_ts(void)
* fac.default_policy_id = '1.2.3.4.5'
* fac.additional_certificates = [ inter1, inter2 ]
* timestamp = fac.create_timestamp(p12.key, p12.certificate, req)
- *
- * ==Attributes
- *
- * ===default_policy_id
+ */
+ cTimestampFactory = rb_define_class_under(mTimestamp, "Factory", rb_cObject);
+ /*
+ * The list of digest algorithms that the factory is allowed
+ * create timestamps for. Known vulnerable or weak algorithms should not be
+ * allowed where possible. Must be an Array of String or OpenSSL::Digest
+ * subclass instances.
+ */
+ rb_attr(cTimestampFactory, rb_intern_const("allowed_digests"), 1, 1, 0);
+ /*
+ * A String representing the default policy object identifier, or +nil+.
*
* Request#policy_id will always be preferred over this if present in the
- * Request, only if Request#policy_id is nil default_policy will be used.
+ * Request, only if Request#policy_id is +nil+ default_policy will be used.
* If none of both is present, a TimestampError will be raised when trying
* to create a Response.
- *
- * call-seq:
- * factory.default_policy_id = "string" -> string
- * factory.default_policy_id -> string or nil
- *
- * ===serial_number
- *
- * Sets or retrieves the serial number to be used for timestamp creation.
- * Must be present for timestamp creation.
- *
- * call-seq:
- * factory.serial_number = number -> number
- * factory.serial_number -> number or nil
- *
- * ===gen_time
- *
- * Sets or retrieves the Time value to be used in the Response. Must be
- * present for timestamp creation.
- *
- * call-seq:
- * factory.gen_time = Time -> Time
- * factory.gen_time -> Time or nil
- *
- * ===additional_certs
- *
- * Sets or retrieves additional certificates apart from the timestamp
- * certificate (e.g. intermediate certificates) to be added to the Response.
- * Must be an Array of OpenSSL::X509::Certificate.
- *
- * call-seq:
- * factory.additional_certs = [cert1, cert2] -> [ cert1, cert2 ]
- * factory.additional_certs -> array or nil
- *
- * ===allowed_digests
- *
- * Sets or retrieves the digest algorithms that the factory is allowed
- * create timestamps for. Known vulnerable or weak algorithms should not be
- * allowed where possible.
- * Must be an Array of String or OpenSSL::Digest subclass instances.
- *
- * call-seq:
- * factory.allowed_digests = ["sha1", OpenSSL::Digest.new('SHA256').new] -> [ "sha1", OpenSSL::Digest) ]
- * factory.allowed_digests -> array or nil
- *
*/
- cTimestampFactory = rb_define_class_under(mTimestamp, "Factory", rb_cObject);
- rb_attr(cTimestampFactory, rb_intern_const("allowed_digests"), 1, 1, 0);
rb_attr(cTimestampFactory, rb_intern_const("default_policy_id"), 1, 1, 0);
+ /*
+ * The serial number to be used for timestamp creation. Must be present for
+ * timestamp creation. Must be an instance of OpenSSL::BN or Integer.
+ */
rb_attr(cTimestampFactory, rb_intern_const("serial_number"), 1, 1, 0);
+ /*
+ * The Time value to be used in the Response. Must be present for timestamp
+ * creation.
+ */
rb_attr(cTimestampFactory, rb_intern_const("gen_time"), 1, 1, 0);
+ /*
+ * Additional certificates apart from the timestamp certificate (e.g.
+ * intermediate certificates) to be added to the Response.
+ * Must be an Array of OpenSSL::X509::Certificate, or +nil+.
+ */
rb_attr(cTimestampFactory, rb_intern_const("additional_certs"), 1, 1, 0);
rb_define_method(cTimestampFactory, "create_timestamp", ossl_tsfac_create_ts, 3);
}
diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c
index 2d552d7847..bc3914fda2 100644
--- a/ext/openssl/ossl_x509.c
+++ b/ext/openssl/ossl_x509.c
@@ -13,7 +13,8 @@ VALUE mX509;
#define DefX509Const(x) rb_define_const(mX509, #x, INT2NUM(X509_##x))
#define DefX509Default(x,i) \
- rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i()))
+ rb_define_const(mX509, "DEFAULT_" #x, \
+ rb_obj_freeze(rb_str_new_cstr(X509_get_default_##i())))
ASN1_TIME *
ossl_x509_time_adjust(ASN1_TIME *s, VALUE time)
@@ -29,10 +30,6 @@ ossl_x509_time_adjust(ASN1_TIME *s, VALUE time)
void
Init_ossl_x509(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
-#endif
-
mX509 = rb_define_module_under(mOSSL, "X509");
Init_ossl_x509attr();
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c
index 3f6b89bdde..4769e56e1e 100644
--- a/ext/openssl/ossl_x509attr.c
+++ b/ext/openssl/ossl_x509attr.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509attr_type, 0)
#define SetX509Attr(obj, attr) do { \
if (!(attr)) { \
- ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (attr); \
} while (0)
#define GetX509Attr(obj, attr) do { \
TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \
if (!(attr)) { \
- ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509attr_free(void *ptr)
static const rb_data_type_t ossl_x509attr_type = {
"OpenSSL/X509/ATTRIBUTE",
{
- 0, ossl_x509attr_free,
+ 0, ossl_x509attr_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -54,14 +54,9 @@ ossl_x509attr_new(X509_ATTRIBUTE *attr)
VALUE obj;
obj = NewX509Attr(cX509Attr);
- if (!attr) {
- new = X509_ATTRIBUTE_new();
- } else {
- new = X509_ATTRIBUTE_dup(attr);
- }
- if (!new) {
- ossl_raise(eX509AttrError, NULL);
- }
+ new = X509_ATTRIBUTE_dup(attr);
+ if (!new)
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
SetX509Attr(obj, new);
return obj;
@@ -88,7 +83,7 @@ ossl_x509attr_alloc(VALUE klass)
obj = NewX509Attr(klass);
if (!(attr = X509_ATTRIBUTE_new()))
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
SetX509Attr(obj, attr);
return obj;
@@ -107,15 +102,15 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
GetX509Attr(self, attr);
if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){
- oid = ossl_to_der_if_possible(oid);
- StringValue(oid);
- p = (unsigned char *)RSTRING_PTR(oid);
- x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
- DATA_PTR(self) = attr;
- if(!x){
- ossl_raise(eX509AttrError, NULL);
- }
- return self;
+ oid = ossl_to_der_if_possible(oid);
+ StringValue(oid);
+ p = (unsigned char *)RSTRING_PTR(oid);
+ x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
+ DATA_PTR(self) = attr;
+ if(!x){
+ ossl_raise(eX509AttrError, NULL);
+ }
+ return self;
}
rb_funcall(self, rb_intern("oid="), 1, oid);
rb_funcall(self, rb_intern("value="), 1, value);
@@ -135,7 +130,7 @@ ossl_x509attr_initialize_copy(VALUE self, VALUE other)
attr_new = X509_ATTRIBUTE_dup(attr_other);
if (!attr_new)
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
SetX509Attr(self, attr_new);
X509_ATTRIBUTE_free(attr);
@@ -159,8 +154,8 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
obj = OBJ_txt2obj(s, 0);
if(!obj) ossl_raise(eX509AttrError, NULL);
if (!X509_ATTRIBUTE_set1_object(attr, obj)) {
- ASN1_OBJECT_free(obj);
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object");
+ ASN1_OBJECT_free(obj);
+ ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object");
}
ASN1_OBJECT_free(obj);
@@ -169,29 +164,18 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
/*
* call-seq:
- * attr.oid => string
+ * attr.oid -> string
+ *
+ * Returns the OID of the attribute. Returns the short name or the dotted
+ * decimal notation.
*/
static VALUE
ossl_x509attr_get_oid(VALUE self)
{
X509_ATTRIBUTE *attr;
- ASN1_OBJECT *oid;
- BIO *out;
- VALUE ret;
- int nid;
GetX509Attr(self, attr);
- oid = X509_ATTRIBUTE_get0_object(attr);
- if ((nid = OBJ_obj2nid(oid)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509AttrError, NULL);
- i2a_ASN1_OBJECT(out, oid);
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return ossl_asn1obj_to_string(X509_ATTRIBUTE_get0_object(attr));
}
/*
@@ -252,21 +236,21 @@ ossl_x509attr_get_value(VALUE self)
GetX509Attr(self, attr);
/* there is no X509_ATTRIBUTE_get0_set() :( */
if (!(sk = sk_ASN1_TYPE_new_null()))
- ossl_raise(eX509AttrError, "sk_new");
+ ossl_raise(eX509AttrError, "sk_new");
count = X509_ATTRIBUTE_count(attr);
for (i = 0; i < count; i++)
- sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i));
+ sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i));
if ((len = i2d_ASN1_SET_ANY(sk, NULL)) <= 0) {
- sk_ASN1_TYPE_free(sk);
- ossl_raise(eX509AttrError, NULL);
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
}
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_ASN1_SET_ANY(sk, &p) <= 0) {
- sk_ASN1_TYPE_free(sk);
- ossl_raise(eX509AttrError, NULL);
+ sk_ASN1_TYPE_free(sk);
+ ossl_raise(eX509AttrError, NULL);
}
ossl_str_adjust(str, p);
sk_ASN1_TYPE_free(sk);
@@ -288,11 +272,11 @@ ossl_x509attr_to_der(VALUE self)
GetX509Attr(self, attr);
if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0)
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)
- ossl_raise(eX509AttrError, NULL);
+ ossl_raise(eX509AttrError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -304,12 +288,6 @@ ossl_x509attr_to_der(VALUE self)
void
Init_ossl_x509attr(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError);
cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject);
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index 4734602bef..95679c7d24 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509_type, 0)
#define SetX509(obj, x509) do { \
if (!(x509)) { \
- ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (x509); \
} while (0)
#define GetX509(obj, x509) do { \
TypedData_Get_Struct((obj), X509, &ossl_x509_type, (x509)); \
if (!(x509)) { \
- ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509_free(void *ptr)
static const rb_data_type_t ossl_x509_type = {
"OpenSSL/X509",
{
- 0, ossl_x509_free,
+ 0, ossl_x509_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -54,14 +54,9 @@ ossl_x509_new(X509 *x509)
VALUE obj;
obj = NewX509(cX509Cert);
- if (!x509) {
- new = X509_new();
- } else {
- new = X509_dup(x509);
- }
- if (!new) {
- ossl_raise(eX509CertError, NULL);
- }
+ new = X509_dup(x509);
+ if (!new)
+ ossl_raise(eX509CertError, "X509_dup");
SetX509(obj, new);
return obj;
@@ -120,8 +115,8 @@ ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- /* create just empty X509Cert */
- return self;
+ /* create just empty X509Cert */
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -175,11 +170,11 @@ ossl_x509_to_der(VALUE self)
GetX509(self, x509);
if ((len = i2d_X509(x509, NULL)) <= 0)
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509(x509, &p) <= 0)
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -201,8 +196,8 @@ ossl_x509_to_pem(VALUE self)
if (!out) ossl_raise(eX509CertError, NULL);
if (!PEM_write_bio_X509(out, x509)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
@@ -226,8 +221,8 @@ ossl_x509_to_text(VALUE self)
if (!out) ossl_raise(eX509CertError, NULL);
if (!X509_print(out, x509)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CertError, NULL);
}
str = ossl_membio2str(out);
@@ -247,7 +242,7 @@ ossl_x509_to_req(VALUE self)
GetX509(self, x509);
if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
obj = ossl_x509req_new(req);
X509_REQ_free(req);
@@ -281,11 +276,11 @@ ossl_x509_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509CertError, "version must be >= 0!");
+ ossl_raise(eX509CertError, "version must be >= 0!");
}
GetX509(self, x509);
if (!X509_set_version(x509, ver)) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return version;
@@ -323,27 +318,23 @@ ossl_x509_set_serial(VALUE self, VALUE num)
/*
* call-seq:
* cert.signature_algorithm => string
+ *
+ * Returns the signature algorithm used to sign this certificate. This returns
+ * the algorithm name found in the TBSCertificate structure, not the outer
+ * \Certificate structure.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
*/
static VALUE
ossl_x509_get_signature_algorithm(VALUE self)
{
X509 *x509;
- BIO *out;
const ASN1_OBJECT *obj;
- VALUE str;
GetX509(self, x509);
- out = BIO_new(BIO_s_mem());
- if (!out) ossl_raise(eX509CertError, NULL);
-
X509_ALGOR_get0(&obj, NULL, NULL, X509_get0_tbs_sigalg(x509));
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509CertError, NULL);
- }
- str = ossl_membio2str(out);
-
- return str;
+ return ossl_asn1obj_to_string_long_name(obj);
}
/*
@@ -358,7 +349,7 @@ ossl_x509_get_subject(VALUE self)
GetX509(self, x509);
if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
@@ -375,7 +366,7 @@ ossl_x509_set_subject(VALUE self, VALUE subject)
GetX509(self, x509);
if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return subject;
@@ -393,7 +384,7 @@ ossl_x509_get_issuer(VALUE self)
GetX509(self, x509);
if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return ossl_x509name_new(name);
@@ -410,7 +401,7 @@ ossl_x509_set_issuer(VALUE self, VALUE issuer)
GetX509(self, x509);
if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return issuer;
@@ -428,7 +419,7 @@ ossl_x509_get_not_before(VALUE self)
GetX509(self, x509);
if (!(asn1time = X509_get0_notBefore(x509))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
@@ -447,8 +438,8 @@ ossl_x509_set_not_before(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notBefore(x509, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CertError, "X509_set_notBefore");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CertError, "X509_set_notBefore");
}
ASN1_TIME_free(asn1time);
@@ -467,7 +458,7 @@ ossl_x509_get_not_after(VALUE self)
GetX509(self, x509);
if (!(asn1time = X509_get0_notAfter(x509))) {
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return asn1time_to_time(asn1time);
@@ -486,8 +477,8 @@ ossl_x509_set_not_after(VALUE self, VALUE time)
GetX509(self, x509);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_set1_notAfter(x509, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CertError, "X509_set_notAfter");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CertError, "X509_set_notAfter");
}
ASN1_TIME_free(asn1time);
@@ -506,10 +497,10 @@ ossl_x509_get_public_key(VALUE self)
GetX509(self, x509);
if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
- return ossl_pkey_new(pkey); /* NO DUP - OK */
+ return ossl_pkey_wrap(pkey);
}
/*
@@ -526,7 +517,7 @@ ossl_x509_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!X509_set_pubkey(x509, pkey))
- ossl_raise(eX509CertError, "X509_set_pubkey");
+ ossl_raise(eX509CertError, "X509_set_pubkey");
return key;
}
@@ -540,17 +531,14 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
X509 *x509;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- if (NIL_P(digest)) {
- md = NULL; /* needed for some key types, e.g. Ed25519 */
- } else {
- md = ossl_evp_get_digestbyname(digest);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
GetX509(self, x509);
- if (!X509_sign(x509, pkey, md)) {
- ossl_raise(eX509CertError, NULL);
- }
+ if (!X509_sign(x509, pkey, md))
+ ossl_raise(eX509CertError, "X509_sign");
return self;
}
@@ -573,12 +561,12 @@ ossl_x509_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_verify(x509, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
}
@@ -599,8 +587,8 @@ ossl_x509_check_private_key(VALUE self, VALUE key)
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
GetX509(self, x509);
if (!X509_check_private_key(x509, pkey)) {
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
}
return Qtrue;
@@ -622,8 +610,8 @@ ossl_x509_get_extensions(VALUE self)
count = X509_get_ext_count(x509);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_get_ext(x509, i); /* NO DUP - don't free! */
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ ext = X509_get_ext(x509, i); /* NO DUP - don't free! */
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -643,16 +631,16 @@ ossl_x509_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary's members should be X509Extension */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509(self, x509);
for (i = X509_get_ext_count(x509); i > 0; i--)
X509_EXTENSION_free(X509_delete_ext(x509, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
- if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
- ossl_raise(eX509CertError, "X509_add_ext");
- }
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i));
+ if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */
+ ossl_raise(eX509CertError, "X509_add_ext");
+ }
}
return ary;
@@ -671,32 +659,24 @@ ossl_x509_add_extension(VALUE self, VALUE extension)
GetX509(self, x509);
ext = GetX509ExtPtr(extension);
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
- ossl_raise(eX509CertError, NULL);
+ ossl_raise(eX509CertError, NULL);
}
return extension;
}
-static VALUE
-ossl_x509_inspect(VALUE self)
-{
- return rb_sprintf("#<%"PRIsVALUE": subject=%+"PRIsVALUE", "
- "issuer=%+"PRIsVALUE", serial=%+"PRIsVALUE", "
- "not_before=%+"PRIsVALUE", not_after=%+"PRIsVALUE">",
- rb_obj_class(self),
- ossl_x509_get_subject(self),
- ossl_x509_get_issuer(self),
- ossl_x509_get_serial(self),
- ossl_x509_get_not_before(self),
- ossl_x509_get_not_after(self));
-}
-
/*
* call-seq:
* cert1 == cert2 -> true | false
*
* Compares the two certificates. Note that this takes into account all fields,
* not just the issuer name and the serial number.
+ *
+ * This method uses X509_cmp() from OpenSSL, which compares certificates based
+ * on their cached DER encodings. The comparison can be unreliable if a
+ * certificate is incomplete.
+ *
+ * See also the man page X509_cmp(3).
*/
static VALUE
ossl_x509_eq(VALUE self, VALUE other)
@@ -705,7 +685,7 @@ ossl_x509_eq(VALUE self, VALUE other)
GetX509(self, a);
if (!rb_obj_is_kind_of(other, cX509Cert))
- return Qfalse;
+ return Qfalse;
GetX509(other, b);
return !X509_cmp(a, b) ? Qtrue : Qfalse;
@@ -800,7 +780,7 @@ load_chained_certificates_PEM(BIO *in) {
certificates = load_chained_certificates_append(Qnil, certificate);
while ((certificate = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
- load_chained_certificates_append(certificates, certificate);
+ load_chained_certificates_append(certificates, certificate);
}
/* We tried to read one more certificate but could not read start line: */
@@ -898,12 +878,6 @@ ossl_x509_load(VALUE klass, VALUE buffer)
void
Init_ossl_x509cert(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError);
/* Document-class: OpenSSL::X509::Certificate
@@ -1031,7 +1005,6 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "extensions", ossl_x509_get_extensions, 0);
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
- rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
rb_define_method(cX509Cert, "tbs_bytes", ossl_x509_tbs_bytes, 0);
}
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 135dfe3d75..a221429c34 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509crl_type, 0)
#define SetX509CRL(obj, crl) do { \
if (!(crl)) { \
- ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (crl); \
} while (0)
#define GetX509CRL(obj, crl) do { \
TypedData_Get_Struct((obj), X509_CRL, &ossl_x509crl_type, (crl)); \
if (!(crl)) { \
- ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509crl_free(void *ptr)
static const rb_data_type_t ossl_x509crl_type = {
"OpenSSL/X509/CRL",
{
- 0, ossl_x509crl_free,
+ 0, ossl_x509crl_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -64,8 +64,9 @@ ossl_x509crl_new(X509_CRL *crl)
VALUE obj;
obj = NewX509CRL(cX509CRL);
- tmp = crl ? X509_CRL_dup(crl) : X509_CRL_new();
- if(!tmp) ossl_raise(eX509CRLError, NULL);
+ tmp = X509_CRL_dup(crl);
+ if (!tmp)
+ ossl_raise(eX509CRLError, "X509_CRL_dup");
SetX509CRL(obj, tmp);
return obj;
@@ -82,7 +83,7 @@ ossl_x509crl_alloc(VALUE klass)
obj = NewX509CRL(klass);
if (!(crl = X509_CRL_new())) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
SetX509CRL(obj, crl);
@@ -98,7 +99,7 @@ ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return self;
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -128,7 +129,7 @@ ossl_x509crl_copy(VALUE self, VALUE other)
GetX509CRL(self, a);
GetX509CRL(other, b);
if (!(crl = X509_CRL_dup(b))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
X509_CRL_free(a);
DATA_PTR(self) = crl;
@@ -155,36 +156,36 @@ ossl_x509crl_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509CRLError, "version must be >= 0!");
+ ossl_raise(eX509CRLError, "version must be >= 0!");
}
GetX509CRL(self, crl);
if (!X509_CRL_set_version(crl, ver)) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return version;
}
+/*
+ * call-seq:
+ * crl.signature_algorithm -> string
+ *
+ * Returns the signature algorithm used to sign this CRL.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
+ */
static VALUE
ossl_x509crl_get_signature_algorithm(VALUE self)
{
X509_CRL *crl;
const X509_ALGOR *alg;
const ASN1_OBJECT *obj;
- BIO *out;
GetX509CRL(self, crl);
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
- }
X509_CRL_get0_signature(crl, NULL, &alg);
X509_ALGOR_get0(&obj, NULL, NULL, alg);
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
- }
-
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(obj);
}
static VALUE
@@ -205,7 +206,7 @@ ossl_x509crl_set_issuer(VALUE self, VALUE issuer)
GetX509CRL(self, crl);
if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return issuer;
}
@@ -219,7 +220,7 @@ ossl_x509crl_get_last_update(VALUE self)
GetX509CRL(self, crl);
time = X509_CRL_get0_lastUpdate(crl);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -233,8 +234,8 @@ ossl_x509crl_set_last_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_CRL_set1_lastUpdate(crl, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CRLError, "X509_CRL_set_lastUpdate");
}
ASN1_TIME_free(asn1time);
@@ -250,7 +251,7 @@ ossl_x509crl_get_next_update(VALUE self)
GetX509CRL(self, crl);
time = X509_CRL_get0_nextUpdate(crl);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -264,8 +265,8 @@ ossl_x509crl_set_next_update(VALUE self, VALUE time)
GetX509CRL(self, crl);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_CRL_set1_nextUpdate(crl, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509CRLError, "X509_CRL_set_nextUpdate");
}
ASN1_TIME_free(asn1time);
@@ -288,8 +289,8 @@ ossl_x509crl_get_revoked(VALUE self)
num = sk_X509_REVOKED_num(sk);
ary = rb_ary_new_capa(num);
for(i=0; i<num; i++) {
- X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i);
- rb_ary_push(ary, ossl_x509revoked_new(rev));
+ X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i);
+ rb_ary_push(ary, ossl_x509revoked_new(rev));
}
return ary;
@@ -306,19 +307,19 @@ ossl_x509crl_set_revoked(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Revoked */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev);
}
GetX509CRL(self, crl);
if ((sk = X509_CRL_get_REVOKED(crl))) {
- while ((rev = sk_X509_REVOKED_pop(sk)))
- X509_REVOKED_free(rev);
+ while ((rev = sk_X509_REVOKED_pop(sk)))
+ X509_REVOKED_free(rev);
}
for (i=0; i<RARRAY_LEN(ary); i++) {
- rev = DupX509RevokedPtr(RARRAY_AREF(ary, i));
- if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
- X509_REVOKED_free(rev);
- ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
- }
+ rev = DupX509RevokedPtr(RARRAY_AREF(ary, i));
+ if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
+ X509_REVOKED_free(rev);
+ ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
+ }
}
X509_CRL_sort(crl);
@@ -334,8 +335,8 @@ ossl_x509crl_add_revoked(VALUE self, VALUE revoked)
GetX509CRL(self, crl);
rev = DupX509RevokedPtr(revoked);
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
- X509_REVOKED_free(rev);
- ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
+ X509_REVOKED_free(rev);
+ ossl_raise(eX509CRLError, "X509_CRL_add0_revoked");
}
X509_CRL_sort(crl);
@@ -348,17 +349,14 @@ ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)
X509_CRL *crl;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
GetX509CRL(self, crl);
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- if (NIL_P(digest)) {
- md = NULL; /* needed for some key types, e.g. Ed25519 */
- } else {
- md = ossl_evp_get_digestbyname(digest);
- }
- if (!X509_CRL_sign(crl, pkey, md)) {
- ossl_raise(eX509CRLError, NULL);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
+ if (!X509_CRL_sign(crl, pkey, md))
+ ossl_raise(eX509CRLError, "X509_CRL_sign");
return self;
}
@@ -374,12 +372,12 @@ ossl_x509crl_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_CRL_verify(crl, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
}
@@ -391,11 +389,11 @@ ossl_x509crl_to_der(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!i2d_X509_CRL_bio(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -409,11 +407,11 @@ ossl_x509crl_to_pem(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!PEM_write_bio_X509_CRL(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -427,11 +425,11 @@ ossl_x509crl_to_text(VALUE self)
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
if (!X509_CRL_print(out, crl)) {
- BIO_free(out);
- ossl_raise(eX509CRLError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509CRLError, NULL);
}
return ossl_membio2str(out);
@@ -452,8 +450,8 @@ ossl_x509crl_get_extensions(VALUE self)
count = X509_CRL_get_ext_count(crl);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -472,16 +470,16 @@ ossl_x509crl_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Extensions */
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509CRL(self, crl);
for (i = X509_CRL_get_ext_count(crl); i > 0; i--)
X509_EXTENSION_free(X509_CRL_delete_ext(crl, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */
- if (!X509_CRL_add_ext(crl, ext, -1)) {
- ossl_raise(eX509CRLError, "X509_CRL_add_ext");
- }
+ ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */
+ if (!X509_CRL_add_ext(crl, ext, -1)) {
+ ossl_raise(eX509CRLError, "X509_CRL_add_ext");
+ }
}
return ary;
@@ -496,7 +494,7 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension)
GetX509CRL(self, crl);
ext = GetX509ExtPtr(extension);
if (!X509_CRL_add_ext(crl, ext, -1)) {
- ossl_raise(eX509CRLError, NULL);
+ ossl_raise(eX509CRLError, NULL);
}
return extension;
@@ -508,12 +506,6 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension)
void
Init_ossl_x509crl(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError);
cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject);
diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c
index 9b0d9aa651..ef66ecc3fe 100644
--- a/ext/openssl/ossl_x509ext.c
+++ b/ext/openssl/ossl_x509ext.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509ext_type, 0)
#define SetX509Ext(obj, ext) do { \
if (!(ext)) { \
- ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (ext); \
} while (0)
#define GetX509Ext(obj, ext) do { \
TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \
if (!(ext)) { \
- ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
} \
} while (0)
#define MakeX509ExtFactory(klass, obj, ctx) do { \
@@ -33,7 +33,7 @@
#define GetX509ExtFactory(obj, ctx) do { \
TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
} \
} while (0)
@@ -53,7 +53,7 @@ ossl_x509ext_free(void *ptr)
static const rb_data_type_t ossl_x509ext_type = {
"OpenSSL/X509/EXTENSION",
{
- 0, ossl_x509ext_free,
+ 0, ossl_x509ext_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -68,14 +68,9 @@ ossl_x509ext_new(X509_EXTENSION *ext)
VALUE obj;
obj = NewX509Ext(cX509Ext);
- if (!ext) {
- new = X509_EXTENSION_new();
- } else {
- new = X509_EXTENSION_dup(ext);
- }
- if (!new) {
- ossl_raise(eX509ExtError, NULL);
- }
+ new = X509_EXTENSION_dup(ext);
+ if (!new)
+ ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
SetX509Ext(obj, new);
return obj;
@@ -106,7 +101,7 @@ ossl_x509extfactory_free(void *ctx)
static const rb_data_type_t ossl_x509extfactory_type = {
"OpenSSL/X509/EXTENSION/Factory",
{
- 0, ossl_x509extfactory_free,
+ 0, ossl_x509extfactory_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -180,15 +175,15 @@ ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
/*GetX509ExtFactory(self, ctx);*/
rb_scan_args(argc, argv, "04",
- &issuer_cert, &subject_cert, &subject_req, &crl);
+ &issuer_cert, &subject_cert, &subject_req, &crl);
if (!NIL_P(issuer_cert))
- ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
+ ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
if (!NIL_P(subject_cert))
- ossl_x509extfactory_set_subject_cert(self, subject_cert);
+ ossl_x509extfactory_set_subject_cert(self, subject_cert);
if (!NIL_P(subject_req))
- ossl_x509extfactory_set_subject_req(self, subject_req);
+ ossl_x509extfactory_set_subject_req(self, subject_req);
if (!NIL_P(crl))
- ossl_x509extfactory_set_crl(self, crl);
+ ossl_x509extfactory_set_crl(self, crl);
return self;
}
@@ -218,7 +213,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
oid_cstr = StringValueCStr(oid);
nid = OBJ_ln2nid(oid_cstr);
if (nid != NID_undef)
- oid_cstr = OBJ_nid2sn(nid);
+ oid_cstr = OBJ_nid2sn(nid);
valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
rb_str_append(valstr, value);
@@ -233,7 +228,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr));
X509V3_set_ctx_nodb(ctx);
if (!ext){
- ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
+ ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
}
SetX509Ext(obj, ext);
@@ -251,7 +246,7 @@ ossl_x509ext_alloc(VALUE klass)
obj = NewX509Ext(klass);
if(!(ext = X509_EXTENSION_new())){
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
}
SetX509Ext(obj, ext);
@@ -279,14 +274,14 @@ ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)
GetX509Ext(self, ext);
if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){
- oid = ossl_to_der_if_possible(oid);
- StringValue(oid);
- p = (unsigned char *)RSTRING_PTR(oid);
- x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
- DATA_PTR(self) = ext;
- if(!x)
- ossl_raise(eX509ExtError, NULL);
- return self;
+ oid = ossl_to_der_if_possible(oid);
+ StringValue(oid);
+ p = (unsigned char *)RSTRING_PTR(oid);
+ x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
+ DATA_PTR(self) = ext;
+ if(!x)
+ ossl_raise(eX509ExtError, NULL);
+ return self;
}
rb_funcall(self, rb_intern("oid="), 1, oid);
rb_funcall(self, rb_intern("value="), 1, value);
@@ -307,7 +302,7 @@ ossl_x509ext_initialize_copy(VALUE self, VALUE other)
ext_new = X509_EXTENSION_dup(ext_other);
if (!ext_new)
- ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
+ ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
SetX509Ext(self, ext_new);
X509_EXTENSION_free(ext);
@@ -324,10 +319,10 @@ ossl_x509ext_set_oid(VALUE self, VALUE oid)
GetX509Ext(self, ext);
obj = OBJ_txt2obj(StringValueCStr(oid), 0);
if (!obj)
- ossl_raise(eX509ExtError, "OBJ_txt2obj");
+ ossl_raise(eX509ExtError, "OBJ_txt2obj");
if (!X509_EXTENSION_set_object(ext, obj)) {
- ASN1_OBJECT_free(obj);
- ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
+ ASN1_OBJECT_free(obj);
+ ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
}
ASN1_OBJECT_free(obj);
@@ -346,8 +341,8 @@ ossl_x509ext_set_value(VALUE self, VALUE data)
asn1s = X509_EXTENSION_get_data(ext);
if (!ASN1_OCTET_STRING_set(asn1s, (unsigned char *)RSTRING_PTR(data),
- RSTRING_LENINT(data))) {
- ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
+ RSTRING_LENINT(data))) {
+ ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
}
return data;
@@ -364,27 +359,20 @@ ossl_x509ext_set_critical(VALUE self, VALUE flag)
return flag;
}
+/*
+ * call-seq:
+ * ext.oid -> string
+ *
+ * Returns the OID of the extension. Returns the short name or the dotted
+ * decimal notation.
+ */
static VALUE
ossl_x509ext_get_oid(VALUE obj)
{
X509_EXTENSION *ext;
- ASN1_OBJECT *extobj;
- BIO *out;
- VALUE ret;
- int nid;
GetX509Ext(obj, ext);
- extobj = X509_EXTENSION_get_object(ext);
- if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
- ret = rb_str_new2(OBJ_nid2sn(nid));
- else{
- if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509ExtError, NULL);
- i2a_ASN1_OBJECT(out, extobj);
- ret = ossl_membio2str(out);
- }
-
- return ret;
+ return ossl_asn1obj_to_string(X509_EXTENSION_get_object(ext));
}
static VALUE
@@ -396,9 +384,9 @@ ossl_x509ext_get_value(VALUE obj)
GetX509Ext(obj, ext);
if (!(out = BIO_new(BIO_s_mem())))
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
if (!X509V3_EXT_print(out, ext, 0, 0))
- ASN1_STRING_print(out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
+ ASN1_STRING_print(out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
ret = ossl_membio2str(out);
return ret;
@@ -412,9 +400,9 @@ ossl_x509ext_get_value_der(VALUE obj)
GetX509Ext(obj, ext);
if ((value = X509_EXTENSION_get_data(ext)) == NULL)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
- return rb_str_new((const char *)value->data, value->length);
+ return asn1str_to_str(value);
}
static VALUE
@@ -436,11 +424,11 @@ ossl_x509ext_to_der(VALUE obj)
GetX509Ext(obj, ext);
if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_EXTENSION(ext, &p) < 0)
- ossl_raise(eX509ExtError, NULL);
+ ossl_raise(eX509ExtError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -453,12 +441,6 @@ void
Init_ossl_x509ext(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index b3791aefa3..5b3c3f7261 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -13,21 +13,21 @@
TypedData_Wrap_Struct((klass), &ossl_x509name_type, 0)
#define SetX509Name(obj, name) do { \
if (!(name)) { \
- ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
} \
RTYPEDDATA_DATA(obj) = (name); \
} while (0)
#define GetX509Name(obj, name) do { \
TypedData_Get_Struct((obj), X509_NAME, &ossl_x509name_type, (name)); \
if (!(name)) { \
- ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
} \
} while (0)
#define OBJECT_TYPE_TEMPLATE \
- rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE"))
+ rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE"))
#define DEFAULT_OBJECT_TYPE \
- rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE"))
+ rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE"))
/*
* Classes
@@ -44,7 +44,7 @@ ossl_x509name_free(void *ptr)
static const rb_data_type_t ossl_x509name_type = {
"OpenSSL/X509/NAME",
{
- 0, ossl_x509name_free,
+ 0, ossl_x509name_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -59,14 +59,9 @@ ossl_x509name_new(X509_NAME *name)
VALUE obj;
obj = NewX509Name(cX509Name);
- if (!name) {
- new = X509_NAME_new();
- } else {
- new = X509_NAME_dup(name);
- }
- if (!new) {
- ossl_raise(eX509NameError, NULL);
- }
+ new = X509_NAME_dup(name);
+ if (!new)
+ ossl_raise(eX509NameError, "X509_NAME_dup");
SetX509Name(obj, new);
return obj;
@@ -93,7 +88,7 @@ ossl_x509name_alloc(VALUE klass)
obj = NewX509Name(klass);
if (!(name = X509_NAME_new())) {
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
}
SetX509Name(obj, name);
@@ -150,28 +145,28 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
GetX509Name(self, name);
if (rb_scan_args(argc, argv, "02", &arg, &template) == 0) {
- return self;
+ return self;
}
else {
- VALUE tmp = rb_check_array_type(arg);
- if (!NIL_P(tmp)) {
- VALUE args;
- if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
- args = rb_ary_new3(2, self, template);
- rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
- }
- else{
- const unsigned char *p;
- VALUE str = ossl_to_der_if_possible(arg);
- X509_NAME *x;
- StringValue(str);
- p = (unsigned char *)RSTRING_PTR(str);
- x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
- DATA_PTR(self) = name;
- if(!x){
- ossl_raise(eX509NameError, NULL);
- }
- }
+ VALUE tmp = rb_check_array_type(arg);
+ if (!NIL_P(tmp)) {
+ VALUE args;
+ if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
+ args = rb_ary_new3(2, self, template);
+ rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
+ }
+ else{
+ const unsigned char *p;
+ VALUE str = ossl_to_der_if_possible(arg);
+ X509_NAME *x;
+ StringValue(str);
+ p = (unsigned char *)RSTRING_PTR(str);
+ x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
+ DATA_PTR(self) = name;
+ if(!x){
+ ossl_raise(eX509NameError, NULL);
+ }
+ }
}
return self;
@@ -189,7 +184,7 @@ ossl_x509name_initialize_copy(VALUE self, VALUE other)
name_new = X509_NAME_dup(name_other);
if (!name_new)
- ossl_raise(eX509NameError, "X509_NAME_dup");
+ ossl_raise(eX509NameError, "X509_NAME_dup");
SetX509Name(self, name_new);
X509_NAME_free(name);
@@ -226,8 +221,8 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
int loc = -1, set = 0;
if (!kwargs_ids[0]) {
- kwargs_ids[0] = rb_intern_const("loc");
- kwargs_ids[1] = rb_intern_const("set");
+ kwargs_ids[0] = rb_intern_const("loc");
+ kwargs_ids[1] = rb_intern_const("set");
}
rb_scan_args(argc, argv, "21:", &oid, &value, &type, &opts);
rb_get_kwargs(opts, kwargs_ids, 0, 2, kwargs);
@@ -235,14 +230,14 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
StringValue(value);
if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid);
if (kwargs[0] != Qundef)
- loc = NUM2INT(kwargs[0]);
+ loc = NUM2INT(kwargs[0]);
if (kwargs[1] != Qundef)
- set = NUM2INT(kwargs[1]);
+ set = NUM2INT(kwargs[1]);
GetX509Name(self, name);
if (!X509_NAME_add_entry_by_txt(name, oid_name, NUM2INT(type),
- (unsigned char *)RSTRING_PTR(value),
- RSTRING_LENINT(value), loc, set))
- ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt");
+ (unsigned char *)RSTRING_PTR(value),
+ RSTRING_LENINT(value), loc, set))
+ ossl_raise(eX509NameError, "X509_NAME_add_entry_by_txt");
return self;
}
@@ -255,7 +250,7 @@ ossl_x509name_to_s_old(VALUE self)
GetX509Name(self, name);
buf = X509_NAME_oneline(name, NULL, 0);
if (!buf)
- ossl_raise(eX509NameError, "X509_NAME_oneline");
+ ossl_raise(eX509NameError, "X509_NAME_oneline");
return ossl_buf2str(buf, rb_long2int(strlen(buf)));
}
@@ -269,11 +264,11 @@ x509name_print(VALUE self, unsigned long iflag)
GetX509Name(self, name);
out = BIO_new(BIO_s_mem());
if (!out)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
ret = X509_NAME_print_ex(out, name, 0, iflag);
if (ret < 0 || (iflag == XN_FLAG_COMPAT && ret == 0)) {
- BIO_free(out);
- ossl_raise(eX509NameError, "X509_NAME_print_ex");
+ BIO_free(out);
+ ossl_raise(eX509NameError, "X509_NAME_print_ex");
}
return ossl_membio2str(out);
}
@@ -307,9 +302,9 @@ ossl_x509name_to_s(int argc, VALUE *argv, VALUE self)
rb_check_arity(argc, 0, 1);
/* name.to_s(nil) was allowed */
if (!argc || NIL_P(argv[0]))
- return ossl_x509name_to_s_old(self);
+ return ossl_x509name_to_s_old(self);
else
- return x509name_print(self, NUM2ULONG(argv[0]));
+ return x509name_print(self, NUM2ULONG(argv[0]));
}
/*
@@ -332,7 +327,7 @@ static VALUE
ossl_x509name_inspect(VALUE self)
{
return rb_enc_sprintf(rb_utf8_encoding(), "#<%"PRIsVALUE" %"PRIsVALUE">",
- rb_obj_class(self), ossl_x509name_to_utf8(self));
+ rb_obj_class(self), ossl_x509name_to_utf8(self));
}
/*
@@ -346,34 +341,22 @@ static VALUE
ossl_x509name_to_a(VALUE self)
{
X509_NAME *name;
- X509_NAME_ENTRY *entry;
- int i,entries,nid;
- char long_name[512];
- const char *short_name;
- VALUE ary, vname, ret;
- ASN1_STRING *value;
+ int entries;
+ VALUE ret;
GetX509Name(self, name);
entries = X509_NAME_entry_count(name);
ret = rb_ary_new_capa(entries);
- for (i=0; i<entries; i++) {
- if (!(entry = X509_NAME_get_entry(name, i))) {
- ossl_raise(eX509NameError, NULL);
- }
- if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name),
- X509_NAME_ENTRY_get_object(entry))) {
- ossl_raise(eX509NameError, NULL);
- }
- nid = OBJ_ln2nid(long_name);
- if (nid == NID_undef) {
- vname = rb_str_new2((const char *) &long_name);
- } else {
- short_name = OBJ_nid2sn(nid);
- vname = rb_str_new2(short_name); /*do not free*/
- }
- value = X509_NAME_ENTRY_get_data(entry);
- ary = rb_ary_new3(3, vname, asn1str_to_str(value), INT2NUM(value->type));
- rb_ary_push(ret, ary);
+ for (int i = 0; i < entries; i++) {
+ const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
+ if (!entry)
+ ossl_raise(eX509NameError, "X509_NAME_get_entry");
+ const ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(entry);
+ VALUE vname = ossl_asn1obj_to_string(obj);
+ const ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry);
+ VALUE vdata = asn1str_to_str(data);
+ VALUE type = INT2NUM(ASN1_STRING_type(data));
+ rb_ary_push(ret, rb_ary_new_from_args(3, vname, vdata, type));
}
return ret;
}
@@ -404,7 +387,7 @@ ossl_x509name_cmp(VALUE self, VALUE other)
int result;
if (!rb_obj_is_kind_of(other, cX509Name))
- return Qnil;
+ return Qnil;
result = ossl_x509name_cmp0(self, other);
if (result < 0) return INT2FIX(-1);
@@ -423,7 +406,7 @@ static VALUE
ossl_x509name_eql(VALUE self, VALUE other)
{
if (!rb_obj_is_kind_of(other, cX509Name))
- return Qfalse;
+ return Qfalse;
return ossl_x509name_cmp0(self, other) == 0 ? Qtrue : Qfalse;
}
@@ -483,11 +466,11 @@ ossl_x509name_to_der(VALUE self)
GetX509Name(self, name);
if((len = i2d_X509_NAME(name, NULL)) <= 0)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if(i2d_X509_NAME(name, &p) <= 0)
- ossl_raise(eX509NameError, NULL);
+ ossl_raise(eX509NameError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -513,12 +496,6 @@ Init_ossl_x509name(void)
#undef rb_intern
VALUE utf8str, ptrstr, ia5str, hash;
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
id_aref = rb_intern("[]");
eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError);
cX509Name = rb_define_class_under(mX509, "Name", rb_cObject);
@@ -557,6 +534,7 @@ Init_ossl_x509name(void)
rb_hash_aset(hash, rb_str_new2("DC"), ia5str);
rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str);
rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str);
+ rb_obj_freeze(hash);
/*
* The default object type template for name entries.
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index add1f8d077..433cc461a9 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509req_type, 0)
#define SetX509Req(obj, req) do { \
if (!(req)) { \
- ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (req); \
} while (0)
#define GetX509Req(obj, req) do { \
TypedData_Get_Struct((obj), X509_REQ, &ossl_x509req_type, (req)); \
if (!(req)) { \
- ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509req_free(void *ptr)
static const rb_data_type_t ossl_x509req_type = {
"OpenSSL/X509/REQ",
{
- 0, ossl_x509req_free,
+ 0, ossl_x509req_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -68,7 +68,7 @@ ossl_x509req_alloc(VALUE klass)
obj = NewX509Req(klass);
if (!(req = X509_REQ_new())) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
SetX509Req(obj, req);
@@ -84,7 +84,7 @@ ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
rb_check_frozen(self);
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return self;
+ return self;
}
arg = ossl_to_der_if_possible(arg);
in = ossl_obj2bio(&arg);
@@ -114,7 +114,7 @@ ossl_x509req_copy(VALUE self, VALUE other)
GetX509Req(self, a);
GetX509Req(other, b);
if (!(req = X509_REQ_dup(b))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
X509_REQ_free(a);
DATA_PTR(self) = req;
@@ -130,11 +130,11 @@ ossl_x509req_to_pem(VALUE self)
GetX509Req(self, req);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
if (!PEM_write_bio_X509_REQ(out, req)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_membio2str(out);
@@ -150,11 +150,11 @@ ossl_x509req_to_der(VALUE self)
GetX509Req(self, req);
if ((len = i2d_X509_REQ(req, NULL)) <= 0)
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
str = rb_str_new(0, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509_REQ(req, &p) <= 0)
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
ossl_str_adjust(str, p);
return str;
@@ -168,11 +168,11 @@ ossl_x509req_to_text(VALUE self)
GetX509Req(self, req);
if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
if (!X509_REQ_print(out, req)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
+ BIO_free(out);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_membio2str(out);
@@ -191,7 +191,7 @@ ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key)
GetX509Req(self, req);
...
if (!(x509 = X509_REQ_to_X509(req, d, pkey))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_x509_new(x509);
@@ -217,11 +217,11 @@ ossl_x509req_set_version(VALUE self, VALUE version)
long ver;
if ((ver = NUM2LONG(version)) < 0) {
- ossl_raise(eX509ReqError, "version must be >= 0!");
+ ossl_raise(eX509ReqError, "version must be >= 0!");
}
GetX509Req(self, req);
if (!X509_REQ_set_version(req, ver)) {
- ossl_raise(eX509ReqError, "X509_REQ_set_version");
+ ossl_raise(eX509ReqError, "X509_REQ_set_version");
}
return version;
@@ -235,7 +235,7 @@ ossl_x509req_get_subject(VALUE self)
GetX509Req(self, req);
if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return ossl_x509name_new(name);
@@ -249,33 +249,32 @@ ossl_x509req_set_subject(VALUE self, VALUE subject)
GetX509Req(self, req);
/* DUPs name */
if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return subject;
}
+/*
+ * call-seq:
+ * req.signature_algorithm -> string
+ *
+ * Returns the signature algorithm used to sign this request.
+ *
+ * Returns the long name of the signature algorithm, or the dotted decimal
+ * notation if \OpenSSL does not define a long name for it.
+ */
static VALUE
ossl_x509req_get_signature_algorithm(VALUE self)
{
X509_REQ *req;
const X509_ALGOR *alg;
const ASN1_OBJECT *obj;
- BIO *out;
GetX509Req(self, req);
-
- if (!(out = BIO_new(BIO_s_mem()))) {
- ossl_raise(eX509ReqError, NULL);
- }
X509_REQ_get0_signature(req, NULL, &alg);
X509_ALGOR_get0(&obj, NULL, NULL, alg);
- if (!i2a_ASN1_OBJECT(out, obj)) {
- BIO_free(out);
- ossl_raise(eX509ReqError, NULL);
- }
-
- return ossl_membio2str(out);
+ return ossl_asn1obj_to_string_long_name(obj);
}
static VALUE
@@ -286,10 +285,10 @@ ossl_x509req_get_public_key(VALUE self)
GetX509Req(self, req);
if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
- return ossl_pkey_new(pkey); /* NO DUP - OK */
+ return ossl_pkey_wrap(pkey);
}
static VALUE
@@ -302,7 +301,7 @@ ossl_x509req_set_public_key(VALUE self, VALUE key)
pkey = GetPKeyPtr(key);
ossl_pkey_check_public_key(pkey);
if (!X509_REQ_set_pubkey(req, pkey))
- ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
+ ossl_raise(eX509ReqError, "X509_REQ_set_pubkey");
return key;
}
@@ -312,17 +311,14 @@ ossl_x509req_sign(VALUE self, VALUE key, VALUE digest)
X509_REQ *req;
EVP_PKEY *pkey;
const EVP_MD *md;
+ VALUE md_holder;
GetX509Req(self, req);
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- if (NIL_P(digest)) {
- md = NULL; /* needed for some key types, e.g. Ed25519 */
- } else {
- md = ossl_evp_get_digestbyname(digest);
- }
- if (!X509_REQ_sign(req, pkey, md)) {
- ossl_raise(eX509ReqError, NULL);
- }
+ /* NULL needed for some key types, e.g. Ed25519 */
+ md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);
+ if (!X509_REQ_sign(req, pkey, md))
+ ossl_raise(eX509ReqError, "X509_REQ_sign");
return self;
}
@@ -341,12 +337,12 @@ ossl_x509req_verify(VALUE self, VALUE key)
ossl_pkey_check_public_key(pkey);
switch (X509_REQ_verify(req, pkey)) {
case 1:
- return Qtrue;
+ return Qtrue;
case 0:
- ossl_clear_error();
- return Qfalse;
+ ossl_clear_error();
+ return Qfalse;
default:
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
}
@@ -362,13 +358,13 @@ ossl_x509req_get_attributes(VALUE self)
count = X509_REQ_get_attr_count(req);
if (count < 0) {
- OSSL_Debug("count < 0???");
- return rb_ary_new();
+ OSSL_Debug("count < 0???");
+ return rb_ary_new();
}
ary = rb_ary_new2(count);
for (i=0; i<count; i++) {
- attr = X509_REQ_get_attr(req, i);
- rb_ary_push(ary, ossl_x509attr_new(attr));
+ attr = X509_REQ_get_attr(req, i);
+ rb_ary_push(ary, ossl_x509attr_new(attr));
}
return ary;
@@ -384,17 +380,17 @@ ossl_x509req_set_attributes(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
for (i=0;i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr);
}
GetX509Req(self, req);
for (i = X509_REQ_get_attr_count(req); i > 0; i--)
X509_ATTRIBUTE_free(X509_REQ_delete_attr(req, 0));
for (i=0;i<RARRAY_LEN(ary); i++) {
- item = RARRAY_AREF(ary, i);
- attr = GetX509AttrPtr(item);
- if (!X509_REQ_add1_attr(req, attr)) {
- ossl_raise(eX509ReqError, "X509_REQ_add1_attr");
- }
+ item = RARRAY_AREF(ary, i);
+ attr = GetX509AttrPtr(item);
+ if (!X509_REQ_add1_attr(req, attr)) {
+ ossl_raise(eX509ReqError, "X509_REQ_add1_attr");
+ }
}
return ary;
}
@@ -406,7 +402,7 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr)
GetX509Req(self, req);
if (!X509_REQ_add1_attr(req, GetX509AttrPtr(attr))) {
- ossl_raise(eX509ReqError, NULL);
+ ossl_raise(eX509ReqError, NULL);
}
return attr;
@@ -418,12 +414,6 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr)
void
Init_ossl_x509req(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError);
cX509Req = rb_define_class_under(mX509, "Request", rb_cObject);
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index 1eff5dd355..b88c390c72 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509rev_type, 0)
#define SetX509Rev(obj, rev) do { \
if (!(rev)) { \
- ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (rev); \
} while (0)
#define GetX509Rev(obj, rev) do { \
TypedData_Get_Struct((obj), X509_REVOKED, &ossl_x509rev_type, (rev)); \
if (!(rev)) { \
- ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
} \
} while (0)
@@ -39,7 +39,7 @@ ossl_x509rev_free(void *ptr)
static const rb_data_type_t ossl_x509rev_type = {
"OpenSSL/X509/REV",
{
- 0, ossl_x509rev_free,
+ 0, ossl_x509rev_free,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
@@ -54,14 +54,9 @@ ossl_x509revoked_new(X509_REVOKED *rev)
VALUE obj;
obj = NewX509Rev(cX509Rev);
- if (!rev) {
- new = X509_REVOKED_new();
- } else {
- new = X509_REVOKED_dup(rev);
- }
- if (!new) {
- ossl_raise(eX509RevError, NULL);
- }
+ new = X509_REVOKED_dup(rev);
+ if (!new)
+ ossl_raise(eX509RevError, "X509_REVOKED_dup");
SetX509Rev(obj, new);
return obj;
@@ -74,7 +69,7 @@ DupX509RevokedPtr(VALUE obj)
GetX509Rev(obj, rev);
if (!(new = X509_REVOKED_dup(rev))) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
return new;
@@ -91,7 +86,7 @@ ossl_x509revoked_alloc(VALUE klass)
obj = NewX509Rev(klass);
if (!(rev = X509_REVOKED_new())) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
SetX509Rev(obj, rev);
@@ -117,7 +112,7 @@ ossl_x509revoked_initialize_copy(VALUE self, VALUE other)
rev_new = X509_REVOKED_dup(rev_other);
if (!rev_new)
- ossl_raise(eX509RevError, "X509_REVOKED_dup");
+ ossl_raise(eX509RevError, "X509_REVOKED_dup");
SetX509Rev(self, rev_new);
X509_REVOKED_free(rev);
@@ -144,8 +139,8 @@ ossl_x509revoked_set_serial(VALUE self, VALUE num)
GetX509Rev(self, rev);
asn1int = num_to_asn1integer(num, NULL);
if (!X509_REVOKED_set_serialNumber(rev, asn1int)) {
- ASN1_INTEGER_free(asn1int);
- ossl_raise(eX509RevError, "X509_REVOKED_set_serialNumber");
+ ASN1_INTEGER_free(asn1int);
+ ossl_raise(eX509RevError, "X509_REVOKED_set_serialNumber");
}
ASN1_INTEGER_free(asn1int);
@@ -161,7 +156,7 @@ ossl_x509revoked_get_time(VALUE self)
GetX509Rev(self, rev);
time = X509_REVOKED_get0_revocationDate(rev);
if (!time)
- return Qnil;
+ return Qnil;
return asn1time_to_time(time);
}
@@ -175,8 +170,8 @@ ossl_x509revoked_set_time(VALUE self, VALUE time)
GetX509Rev(self, rev);
asn1time = ossl_x509_time_adjust(NULL, time);
if (!X509_REVOKED_set_revocationDate(rev, asn1time)) {
- ASN1_TIME_free(asn1time);
- ossl_raise(eX509RevError, "X509_REVOKED_set_revocationDate");
+ ASN1_TIME_free(asn1time);
+ ossl_raise(eX509RevError, "X509_REVOKED_set_revocationDate");
}
ASN1_TIME_free(asn1time);
@@ -197,8 +192,8 @@ ossl_x509revoked_get_extensions(VALUE self)
count = X509_REVOKED_get_ext_count(rev);
ary = rb_ary_new_capa(count);
for (i=0; i<count; i++) {
- ext = X509_REVOKED_get_ext(rev, i);
- rb_ary_push(ary, ossl_x509ext_new(ext));
+ ext = X509_REVOKED_get_ext(rev, i);
+ rb_ary_push(ary, ossl_x509ext_new(ext));
}
return ary;
@@ -217,17 +212,17 @@ ossl_x509revoked_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
for (i=0; i<RARRAY_LEN(ary); i++) {
- OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
+ OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);
}
GetX509Rev(self, rev);
for (i = X509_REVOKED_get_ext_count(rev); i > 0; i--)
X509_EXTENSION_free(X509_REVOKED_delete_ext(rev, 0));
for (i=0; i<RARRAY_LEN(ary); i++) {
- item = RARRAY_AREF(ary, i);
- ext = GetX509ExtPtr(item);
- if(!X509_REVOKED_add_ext(rev, ext, -1)) {
- ossl_raise(eX509RevError, "X509_REVOKED_add_ext");
- }
+ item = RARRAY_AREF(ary, i);
+ ext = GetX509ExtPtr(item);
+ if(!X509_REVOKED_add_ext(rev, ext, -1)) {
+ ossl_raise(eX509RevError, "X509_REVOKED_add_ext");
+ }
}
return ary;
@@ -240,7 +235,7 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
GetX509Rev(self, rev);
if (!X509_REVOKED_add_ext(rev, GetX509ExtPtr(ext), -1)) {
- ossl_raise(eX509RevError, NULL);
+ ossl_raise(eX509RevError, NULL);
}
return ext;
@@ -257,11 +252,11 @@ ossl_x509revoked_to_der(VALUE self)
GetX509Rev(self, rev);
len = i2d_X509_REVOKED(rev, NULL);
if (len <= 0)
- ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
str = rb_str_new(NULL, len);
p = (unsigned char *)RSTRING_PTR(str);
if (i2d_X509_REVOKED(rev, &p) <= 0)
- ossl_raise(eX509RevError, "i2d_X509_REVOKED");
+ ossl_raise(eX509RevError, "i2d_X509_REVOKED");
ossl_str_adjust(str, p);
return str;
}
@@ -272,12 +267,6 @@ ossl_x509revoked_to_der(VALUE self)
void
Init_ossl_x509revoked(void)
{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
eX509RevError = rb_define_class_under(mX509, "RevokedError", eOSSLError);
cX509Rev = rb_define_class_under(mX509, "Revoked", rb_cObject);
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index 18acdc8ad0..be1458cec5 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -13,14 +13,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509store_type, 0)
#define SetX509Store(obj, st) do { \
if (!(st)) { \
- ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (st); \
} while (0)
#define GetX509Store(obj, st) do { \
TypedData_Get_Struct((obj), X509_STORE, &ossl_x509store_type, (st)); \
if (!(st)) { \
- ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
} \
} while (0)
@@ -28,14 +28,14 @@
TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, 0)
#define SetX509StCtx(obj, ctx) do { \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
} \
RTYPEDDATA_DATA(obj) = (ctx); \
} while (0)
#define GetX509StCtx(obj, ctx) do { \
TypedData_Get_Struct((obj), X509_STORE_CTX, &ossl_x509stctx_type, (ctx)); \
if (!(ctx)) { \
- ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
} \
} while (0)
@@ -62,7 +62,7 @@ call_verify_cb_proc(VALUE arg)
{
struct ossl_verify_cb_args *args = (struct ossl_verify_cb_args *)arg;
return rb_funcall(args->proc, rb_intern("call"), 2,
- args->preverify_ok, args->store_ctx);
+ args->preverify_ok, args->store_ctx);
}
int
@@ -73,33 +73,33 @@ ossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx)
int state;
if (NIL_P(proc))
- return ok;
+ return ok;
ret = Qfalse;
rctx = rb_protect(ossl_x509stctx_new_i, (VALUE)ctx, &state);
if (state) {
- rb_set_errinfo(Qnil);
- rb_warn("StoreContext initialization failure");
+ rb_set_errinfo(Qnil);
+ rb_warn("StoreContext initialization failure");
}
else {
- args.proc = proc;
- args.preverify_ok = ok ? Qtrue : Qfalse;
- args.store_ctx = rctx;
- ret = rb_protect(call_verify_cb_proc, (VALUE)&args, &state);
- if (state) {
- rb_set_errinfo(Qnil);
- rb_warn("exception in verify_callback is ignored");
- }
- RTYPEDDATA_DATA(rctx) = NULL;
+ args.proc = proc;
+ args.preverify_ok = ok ? Qtrue : Qfalse;
+ args.store_ctx = rctx;
+ ret = rb_protect(call_verify_cb_proc, (VALUE)&args, &state);
+ if (state) {
+ rb_set_errinfo(Qnil);
+ rb_warn("exception in verify_callback is ignored");
+ }
+ RTYPEDDATA_DATA(rctx) = NULL;
}
if (ret == Qtrue) {
- X509_STORE_CTX_set_error(ctx, X509_V_OK);
- ok = 1;
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ ok = 1;
}
else {
- if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
- X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
- ok = 0;
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
+ ok = 0;
}
return ok;
@@ -159,10 +159,10 @@ x509store_verify_cb(int ok, X509_STORE_CTX *ctx)
proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx);
if (!proc)
- proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx),
- store_ex_verify_cb_idx);
+ proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx),
+ store_ex_verify_cb_idx);
if (!proc)
- return ok;
+ return ok;
return ossl_verify_cb_call(proc, ok, ctx);
}
@@ -191,8 +191,8 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
GetX509Store(self, store);
rb_iv_set(self, "@verify_callback", cb);
- // We don't need to trigger a write barrier because `rb_iv_set` did it.
X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb);
+ RB_OBJ_WRITTEN(self, Qundef, cb);
return cb;
}
@@ -484,7 +484,7 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &cert, &chain);
ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain);
proc = rb_block_given_p() ? rb_block_proc() :
- rb_iv_get(self, "@verify_callback");
+ rb_iv_get(self, "@verify_callback");
rb_iv_set(ctx, "@verify_callback", proc);
result = rb_funcall(ctx, rb_intern("verify"), 0);
@@ -513,9 +513,9 @@ ossl_x509stctx_free(void *ptr)
{
X509_STORE_CTX *ctx = ptr;
if (X509_STORE_CTX_get0_untrusted(ctx))
- sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free);
+ sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free);
if (X509_STORE_CTX_get0_cert(ctx))
- X509_free(X509_STORE_CTX_get0_cert(ctx));
+ X509_free(X509_STORE_CTX_get0_cert(ctx));
X509_STORE_CTX_free(ctx);
}
@@ -611,6 +611,7 @@ ossl_x509stctx_verify(VALUE self)
GetX509StCtx(self, ctx);
VALUE cb = rb_iv_get(self, "@verify_callback");
X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb);
+ RB_OBJ_WRITTEN(self, Qundef, cb);
switch (X509_verify_cert(ctx)) {
case 1:
@@ -735,10 +736,14 @@ static VALUE
ossl_x509stctx_get_curr_cert(VALUE self)
{
X509_STORE_CTX *ctx;
+ X509 *x509;
GetX509StCtx(self, ctx);
+ x509 = X509_STORE_CTX_get_current_cert(ctx);
+ if (!x509)
+ return Qnil;
- return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
+ return ossl_x509_new(x509);
}
/*
@@ -758,7 +763,7 @@ ossl_x509stctx_get_curr_crl(VALUE self)
GetX509StCtx(self, ctx);
crl = X509_STORE_CTX_get0_current_crl(ctx);
if (!crl)
- return Qnil;
+ return Qnil;
return ossl_x509crl_new(crl);
}
@@ -854,19 +859,13 @@ void
Init_ossl_x509store(void)
{
#undef rb_intern
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
- mX509 = rb_define_module_under(mOSSL, "X509");
-#endif
-
/* Register ext_data slot for verify callback Proc */
stctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"stctx_ex_verify_cb_idx", 0, 0, 0);
if (stctx_ex_verify_cb_idx < 0)
- ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
+ ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)"store_ex_verify_cb_idx", 0, 0, 0);
if (store_ex_verify_cb_idx < 0)
- ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index");
+ ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index");
eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError);
diff --git a/ext/pathname/depend b/ext/pathname/depend
deleted file mode 100644
index cca7877dad..0000000000
--- a/ext/pathname/depend
+++ /dev/null
@@ -1,174 +0,0 @@
-# AUTOGENERATED DEPENDENCIES START
-pathname.o: $(RUBY_EXTCONF_H)
-pathname.o: $(arch_hdrdir)/ruby/config.h
-pathname.o: $(hdrdir)/ruby.h
-pathname.o: $(hdrdir)/ruby/assert.h
-pathname.o: $(hdrdir)/ruby/backward.h
-pathname.o: $(hdrdir)/ruby/backward/2/assume.h
-pathname.o: $(hdrdir)/ruby/backward/2/attributes.h
-pathname.o: $(hdrdir)/ruby/backward/2/bool.h
-pathname.o: $(hdrdir)/ruby/backward/2/inttypes.h
-pathname.o: $(hdrdir)/ruby/backward/2/limits.h
-pathname.o: $(hdrdir)/ruby/backward/2/long_long.h
-pathname.o: $(hdrdir)/ruby/backward/2/stdalign.h
-pathname.o: $(hdrdir)/ruby/backward/2/stdarg.h
-pathname.o: $(hdrdir)/ruby/defines.h
-pathname.o: $(hdrdir)/ruby/encoding.h
-pathname.o: $(hdrdir)/ruby/intern.h
-pathname.o: $(hdrdir)/ruby/internal/abi.h
-pathname.o: $(hdrdir)/ruby/internal/anyargs.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-pathname.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-pathname.o: $(hdrdir)/ruby/internal/assume.h
-pathname.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-pathname.o: $(hdrdir)/ruby/internal/attr/artificial.h
-pathname.o: $(hdrdir)/ruby/internal/attr/cold.h
-pathname.o: $(hdrdir)/ruby/internal/attr/const.h
-pathname.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-pathname.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-pathname.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-pathname.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-pathname.o: $(hdrdir)/ruby/internal/attr/error.h
-pathname.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-pathname.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-pathname.o: $(hdrdir)/ruby/internal/attr/format.h
-pathname.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-pathname.o: $(hdrdir)/ruby/internal/attr/noalias.h
-pathname.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-pathname.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-pathname.o: $(hdrdir)/ruby/internal/attr/noinline.h
-pathname.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-pathname.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pathname.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-pathname.o: $(hdrdir)/ruby/internal/attr/pure.h
-pathname.o: $(hdrdir)/ruby/internal/attr/restrict.h
-pathname.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-pathname.o: $(hdrdir)/ruby/internal/attr/warning.h
-pathname.o: $(hdrdir)/ruby/internal/attr/weakref.h
-pathname.o: $(hdrdir)/ruby/internal/cast.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-pathname.o: $(hdrdir)/ruby/internal/compiler_since.h
-pathname.o: $(hdrdir)/ruby/internal/config.h
-pathname.o: $(hdrdir)/ruby/internal/constant_p.h
-pathname.o: $(hdrdir)/ruby/internal/core.h
-pathname.o: $(hdrdir)/ruby/internal/core/rarray.h
-pathname.o: $(hdrdir)/ruby/internal/core/rbasic.h
-pathname.o: $(hdrdir)/ruby/internal/core/rbignum.h
-pathname.o: $(hdrdir)/ruby/internal/core/rclass.h
-pathname.o: $(hdrdir)/ruby/internal/core/rdata.h
-pathname.o: $(hdrdir)/ruby/internal/core/rfile.h
-pathname.o: $(hdrdir)/ruby/internal/core/rhash.h
-pathname.o: $(hdrdir)/ruby/internal/core/robject.h
-pathname.o: $(hdrdir)/ruby/internal/core/rregexp.h
-pathname.o: $(hdrdir)/ruby/internal/core/rstring.h
-pathname.o: $(hdrdir)/ruby/internal/core/rstruct.h
-pathname.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-pathname.o: $(hdrdir)/ruby/internal/ctype.h
-pathname.o: $(hdrdir)/ruby/internal/dllexport.h
-pathname.o: $(hdrdir)/ruby/internal/dosish.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/re.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/string.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-pathname.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-pathname.o: $(hdrdir)/ruby/internal/error.h
-pathname.o: $(hdrdir)/ruby/internal/eval.h
-pathname.o: $(hdrdir)/ruby/internal/event.h
-pathname.o: $(hdrdir)/ruby/internal/fl_type.h
-pathname.o: $(hdrdir)/ruby/internal/gc.h
-pathname.o: $(hdrdir)/ruby/internal/glob.h
-pathname.o: $(hdrdir)/ruby/internal/globals.h
-pathname.o: $(hdrdir)/ruby/internal/has/attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/builtin.h
-pathname.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-pathname.o: $(hdrdir)/ruby/internal/has/extension.h
-pathname.o: $(hdrdir)/ruby/internal/has/feature.h
-pathname.o: $(hdrdir)/ruby/internal/has/warning.h
-pathname.o: $(hdrdir)/ruby/internal/intern/array.h
-pathname.o: $(hdrdir)/ruby/internal/intern/bignum.h
-pathname.o: $(hdrdir)/ruby/internal/intern/class.h
-pathname.o: $(hdrdir)/ruby/internal/intern/compar.h
-pathname.o: $(hdrdir)/ruby/internal/intern/complex.h
-pathname.o: $(hdrdir)/ruby/internal/intern/cont.h
-pathname.o: $(hdrdir)/ruby/internal/intern/dir.h
-pathname.o: $(hdrdir)/ruby/internal/intern/enum.h
-pathname.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-pathname.o: $(hdrdir)/ruby/internal/intern/error.h
-pathname.o: $(hdrdir)/ruby/internal/intern/eval.h
-pathname.o: $(hdrdir)/ruby/internal/intern/file.h
-pathname.o: $(hdrdir)/ruby/internal/intern/hash.h
-pathname.o: $(hdrdir)/ruby/internal/intern/io.h
-pathname.o: $(hdrdir)/ruby/internal/intern/load.h
-pathname.o: $(hdrdir)/ruby/internal/intern/marshal.h
-pathname.o: $(hdrdir)/ruby/internal/intern/numeric.h
-pathname.o: $(hdrdir)/ruby/internal/intern/object.h
-pathname.o: $(hdrdir)/ruby/internal/intern/parse.h
-pathname.o: $(hdrdir)/ruby/internal/intern/proc.h
-pathname.o: $(hdrdir)/ruby/internal/intern/process.h
-pathname.o: $(hdrdir)/ruby/internal/intern/random.h
-pathname.o: $(hdrdir)/ruby/internal/intern/range.h
-pathname.o: $(hdrdir)/ruby/internal/intern/rational.h
-pathname.o: $(hdrdir)/ruby/internal/intern/re.h
-pathname.o: $(hdrdir)/ruby/internal/intern/ruby.h
-pathname.o: $(hdrdir)/ruby/internal/intern/select.h
-pathname.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-pathname.o: $(hdrdir)/ruby/internal/intern/signal.h
-pathname.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-pathname.o: $(hdrdir)/ruby/internal/intern/string.h
-pathname.o: $(hdrdir)/ruby/internal/intern/struct.h
-pathname.o: $(hdrdir)/ruby/internal/intern/thread.h
-pathname.o: $(hdrdir)/ruby/internal/intern/time.h
-pathname.o: $(hdrdir)/ruby/internal/intern/variable.h
-pathname.o: $(hdrdir)/ruby/internal/intern/vm.h
-pathname.o: $(hdrdir)/ruby/internal/interpreter.h
-pathname.o: $(hdrdir)/ruby/internal/iterator.h
-pathname.o: $(hdrdir)/ruby/internal/memory.h
-pathname.o: $(hdrdir)/ruby/internal/method.h
-pathname.o: $(hdrdir)/ruby/internal/module.h
-pathname.o: $(hdrdir)/ruby/internal/newobj.h
-pathname.o: $(hdrdir)/ruby/internal/scan_args.h
-pathname.o: $(hdrdir)/ruby/internal/special_consts.h
-pathname.o: $(hdrdir)/ruby/internal/static_assert.h
-pathname.o: $(hdrdir)/ruby/internal/stdalign.h
-pathname.o: $(hdrdir)/ruby/internal/stdbool.h
-pathname.o: $(hdrdir)/ruby/internal/stdckdint.h
-pathname.o: $(hdrdir)/ruby/internal/symbol.h
-pathname.o: $(hdrdir)/ruby/internal/value.h
-pathname.o: $(hdrdir)/ruby/internal/value_type.h
-pathname.o: $(hdrdir)/ruby/internal/variable.h
-pathname.o: $(hdrdir)/ruby/internal/warning_push.h
-pathname.o: $(hdrdir)/ruby/internal/xmalloc.h
-pathname.o: $(hdrdir)/ruby/missing.h
-pathname.o: $(hdrdir)/ruby/onigmo.h
-pathname.o: $(hdrdir)/ruby/oniguruma.h
-pathname.o: $(hdrdir)/ruby/ruby.h
-pathname.o: $(hdrdir)/ruby/st.h
-pathname.o: $(hdrdir)/ruby/subst.h
-pathname.o: pathname.c
-# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/pathname/extconf.rb b/ext/pathname/extconf.rb
deleted file mode 100644
index b4e1617b9e..0000000000
--- a/ext/pathname/extconf.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: false
-require 'mkmf'
-create_makefile('pathname')
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
deleted file mode 100644
index 35fd778561..0000000000
--- a/ext/pathname/lib/pathname.rb
+++ /dev/null
@@ -1,621 +0,0 @@
-# frozen_string_literal: true
-#
-# = pathname.rb
-#
-# Object-Oriented Pathname Class
-#
-# Author:: Tanaka Akira <akr@m17n.org>
-# Documentation:: Author and Gavin Sinclair
-#
-# For documentation, see class Pathname.
-#
-
-require 'pathname.so'
-
-class Pathname
-
- VERSION = "0.4.0"
-
- # :stopdoc:
-
- # to_path is implemented so Pathname objects are usable with File.open, etc.
- TO_PATH = :to_path
-
- SAME_PATHS = if File::FNM_SYSCASE.nonzero?
- # Avoid #zero? here because #casecmp can return nil.
- proc {|a, b| a.casecmp(b) == 0}
- else
- proc {|a, b| a == b}
- end
-
-
- if File::ALT_SEPARATOR
- SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}"
- SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
- else
- SEPARATOR_LIST = "#{Regexp.quote File::SEPARATOR}"
- SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
- end
-
- if File.dirname('A:') == 'A:.' # DOSish drive letter
- ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/o
- else
- ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/o
- end
- private_constant :ABSOLUTE_PATH
-
- # :startdoc:
-
- # chop_basename(path) -> [pre-basename, basename] or nil
- def chop_basename(path) # :nodoc:
- base = File.basename(path)
- if /\A#{SEPARATOR_PAT}?\z/o.match?(base)
- return nil
- else
- return path[0, path.rindex(base)], base
- end
- end
- private :chop_basename
-
- # split_names(path) -> prefix, [name, ...]
- def split_names(path) # :nodoc:
- names = []
- while r = chop_basename(path)
- path, basename = r
- names.unshift basename
- end
- return path, names
- end
- private :split_names
-
- def prepend_prefix(prefix, relpath) # :nodoc:
- if relpath.empty?
- File.dirname(prefix)
- elsif /#{SEPARATOR_PAT}/o.match?(prefix)
- prefix = File.dirname(prefix)
- prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
- prefix + relpath
- else
- prefix + relpath
- end
- end
- private :prepend_prefix
-
- # Returns clean pathname of +self+ with consecutive slashes and useless dots
- # removed. The filesystem is not accessed.
- #
- # If +consider_symlink+ is +true+, then a more conservative algorithm is used
- # to avoid breaking symbolic linkages. This may retain more +..+
- # entries than absolutely necessary, but without accessing the filesystem,
- # this can't be avoided.
- #
- # See Pathname#realpath.
- #
- def cleanpath(consider_symlink=false)
- if consider_symlink
- cleanpath_conservative
- else
- cleanpath_aggressive
- end
- end
-
- #
- # Clean the path simply by resolving and removing excess +.+ and +..+ entries.
- # Nothing more, nothing less.
- #
- def cleanpath_aggressive # :nodoc:
- path = @path
- names = []
- pre = path
- while r = chop_basename(pre)
- pre, base = r
- case base
- when '.'
- when '..'
- names.unshift base
- else
- if names[0] == '..'
- names.shift
- else
- names.unshift base
- end
- end
- end
- pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
- if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
- names.shift while names[0] == '..'
- end
- self.class.new(prepend_prefix(pre, File.join(*names)))
- end
- private :cleanpath_aggressive
-
- # has_trailing_separator?(path) -> bool
- def has_trailing_separator?(path) # :nodoc:
- if r = chop_basename(path)
- pre, basename = r
- pre.length + basename.length < path.length
- else
- false
- end
- end
- private :has_trailing_separator?
-
- # add_trailing_separator(path) -> path
- def add_trailing_separator(path) # :nodoc:
- if File.basename(path + 'a') == 'a'
- path
- else
- File.join(path, "") # xxx: Is File.join is appropriate to add separator?
- end
- end
- private :add_trailing_separator
-
- def del_trailing_separator(path) # :nodoc:
- if r = chop_basename(path)
- pre, basename = r
- pre + basename
- elsif /#{SEPARATOR_PAT}+\z/o =~ path
- $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
- else
- path
- end
- end
- private :del_trailing_separator
-
- def cleanpath_conservative # :nodoc:
- path = @path
- names = []
- pre = path
- while r = chop_basename(pre)
- pre, base = r
- names.unshift base if base != '.'
- end
- pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
- if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
- names.shift while names[0] == '..'
- end
- if names.empty?
- self.class.new(File.dirname(pre))
- else
- if names.last != '..' && File.basename(path) == '.'
- names << '.'
- end
- result = prepend_prefix(pre, File.join(*names))
- if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
- self.class.new(add_trailing_separator(result))
- else
- self.class.new(result)
- end
- end
- end
- private :cleanpath_conservative
-
- # Returns the parent directory.
- #
- # This is same as <code>self + '..'</code>.
- def parent
- self + '..'
- end
-
- # Returns +true+ if +self+ points to a mountpoint.
- def mountpoint?
- begin
- stat1 = self.lstat
- stat2 = self.parent.lstat
- stat1.dev != stat2.dev || stat1.ino == stat2.ino
- rescue Errno::ENOENT
- false
- end
- end
-
- #
- # Predicate method for root directories. Returns +true+ if the
- # pathname consists of consecutive slashes.
- #
- # It doesn't access the filesystem. So it may return +false+ for some
- # pathnames which points to roots such as <tt>/usr/..</tt>.
- #
- def root?
- chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o.match?(@path)
- end
-
- # Predicate method for testing whether a path is absolute.
- #
- # It returns +true+ if the pathname begins with a slash.
- #
- # p = Pathname.new('/im/sure')
- # p.absolute?
- # #=> true
- #
- # p = Pathname.new('not/so/sure')
- # p.absolute?
- # #=> false
- def absolute?
- ABSOLUTE_PATH.match? @path
- end
-
- # The opposite of Pathname#absolute?
- #
- # It returns +false+ if the pathname begins with a slash.
- #
- # p = Pathname.new('/im/sure')
- # p.relative?
- # #=> false
- #
- # p = Pathname.new('not/so/sure')
- # p.relative?
- # #=> true
- def relative?
- !absolute?
- end
-
- #
- # Iterates over each component of the path.
- #
- # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
- # # yields "usr", "bin", and "ruby".
- #
- # Returns an Enumerator if no block was given.
- #
- # enum = Pathname.new("/usr/bin/ruby").each_filename
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields "usr", "bin", and "ruby".
- #
- def each_filename # :yield: filename
- return to_enum(__method__) unless block_given?
- _, names = split_names(@path)
- names.each {|filename| yield filename }
- nil
- end
-
- # Iterates over and yields a new Pathname object
- # for each element in the given path in descending order.
- #
- # Pathname.new('/path/to/some/file.rb').descend {|v| p v}
- # #<Pathname:/>
- # #<Pathname:/path>
- # #<Pathname:/path/to>
- # #<Pathname:/path/to/some>
- # #<Pathname:/path/to/some/file.rb>
- #
- # Pathname.new('path/to/some/file.rb').descend {|v| p v}
- # #<Pathname:path>
- # #<Pathname:path/to>
- # #<Pathname:path/to/some>
- # #<Pathname:path/to/some/file.rb>
- #
- # Returns an Enumerator if no block was given.
- #
- # enum = Pathname.new("/usr/bin/ruby").descend
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby.
- #
- # It doesn't access the filesystem.
- #
- def descend
- return to_enum(__method__) unless block_given?
- vs = []
- ascend {|v| vs << v }
- vs.reverse_each {|v| yield v }
- nil
- end
-
- # Iterates over and yields a new Pathname object
- # for each element in the given path in ascending order.
- #
- # Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
- # #<Pathname:/path/to/some/file.rb>
- # #<Pathname:/path/to/some>
- # #<Pathname:/path/to>
- # #<Pathname:/path>
- # #<Pathname:/>
- #
- # Pathname.new('path/to/some/file.rb').ascend {|v| p v}
- # #<Pathname:path/to/some/file.rb>
- # #<Pathname:path/to/some>
- # #<Pathname:path/to>
- # #<Pathname:path>
- #
- # Returns an Enumerator if no block was given.
- #
- # enum = Pathname.new("/usr/bin/ruby").ascend
- # # ... do stuff ...
- # enum.each { |e| ... }
- # # yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /.
- #
- # It doesn't access the filesystem.
- #
- def ascend
- return to_enum(__method__) unless block_given?
- path = @path
- yield self
- while r = chop_basename(path)
- path, = r
- break if path.empty?
- yield self.class.new(del_trailing_separator(path))
- end
- end
-
- #
- # Appends a pathname fragment to +self+ to produce a new Pathname object.
- # Since +other+ is considered as a path relative to +self+, if +other+ is
- # an absolute path, the new Pathname object is created from just +other+.
- #
- # p1 = Pathname.new("/usr") # Pathname:/usr
- # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
- # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
- #
- # # / is aliased to +.
- # p4 = p1 / "bin/ruby" # Pathname:/usr/bin/ruby
- # p5 = p1 / "/etc/passwd" # Pathname:/etc/passwd
- #
- # This method doesn't access the file system; it is pure string manipulation.
- #
- def +(other)
- other = Pathname.new(other) unless Pathname === other
- Pathname.new(plus(@path, other.to_s))
- end
- alias / +
-
- def plus(path1, path2) # -> path # :nodoc:
- prefix2 = path2
- index_list2 = []
- basename_list2 = []
- while r2 = chop_basename(prefix2)
- prefix2, basename2 = r2
- index_list2.unshift prefix2.length
- basename_list2.unshift basename2
- end
- return path2 if prefix2 != ''
- prefix1 = path1
- while true
- while !basename_list2.empty? && basename_list2.first == '.'
- index_list2.shift
- basename_list2.shift
- end
- break unless r1 = chop_basename(prefix1)
- prefix1, basename1 = r1
- next if basename1 == '.'
- if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
- prefix1 = prefix1 + basename1
- break
- end
- index_list2.shift
- basename_list2.shift
- end
- r1 = chop_basename(prefix1)
- if !r1 && (r1 = /#{SEPARATOR_PAT}/o.match?(File.basename(prefix1)))
- while !basename_list2.empty? && basename_list2.first == '..'
- index_list2.shift
- basename_list2.shift
- end
- end
- if !basename_list2.empty?
- suffix2 = path2[index_list2.first..-1]
- r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
- else
- r1 ? prefix1 : File.dirname(prefix1)
- end
- end
- private :plus
-
- #
- # Joins the given pathnames onto +self+ to create a new Pathname object.
- # This is effectively the same as using Pathname#+ to append +self+ and
- # all arguments sequentially.
- #
- # path0 = Pathname.new("/usr") # Pathname:/usr
- # path0 = path0.join("bin/ruby") # Pathname:/usr/bin/ruby
- # # is the same as
- # path1 = Pathname.new("/usr") + "bin/ruby" # Pathname:/usr/bin/ruby
- # path0 == path1
- # #=> true
- #
- def join(*args)
- return self if args.empty?
- result = args.pop
- result = Pathname.new(result) unless Pathname === result
- return result if result.absolute?
- args.reverse_each {|arg|
- arg = Pathname.new(arg) unless Pathname === arg
- result = arg + result
- return result if result.absolute?
- }
- self + result
- end
-
- #
- # Returns the children of the directory (files and subdirectories, not
- # recursive) as an array of Pathname objects.
- #
- # By default, the returned pathnames will have enough information to access
- # the files. If you set +with_directory+ to +false+, then the returned
- # pathnames will contain the filename only.
- #
- # For example:
- # pn = Pathname("/usr/lib/ruby/1.8")
- # pn.children
- # # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
- # Pathname:/usr/lib/ruby/1.8/Env.rb,
- # Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
- # pn.children(false)
- # # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
- #
- # Note that the results never contain the entries +.+ and +..+ in
- # the directory because they are not children.
- #
- def children(with_directory=true)
- with_directory = false if @path == '.'
- result = []
- Dir.foreach(@path) {|e|
- next if e == '.' || e == '..'
- if with_directory
- result << self.class.new(File.join(@path, e))
- else
- result << self.class.new(e)
- end
- }
- result
- end
-
- # Iterates over the children of the directory
- # (files and subdirectories, not recursive).
- #
- # It yields Pathname object for each child.
- #
- # By default, the yielded pathnames will have enough information to access
- # the files.
- #
- # If you set +with_directory+ to +false+, then the returned pathnames will
- # contain the filename only.
- #
- # Pathname("/usr/local").each_child {|f| p f }
- # #=> #<Pathname:/usr/local/share>
- # # #<Pathname:/usr/local/bin>
- # # #<Pathname:/usr/local/games>
- # # #<Pathname:/usr/local/lib>
- # # #<Pathname:/usr/local/include>
- # # #<Pathname:/usr/local/sbin>
- # # #<Pathname:/usr/local/src>
- # # #<Pathname:/usr/local/man>
- #
- # Pathname("/usr/local").each_child(false) {|f| p f }
- # #=> #<Pathname:share>
- # # #<Pathname:bin>
- # # #<Pathname:games>
- # # #<Pathname:lib>
- # # #<Pathname:include>
- # # #<Pathname:sbin>
- # # #<Pathname:src>
- # # #<Pathname:man>
- #
- # Note that the results never contain the entries +.+ and +..+ in
- # the directory because they are not children.
- #
- # See Pathname#children
- #
- def each_child(with_directory=true, &b)
- children(with_directory).each(&b)
- end
-
- #
- # Returns a relative path from the given +base_directory+ to the receiver.
- #
- # If +self+ is absolute, then +base_directory+ must be absolute too.
- #
- # If +self+ is relative, then +base_directory+ must be relative too.
- #
- # This method doesn't access the filesystem. It assumes no symlinks.
- #
- # ArgumentError is raised when it cannot find a relative path.
- #
- # Note that this method does not handle situations where the case sensitivity
- # of the filesystem in use differs from the operating system default.
- #
- def relative_path_from(base_directory)
- base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname
- dest_directory = self.cleanpath.to_s
- base_directory = base_directory.cleanpath.to_s
- dest_prefix = dest_directory
- dest_names = []
- while r = chop_basename(dest_prefix)
- dest_prefix, basename = r
- dest_names.unshift basename if basename != '.'
- end
- base_prefix = base_directory
- base_names = []
- while r = chop_basename(base_prefix)
- base_prefix, basename = r
- base_names.unshift basename if basename != '.'
- end
- unless SAME_PATHS[dest_prefix, base_prefix]
- raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
- end
- while !dest_names.empty? &&
- !base_names.empty? &&
- SAME_PATHS[dest_names.first, base_names.first]
- dest_names.shift
- base_names.shift
- end
- if base_names.include? '..'
- raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
- end
- base_names.fill('..')
- relpath_names = base_names + dest_names
- if relpath_names.empty?
- Pathname.new('.')
- else
- Pathname.new(File.join(*relpath_names))
- end
- end
-end
-
-
-class Pathname # * Find *
- #
- # Iterates over the directory tree in a depth first manner, yielding a
- # Pathname for each file under "this" directory.
- #
- # Returns an Enumerator if no block is given.
- #
- # Since it is implemented by the standard library module Find, Find.prune can
- # be used to control the traversal.
- #
- # If +self+ is +.+, yielded pathnames begin with a filename in the
- # current directory, not +./+.
- #
- # See Find.find
- #
- def find(ignore_error: true) # :yield: pathname
- return to_enum(__method__, ignore_error: ignore_error) unless block_given?
- require 'find'
- if @path == '.'
- Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.delete_prefix('./')) }
- else
- Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
- end
- end
-end
-
-
-class Pathname # * FileUtils *
- # Creates a full path, including any intermediate directories that don't yet
- # exist.
- #
- # See FileUtils.mkpath and FileUtils.mkdir_p
- def mkpath(mode: nil)
- require 'fileutils'
- FileUtils.mkpath(@path, mode: mode)
- self
- end
-
- # Recursively deletes a directory, including all directories beneath it.
- #
- # See FileUtils.rm_rf
- def rmtree(noop: nil, verbose: nil, secure: nil)
- # The name "rmtree" is borrowed from File::Path of Perl.
- # File::Path provides "mkpath" and "rmtree".
- require 'fileutils'
- FileUtils.rm_rf(@path, noop: noop, verbose: verbose, secure: secure)
- self
- end
-end
-
-class Pathname # * tmpdir *
- # Creates a tmp directory and wraps the returned path in a Pathname object.
- #
- # See Dir.mktmpdir
- def self.mktmpdir
- require 'tmpdir' unless defined?(Dir.mktmpdir)
- if block_given?
- Dir.mktmpdir do |dir|
- dir = self.new(dir)
- yield dir
- end
- else
- self.new(Dir.mktmpdir)
- end
- end
-end
diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c
deleted file mode 100644
index cdecb3f897..0000000000
--- a/ext/pathname/pathname.c
+++ /dev/null
@@ -1,1668 +0,0 @@
-#include "ruby.h"
-#include "ruby/encoding.h"
-
-static VALUE rb_cPathname;
-static ID id_ENOTDIR;
-static ID id_at_path;
-static ID id_atime;
-static ID id_base;
-static ID id_basename;
-static ID id_binread;
-static ID id_binwrite;
-static ID id_birthtime;
-static ID id_blockdev_p;
-static ID id_chardev_p;
-static ID id_chmod;
-static ID id_chown;
-static ID id_ctime;
-static ID id_directory_p;
-static ID id_dirname;
-static ID id_empty_p;
-static ID id_entries;
-static ID id_executable_p;
-static ID id_executable_real_p;
-static ID id_exist_p;
-static ID id_expand_path;
-static ID id_extname;
-static ID id_file_p;
-static ID id_fnmatch;
-static ID id_foreach;
-static ID id_ftype;
-static ID id_getwd;
-static ID id_glob;
-static ID id_grpowned_p;
-static ID id_lchmod;
-static ID id_lchown;
-static ID id_link;
-static ID id_lstat;
-static ID id_lutime;
-static ID id_mkdir;
-static ID id_mtime;
-static ID id_open;
-static ID id_owned_p;
-static ID id_pipe_p;
-static ID id_read;
-static ID id_readable_p;
-static ID id_readable_real_p;
-static ID id_readlines;
-static ID id_readlink;
-static ID id_realdirpath;
-static ID id_realpath;
-static ID id_rename;
-static ID id_rmdir;
-static ID id_setgid_p;
-static ID id_setuid_p;
-static ID id_size;
-static ID id_size_p;
-static ID id_socket_p;
-static ID id_split;
-static ID id_stat;
-static ID id_sticky_p;
-static ID id_sub;
-static ID id_symlink;
-static ID id_symlink_p;
-static ID id_sysopen;
-static ID id_to_path;
-static ID id_truncate;
-static ID id_unlink;
-static ID id_utime;
-static ID id_world_readable_p;
-static ID id_world_writable_p;
-static ID id_writable_p;
-static ID id_writable_real_p;
-static ID id_write;
-static ID id_zero_p;
-
-static VALUE
-get_strpath(VALUE obj)
-{
- VALUE strpath;
- strpath = rb_ivar_get(obj, id_at_path);
- if (!RB_TYPE_P(strpath, T_STRING))
- rb_raise(rb_eTypeError, "unexpected @path");
- return strpath;
-}
-
-static void
-set_strpath(VALUE obj, VALUE val)
-{
- rb_ivar_set(obj, id_at_path, val);
-}
-
-/*
- * Create a Pathname object from the given String (or String-like object).
- * If +path+ contains a NULL character (<tt>\0</tt>), an ArgumentError is raised.
- */
-static VALUE
-path_initialize(VALUE self, VALUE arg)
-{
- VALUE str;
- if (RB_TYPE_P(arg, T_STRING)) {
- str = arg;
- }
- else {
- str = rb_check_funcall(arg, id_to_path, 0, NULL);
- if (str == Qundef)
- str = arg;
- StringValue(str);
- }
- if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str)))
- rb_raise(rb_eArgError, "pathname contains null byte");
- str = rb_obj_dup(str);
-
- set_strpath(self, str);
- return self;
-}
-
-/*
- * call-seq:
- * pathname.freeze -> obj
- *
- * Freezes this Pathname.
- *
- * See Object.freeze.
- */
-static VALUE
-path_freeze(VALUE self)
-{
- rb_call_super(0, 0);
- rb_str_freeze(get_strpath(self));
- return self;
-}
-
-/*
- * Compare this pathname with +other+. The comparison is string-based.
- * Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
- * can refer to the same file.
- */
-static VALUE
-path_eq(VALUE self, VALUE other)
-{
- if (!rb_obj_is_kind_of(other, rb_cPathname))
- return Qfalse;
- return rb_str_equal(get_strpath(self), get_strpath(other));
-}
-
-/*
- * Provides a case-sensitive comparison operator for pathnames.
- *
- * Pathname.new('/usr') <=> Pathname.new('/usr/bin')
- * #=> -1
- * Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
- * #=> 0
- * Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
- * #=> 1
- *
- * It will return +-1+, +0+ or +1+ depending on the value of the left argument
- * relative to the right argument. Or it will return +nil+ if the arguments
- * are not comparable.
- */
-static VALUE
-path_cmp(VALUE self, VALUE other)
-{
- VALUE s1, s2;
- char *p1, *p2;
- char *e1, *e2;
- if (!rb_obj_is_kind_of(other, rb_cPathname))
- return Qnil;
- s1 = get_strpath(self);
- s2 = get_strpath(other);
- p1 = RSTRING_PTR(s1);
- p2 = RSTRING_PTR(s2);
- e1 = p1 + RSTRING_LEN(s1);
- e2 = p2 + RSTRING_LEN(s2);
- while (p1 < e1 && p2 < e2) {
- int c1, c2;
- c1 = (unsigned char)*p1++;
- c2 = (unsigned char)*p2++;
- if (c1 == '/') c1 = '\0';
- if (c2 == '/') c2 = '\0';
- if (c1 != c2) {
- if (c1 < c2)
- return INT2FIX(-1);
- else
- return INT2FIX(1);
- }
- }
- if (p1 < e1)
- return INT2FIX(1);
- if (p2 < e2)
- return INT2FIX(-1);
- return INT2FIX(0);
-}
-
-#ifndef ST2FIX
-#define ST2FIX(h) LONG2FIX((long)(h))
-#endif
-
-/* :nodoc: */
-static VALUE
-path_hash(VALUE self)
-{
- return ST2FIX(rb_str_hash(get_strpath(self)));
-}
-
-/*
- * call-seq:
- * pathname.to_s -> string
- * pathname.to_path -> string
- *
- * Return the path as a String.
- *
- * to_path is implemented so Pathname objects are usable with File.open, etc.
- */
-static VALUE
-path_to_s(VALUE self)
-{
- return rb_obj_dup(get_strpath(self));
-}
-
-/* :nodoc: */
-static VALUE
-path_inspect(VALUE self)
-{
- const char *c = rb_obj_classname(self);
- VALUE str = get_strpath(self);
- return rb_sprintf("#<%s:%"PRIsVALUE">", c, str);
-}
-
-/*
- * Return a pathname which is substituted by String#sub.
- *
- * path1 = Pathname.new('/usr/bin/perl')
- * path1.sub('perl', 'ruby')
- * #=> #<Pathname:/usr/bin/ruby>
- */
-static VALUE
-path_sub(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
-
- if (rb_block_given_p()) {
- str = rb_block_call(str, id_sub, argc, argv, 0, 0);
- }
- else {
- str = rb_funcallv(str, id_sub, argc, argv);
- }
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Return a pathname with +repl+ added as a suffix to the basename.
- *
- * If self has no extension part, +repl+ is appended.
- *
- * Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
- * #=> #<Pathname:/usr/bin/shutdown.rb>
- */
-static VALUE
-path_sub_ext(VALUE self, VALUE repl)
-{
- VALUE str = get_strpath(self);
- VALUE str2;
- long extlen;
- const char *ext;
- const char *p;
-
- StringValue(repl);
- p = RSTRING_PTR(str);
- extlen = RSTRING_LEN(str);
- ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str));
- if (ext == NULL) {
- ext = p + RSTRING_LEN(str);
- }
- else if (extlen <= 1) {
- ext += extlen;
- }
- str2 = rb_str_subseq(str, 0, ext-p);
- rb_str_append(str2, repl);
- return rb_class_new_instance(1, &str2, rb_obj_class(self));
-}
-
-/* Facade for File */
-
-/*
- * Returns the real (absolute) pathname for +self+ in the actual
- * filesystem.
- *
- * Does not contain symlinks or useless dots, +..+ and +.+.
- *
- * All components of the pathname must exist when this method is
- * called.
- *
- */
-static VALUE
-path_realpath(int argc, VALUE *argv, VALUE self)
-{
- VALUE basedir, str;
- rb_scan_args(argc, argv, "01", &basedir);
- str = rb_funcall(rb_cFile, id_realpath, 2, get_strpath(self), basedir);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the real (absolute) pathname of +self+ in the actual filesystem.
- *
- * Does not contain symlinks or useless dots, +..+ and +.+.
- *
- * The last component of the real pathname can be nonexistent.
- */
-static VALUE
-path_realdirpath(int argc, VALUE *argv, VALUE self)
-{
- VALUE basedir, str;
- rb_scan_args(argc, argv, "01", &basedir);
- str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * call-seq:
- * pathname.each_line {|line| ... }
- * pathname.each_line(sep=$/ [, open_args]) {|line| block } -> nil
- * pathname.each_line(limit [, open_args]) {|line| block } -> nil
- * pathname.each_line(sep, limit [, open_args]) {|line| block } -> nil
- * pathname.each_line(...) -> an_enumerator
- *
- * Iterates over each line in the file and yields a String object for each.
- */
-static VALUE
-path_each_line(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cFile, id_foreach, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- return rb_funcallv_kw(rb_cFile, id_foreach, 1+n, args, RB_PASS_CALLED_KEYWORDS);
- }
-}
-
-/*
- * call-seq:
- * pathname.read([length [, offset]]) -> string
- * pathname.read([length [, offset]], open_args) -> string
- *
- * Returns all data from the file, or the first +N+ bytes if specified.
- *
- * See File.read.
- *
- */
-static VALUE
-path_read(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_read, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.binread([length [, offset]]) -> string
- *
- * Returns all the bytes from the file, or the first +N+ if specified.
- *
- * See File.binread.
- *
- */
-static VALUE
-path_binread(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
- return rb_funcallv(rb_cFile, id_binread, 1+n, args);
-}
-
-/*
- * call-seq:
- * pathname.write(string, [offset] ) => fixnum
- * pathname.write(string, [offset], open_args ) => fixnum
- *
- * Writes +contents+ to the file.
- *
- * See File.write.
- *
- */
-static VALUE
-path_write(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_write, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.binwrite(string, [offset] ) => fixnum
- * pathname.binwrite(string, [offset], open_args ) => fixnum
- *
- * Writes +contents+ to the file, opening it in binary mode.
- *
- * See File.binwrite.
- *
- */
-static VALUE
-path_binwrite(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_binwrite, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.readlines(sep=$/ [, open_args]) -> array
- * pathname.readlines(limit [, open_args]) -> array
- * pathname.readlines(sep, limit [, open_args]) -> array
- *
- * Returns all the lines from the file.
- *
- * See File.readlines.
- *
- */
-static VALUE
-path_readlines(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- return rb_funcallv_kw(rb_cFile, id_readlines, 1+n, args, RB_PASS_CALLED_KEYWORDS);
-}
-
-/*
- * call-seq:
- * pathname.sysopen([mode, [perm]]) -> fixnum
- *
- * See IO.sysopen.
- *
- */
-static VALUE
-path_sysopen(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
- return rb_funcallv(rb_cIO, id_sysopen, 1+n, args);
-}
-
-/*
- * call-seq:
- * pathname.atime -> time
- *
- * Returns the last access time for the file.
- *
- * See File.atime.
- */
-static VALUE
-path_atime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.birthtime -> time
- *
- * Returns the birth time for the file.
- * If the platform doesn't have birthtime, raises NotImplementedError.
- *
- * See File.birthtime.
- */
-static VALUE
-path_birthtime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.ctime -> time
- *
- * Returns the last change time, using directory information, not the file itself.
- *
- * See File.ctime.
- */
-static VALUE
-path_ctime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_ctime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.mtime -> time
- *
- * Returns the last modified time of the file.
- *
- * See File.mtime.
- */
-static VALUE
-path_mtime(VALUE self)
-{
- return rb_funcall(rb_cFile, id_mtime, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.chmod(mode_int) -> integer
- *
- * Changes file permissions.
- *
- * See File.chmod.
- */
-static VALUE
-path_chmod(VALUE self, VALUE mode)
-{
- return rb_funcall(rb_cFile, id_chmod, 2, mode, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.lchmod(mode_int) -> integer
- *
- * Same as Pathname.chmod, but does not follow symbolic links.
- *
- * See File.lchmod.
- */
-static VALUE
-path_lchmod(VALUE self, VALUE mode)
-{
- return rb_funcall(rb_cFile, id_lchmod, 2, mode, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.chown(owner_int, group_int) -> integer
- *
- * Change owner and group of the file.
- *
- * See File.chown.
- */
-static VALUE
-path_chown(VALUE self, VALUE owner, VALUE group)
-{
- return rb_funcall(rb_cFile, id_chown, 3, owner, group, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.lchown(owner_int, group_int) -> integer
- *
- * Same as Pathname.chown, but does not follow symbolic links.
- *
- * See File.lchown.
- */
-static VALUE
-path_lchown(VALUE self, VALUE owner, VALUE group)
-{
- return rb_funcall(rb_cFile, id_lchown, 3, owner, group, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.fnmatch(pattern, [flags]) -> true or false
- * pathname.fnmatch?(pattern, [flags]) -> true or false
- *
- * Return +true+ if the receiver matches the given pattern.
- *
- * See File.fnmatch.
- */
-static VALUE
-path_fnmatch(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE pattern, flags;
- if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1)
- return rb_funcall(rb_cFile, id_fnmatch, 2, pattern, str);
- else
- return rb_funcall(rb_cFile, id_fnmatch, 3, pattern, str, flags);
-}
-
-/*
- * call-seq:
- * pathname.ftype -> string
- *
- * Returns "type" of file ("file", "directory", etc).
- *
- * See File.ftype.
- */
-static VALUE
-path_ftype(VALUE self)
-{
- return rb_funcall(rb_cFile, id_ftype, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.make_link(old)
- *
- * Creates a hard link at _pathname_.
- *
- * See File.link.
- */
-static VALUE
-path_make_link(VALUE self, VALUE old)
-{
- return rb_funcall(rb_cFile, id_link, 2, old, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.open()
- * pathname.open(mode="r" [, opt]) -> file
- * pathname.open([mode [, perm]] [, opt]) -> file
- * pathname.open(mode="r" [, opt]) {|file| block } -> obj
- * pathname.open([mode [, perm]] [, opt]) {|file| block } -> obj
- *
- * Opens the file for reading or writing.
- *
- * See File.open.
- */
-static VALUE
-path_open(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[4];
- int n;
-
- args[0] = get_strpath(self);
- n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cFile, id_open, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- return rb_funcallv_kw(rb_cFile, id_open, 1+n, args, RB_PASS_CALLED_KEYWORDS);
- }
-}
-
-/*
- * Read symbolic link.
- *
- * See File.readlink.
- */
-static VALUE
-path_readlink(VALUE self)
-{
- VALUE str;
- str = rb_funcall(rb_cFile, id_readlink, 1, get_strpath(self));
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Rename the file.
- *
- * See File.rename.
- */
-static VALUE
-path_rename(VALUE self, VALUE to)
-{
- return rb_funcall(rb_cFile, id_rename, 2, get_strpath(self), to);
-}
-
-/*
- * Returns a File::Stat object.
- *
- * See File.stat.
- */
-static VALUE
-path_stat(VALUE self)
-{
- return rb_funcall(rb_cFile, id_stat, 1, get_strpath(self));
-}
-
-/*
- * See File.lstat.
- */
-static VALUE
-path_lstat(VALUE self)
-{
- return rb_funcall(rb_cFile, id_lstat, 1, get_strpath(self));
-}
-
-/*
- * call-seq:
- * pathname.make_symlink(old)
- *
- * Creates a symbolic link.
- *
- * See File.symlink.
- */
-static VALUE
-path_make_symlink(VALUE self, VALUE old)
-{
- return rb_funcall(rb_cFile, id_symlink, 2, old, get_strpath(self));
-}
-
-/*
- * Truncates the file to +length+ bytes.
- *
- * See File.truncate.
- */
-static VALUE
-path_truncate(VALUE self, VALUE length)
-{
- return rb_funcall(rb_cFile, id_truncate, 2, get_strpath(self), length);
-}
-
-/*
- * Update the access and modification times of the file.
- *
- * See File.utime.
- */
-static VALUE
-path_utime(VALUE self, VALUE atime, VALUE mtime)
-{
- return rb_funcall(rb_cFile, id_utime, 3, atime, mtime, get_strpath(self));
-}
-
-/*
- * Update the access and modification times of the file.
- *
- * Same as Pathname#utime, but does not follow symbolic links.
- *
- * See File.lutime.
- */
-static VALUE
-path_lutime(VALUE self, VALUE atime, VALUE mtime)
-{
- return rb_funcall(rb_cFile, id_lutime, 3, atime, mtime, get_strpath(self));
-}
-
-/*
- * Returns the last component of the path.
- *
- * See File.basename.
- */
-static VALUE
-path_basename(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE fext;
- if (rb_scan_args(argc, argv, "01", &fext) == 0)
- str = rb_funcall(rb_cFile, id_basename, 1, str);
- else
- str = rb_funcall(rb_cFile, id_basename, 2, str, fext);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns all but the last component of the path.
- *
- * See File.dirname.
- */
-static VALUE
-path_dirname(VALUE self)
-{
- VALUE str = get_strpath(self);
- str = rb_funcall(rb_cFile, id_dirname, 1, str);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the file's extension.
- *
- * See File.extname.
- */
-static VALUE
-path_extname(VALUE self)
-{
- VALUE str = get_strpath(self);
- return rb_funcall(rb_cFile, id_extname, 1, str);
-}
-
-/*
- * Returns the absolute path for the file.
- *
- * See File.expand_path.
- */
-static VALUE
-path_expand_path(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE dname;
- if (rb_scan_args(argc, argv, "01", &dname) == 0)
- str = rb_funcall(rb_cFile, id_expand_path, 1, str);
- else
- str = rb_funcall(rb_cFile, id_expand_path, 2, str, dname);
- return rb_class_new_instance(1, &str, rb_obj_class(self));
-}
-
-/*
- * Returns the #dirname and the #basename in an Array.
- *
- * See File.split.
- */
-static VALUE
-path_split(VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE ary, dirname, basename;
- ary = rb_funcall(rb_cFile, id_split, 1, str);
- Check_Type(ary, T_ARRAY);
- dirname = rb_ary_entry(ary, 0);
- basename = rb_ary_entry(ary, 1);
- dirname = rb_class_new_instance(1, &dirname, rb_obj_class(self));
- basename = rb_class_new_instance(1, &basename, rb_obj_class(self));
- return rb_ary_new3(2, dirname, basename);
-}
-
-/*
- * See FileTest.blockdev?.
- */
-static VALUE
-path_blockdev_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_blockdev_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.chardev?.
- */
-static VALUE
-path_chardev_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_chardev_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.executable?.
- */
-static VALUE
-path_executable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_executable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.executable_real?.
- */
-static VALUE
-path_executable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_executable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.exist?.
- */
-static VALUE
-path_exist_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_exist_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.grpowned?.
- */
-static VALUE
-path_grpowned_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_grpowned_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.directory?.
- */
-static VALUE
-path_directory_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_directory_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.file?.
- */
-static VALUE
-path_file_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_file_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.pipe?.
- */
-static VALUE
-path_pipe_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_pipe_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.socket?.
- */
-static VALUE
-path_socket_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_socket_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.owned?.
- */
-static VALUE
-path_owned_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_owned_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.readable?.
- */
-static VALUE
-path_readable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_readable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.world_readable?.
- */
-static VALUE
-path_world_readable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_world_readable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.readable_real?.
- */
-static VALUE
-path_readable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_readable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.setuid?.
- */
-static VALUE
-path_setuid_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_setuid_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.setgid?.
- */
-static VALUE
-path_setgid_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_setgid_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.size.
- */
-static VALUE
-path_size(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_size, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.size?.
- */
-static VALUE
-path_size_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_size_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.sticky?.
- */
-static VALUE
-path_sticky_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_sticky_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.symlink?.
- */
-static VALUE
-path_symlink_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_symlink_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.writable?.
- */
-static VALUE
-path_writable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_writable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.world_writable?.
- */
-static VALUE
-path_world_writable_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_world_writable_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.writable_real?.
- */
-static VALUE
-path_writable_real_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_writable_real_p, 1, get_strpath(self));
-}
-
-/*
- * See FileTest.zero?.
- */
-static VALUE
-path_zero_p(VALUE self)
-{
- return rb_funcall(rb_mFileTest, id_zero_p, 1, get_strpath(self));
-}
-
-/*
- * Tests the file is empty.
- *
- * See Dir#empty? and FileTest.empty?.
- */
-static VALUE
-path_empty_p(VALUE self)
-{
-
- VALUE path = get_strpath(self);
- if (RTEST(rb_funcall(rb_mFileTest, id_directory_p, 1, path)))
- return rb_funcall(rb_cDir, id_empty_p, 1, path);
- else
- return rb_funcall(rb_mFileTest, id_empty_p, 1, path);
-}
-
-static VALUE
-s_glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
-{
- return rb_yield(rb_class_new_instance(1, &elt, klass));
-}
-
-/*
- * Returns or yields Pathname objects.
- *
- * Pathname.glob("lib/i*.rb")
- * #=> [#<Pathname:lib/ipaddr.rb>, #<Pathname:lib/irb.rb>]
- *
- * See Dir.glob.
- */
-static VALUE
-path_s_glob(int argc, VALUE *argv, VALUE klass)
-{
- VALUE args[3];
- int n;
-
- n = rb_scan_args(argc, argv, "12", &args[0], &args[1], &args[2]);
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cDir, id_glob, n, args, s_glob_i, klass, RB_PASS_CALLED_KEYWORDS);
- }
- else {
- VALUE ary;
- long i;
- ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_CALLED_KEYWORDS);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_class_new_instance(1, &elt, klass);
- rb_ary_store(ary, i, elt);
- }
- return ary;
- }
-}
-
-static VALUE
-glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, self))
-{
- elt = rb_funcall(self, '+', 1, elt);
- return rb_yield(elt);
-}
-
-/*
- * Returns or yields Pathname objects.
- *
- * Pathname("ruby-2.4.2").glob("R*.md")
- * #=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]
- *
- * See Dir.glob.
- * This method uses the +base+ keyword argument of Dir.glob.
- */
-static VALUE
-path_glob(int argc, VALUE *argv, VALUE self)
-{
- VALUE args[3];
- int n;
-
- n = rb_scan_args(argc, argv, "11", &args[0], &args[1]);
- if (n == 1)
- args[1] = INT2FIX(0);
-
- args[2] = rb_hash_new();
- rb_hash_aset(args[2], ID2SYM(id_base), get_strpath(self));
-
- n = 3;
-
- if (rb_block_given_p()) {
- return rb_block_call_kw(rb_cDir, id_glob, n, args, glob_i, self, RB_PASS_KEYWORDS);
- }
- else {
- VALUE ary;
- long i;
- ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_KEYWORDS);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_funcall(self, '+', 1, elt);
- rb_ary_store(ary, i, elt);
- }
- return ary;
- }
-}
-
-/*
- * Returns the current working directory as a Pathname.
- *
- * Pathname.getwd
- * #=> #<Pathname:/home/zzak/projects/ruby>
- *
- * See Dir.getwd.
- */
-static VALUE
-path_s_getwd(VALUE klass)
-{
- VALUE str;
- str = rb_funcall(rb_cDir, id_getwd, 0);
- return rb_class_new_instance(1, &str, klass);
-}
-
-/*
- * Return the entries (files and subdirectories) in the directory, each as a
- * Pathname object.
- *
- * The results contains just the names in the directory, without any trailing
- * slashes or recursive look-up.
- *
- * pp Pathname.new('/usr/local').entries
- * #=> [#<Pathname:share>,
- * # #<Pathname:lib>,
- * # #<Pathname:..>,
- * # #<Pathname:include>,
- * # #<Pathname:etc>,
- * # #<Pathname:bin>,
- * # #<Pathname:man>,
- * # #<Pathname:games>,
- * # #<Pathname:.>,
- * # #<Pathname:sbin>,
- * # #<Pathname:src>]
- *
- * The result may contain the current directory <code>#<Pathname:.></code> and
- * the parent directory <code>#<Pathname:..></code>.
- *
- * If you don't want +.+ and +..+ and
- * want directories, consider Pathname#children.
- */
-static VALUE
-path_entries(VALUE self)
-{
- VALUE klass, str, ary;
- long i;
- klass = rb_obj_class(self);
- str = get_strpath(self);
- ary = rb_funcall(rb_cDir, id_entries, 1, str);
- ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- VALUE elt = RARRAY_AREF(ary, i);
- elt = rb_class_new_instance(1, &elt, klass);
- rb_ary_store(ary, i, elt);
- }
- return ary;
-}
-
-/*
- * Create the referenced directory.
- *
- * See Dir.mkdir.
- */
-static VALUE
-path_mkdir(int argc, VALUE *argv, VALUE self)
-{
- VALUE str = get_strpath(self);
- VALUE vmode;
- if (rb_scan_args(argc, argv, "01", &vmode) == 0)
- return rb_funcall(rb_cDir, id_mkdir, 1, str);
- else
- return rb_funcall(rb_cDir, id_mkdir, 2, str, vmode);
-}
-
-/*
- * Remove the referenced directory.
- *
- * See Dir.rmdir.
- */
-static VALUE
-path_rmdir(VALUE self)
-{
- return rb_funcall(rb_cDir, id_rmdir, 1, get_strpath(self));
-}
-
-/*
- * Opens the referenced directory.
- *
- * See Dir.open.
- */
-static VALUE
-path_opendir(VALUE self)
-{
- VALUE args[1];
-
- args[0] = get_strpath(self);
- return rb_block_call(rb_cDir, id_open, 1, args, 0, 0);
-}
-
-static VALUE
-each_entry_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
-{
- return rb_yield(rb_class_new_instance(1, &elt, klass));
-}
-
-/*
- * Iterates over the entries (files and subdirectories) in the directory,
- * yielding a Pathname object for each entry.
- */
-static VALUE
-path_each_entry(VALUE self)
-{
- VALUE args[1];
- RETURN_ENUMERATOR(self, 0, 0);
-
- args[0] = get_strpath(self);
- return rb_block_call(rb_cDir, id_foreach, 1, args, each_entry_i, rb_obj_class(self));
-}
-
-static VALUE
-unlink_body(VALUE str)
-{
- return rb_funcall(rb_cDir, id_unlink, 1, str);
-}
-
-static VALUE
-unlink_rescue(VALUE str, VALUE errinfo)
-{
- return rb_funcall(rb_cFile, id_unlink, 1, str);
-}
-
-/*
- * Removes a file or directory, using File.unlink if +self+ is a file, or
- * Dir.unlink as necessary.
- */
-static VALUE
-path_unlink(VALUE self)
-{
- VALUE eENOTDIR = rb_const_get_at(rb_mErrno, id_ENOTDIR);
- VALUE str = get_strpath(self);
- return rb_rescue2(unlink_body, str, unlink_rescue, str, eENOTDIR, (VALUE)0);
-}
-
-/*
- * :call-seq:
- * Pathname(path) -> pathname
- *
- * Creates a new Pathname object from the given string, +path+, and returns
- * pathname object.
- *
- * In order to use this constructor, you must first require the Pathname
- * standard library extension.
- *
- * require 'pathname'
- * Pathname("/home/zzak")
- * #=> #<Pathname:/home/zzak>
- *
- * See also Pathname::new for more information.
- */
-static VALUE
-path_f_pathname(VALUE self, VALUE str)
-{
- if (CLASS_OF(str) == rb_cPathname)
- return str;
- return rb_class_new_instance(1, &str, rb_cPathname);
-}
-
-/*
- *
- * Pathname represents the name of a file or directory on the filesystem,
- * but not the file itself.
- *
- * The pathname depends on the Operating System: Unix, Windows, etc.
- * This library works with pathnames of local OS, however non-Unix pathnames
- * are supported experimentally.
- *
- * A Pathname can be relative or absolute. It's not until you try to
- * reference the file that it even matters whether the file exists or not.
- *
- * Pathname is immutable. It has no method for destructive update.
- *
- * The goal of this class is to manipulate file path information in a neater
- * way than standard Ruby provides. The examples below demonstrate the
- * difference.
- *
- * *All* functionality from File, FileTest, and some from Dir and FileUtils is
- * included, in an unsurprising way. It is essentially a facade for all of
- * these, and more.
- *
- * == Examples
- *
- * === Example 1: Using Pathname
- *
- * require 'pathname'
- * pn = Pathname.new("/usr/bin/ruby")
- * size = pn.size # 27662
- * isdir = pn.directory? # false
- * dir = pn.dirname # Pathname:/usr/bin
- * base = pn.basename # Pathname:ruby
- * dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby]
- * data = pn.read
- * pn.open { |f| _ }
- * pn.each_line { |line| _ }
- *
- * === Example 2: Using standard Ruby
- *
- * pn = "/usr/bin/ruby"
- * size = File.size(pn) # 27662
- * isdir = File.directory?(pn) # false
- * dir = File.dirname(pn) # "/usr/bin"
- * base = File.basename(pn) # "ruby"
- * dir, base = File.split(pn) # ["/usr/bin", "ruby"]
- * data = File.read(pn)
- * File.open(pn) { |f| _ }
- * File.foreach(pn) { |line| _ }
- *
- * === Example 3: Special features
- *
- * p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib
- * p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8
- * p3 = p1.parent # Pathname:/usr
- * p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8
- * pwd = Pathname.pwd # Pathname:/home/gavin
- * pwd.absolute? # true
- * p5 = Pathname.new "." # Pathname:.
- * p5 = p5 + "music/../articles" # Pathname:music/../articles
- * p5.cleanpath # Pathname:articles
- * p5.realpath # Pathname:/home/gavin/articles
- * p5.children # [Pathname:/home/gavin/articles/linux, ...]
- *
- * == Breakdown of functionality
- *
- * === Core methods
- *
- * These methods are effectively manipulating a String, because that's
- * all a path is. None of these access the file system except for
- * #mountpoint?, #children, #each_child, #realdirpath and #realpath.
- *
- * - +
- * - #join
- * - #parent
- * - #root?
- * - #absolute?
- * - #relative?
- * - #relative_path_from
- * - #each_filename
- * - #cleanpath
- * - #realpath
- * - #realdirpath
- * - #children
- * - #each_child
- * - #mountpoint?
- *
- * === File status predicate methods
- *
- * These methods are a facade for FileTest:
- * - #blockdev?
- * - #chardev?
- * - #directory?
- * - #executable?
- * - #executable_real?
- * - #exist?
- * - #file?
- * - #grpowned?
- * - #owned?
- * - #pipe?
- * - #readable?
- * - #world_readable?
- * - #readable_real?
- * - #setgid?
- * - #setuid?
- * - #size
- * - #size?
- * - #socket?
- * - #sticky?
- * - #symlink?
- * - #writable?
- * - #world_writable?
- * - #writable_real?
- * - #zero?
- *
- * === File property and manipulation methods
- *
- * These methods are a facade for File:
- * - #atime
- * - #birthtime
- * - #ctime
- * - #mtime
- * - #chmod(mode)
- * - #lchmod(mode)
- * - #chown(owner, group)
- * - #lchown(owner, group)
- * - #fnmatch(pattern, *args)
- * - #fnmatch?(pattern, *args)
- * - #ftype
- * - #make_link(old)
- * - #open(*args, &block)
- * - #readlink
- * - #rename(to)
- * - #stat
- * - #lstat
- * - #make_symlink(old)
- * - #truncate(length)
- * - #utime(atime, mtime)
- * - #lutime(atime, mtime)
- * - #basename(*args)
- * - #dirname
- * - #extname
- * - #expand_path(*args)
- * - #split
- *
- * === Directory methods
- *
- * These methods are a facade for Dir:
- * - Pathname.glob(*args)
- * - Pathname.getwd / Pathname.pwd
- * - #rmdir
- * - #entries
- * - #each_entry(&block)
- * - #mkdir(*args)
- * - #opendir(*args)
- *
- * === IO
- *
- * These methods are a facade for IO:
- * - #each_line(*args, &block)
- * - #read(*args)
- * - #binread(*args)
- * - #readlines(*args)
- * - #sysopen(*args)
- * - #write(*args)
- * - #binwrite(*args)
- *
- * === Utilities
- *
- * These methods are a mixture of Find, FileUtils, and others:
- * - #find(&block)
- * - #mkpath
- * - #rmtree
- * - #unlink / #delete
- *
- *
- * == Method documentation
- *
- * As the above section shows, most of the methods in Pathname are facades. The
- * documentation for these methods generally just says, for instance, "See
- * FileTest.writable?", as you should be familiar with the original method
- * anyway, and its documentation (e.g. through +ri+) will contain more
- * information. In some cases, a brief description will follow.
- */
-void
-Init_pathname(void)
-{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
-#endif
-
- InitVM(pathname);
-
- rb_cPathname = rb_define_class("Pathname", rb_cObject);
- rb_define_method(rb_cPathname, "initialize", path_initialize, 1);
- rb_define_method(rb_cPathname, "freeze", path_freeze, 0);
- rb_define_method(rb_cPathname, "==", path_eq, 1);
- rb_define_method(rb_cPathname, "===", path_eq, 1);
- rb_define_method(rb_cPathname, "eql?", path_eq, 1);
- rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
- rb_define_method(rb_cPathname, "hash", path_hash, 0);
- rb_define_method(rb_cPathname, "to_s", path_to_s, 0);
- rb_define_method(rb_cPathname, "to_path", path_to_s, 0);
- rb_define_method(rb_cPathname, "inspect", path_inspect, 0);
- rb_define_method(rb_cPathname, "sub", path_sub, -1);
- rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1);
- rb_define_method(rb_cPathname, "realpath", path_realpath, -1);
- rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1);
- rb_define_method(rb_cPathname, "each_line", path_each_line, -1);
- rb_define_method(rb_cPathname, "read", path_read, -1);
- rb_define_method(rb_cPathname, "binread", path_binread, -1);
- rb_define_method(rb_cPathname, "readlines", path_readlines, -1);
- rb_define_method(rb_cPathname, "write", path_write, -1);
- rb_define_method(rb_cPathname, "binwrite", path_binwrite, -1);
- rb_define_method(rb_cPathname, "sysopen", path_sysopen, -1);
- rb_define_method(rb_cPathname, "atime", path_atime, 0);
- rb_define_method(rb_cPathname, "birthtime", path_birthtime, 0);
- rb_define_method(rb_cPathname, "ctime", path_ctime, 0);
- rb_define_method(rb_cPathname, "mtime", path_mtime, 0);
- rb_define_method(rb_cPathname, "chmod", path_chmod, 1);
- rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1);
- rb_define_method(rb_cPathname, "chown", path_chown, 2);
- rb_define_method(rb_cPathname, "lchown", path_lchown, 2);
- rb_define_method(rb_cPathname, "fnmatch", path_fnmatch, -1);
- rb_define_method(rb_cPathname, "fnmatch?", path_fnmatch, -1);
- rb_define_method(rb_cPathname, "ftype", path_ftype, 0);
- rb_define_method(rb_cPathname, "make_link", path_make_link, 1);
- rb_define_method(rb_cPathname, "open", path_open, -1);
- rb_define_method(rb_cPathname, "readlink", path_readlink, 0);
- rb_define_method(rb_cPathname, "rename", path_rename, 1);
- rb_define_method(rb_cPathname, "stat", path_stat, 0);
- rb_define_method(rb_cPathname, "lstat", path_lstat, 0);
- rb_define_method(rb_cPathname, "make_symlink", path_make_symlink, 1);
- rb_define_method(rb_cPathname, "truncate", path_truncate, 1);
- rb_define_method(rb_cPathname, "utime", path_utime, 2);
- rb_define_method(rb_cPathname, "lutime", path_lutime, 2);
- rb_define_method(rb_cPathname, "basename", path_basename, -1);
- rb_define_method(rb_cPathname, "dirname", path_dirname, 0);
- rb_define_method(rb_cPathname, "extname", path_extname, 0);
- rb_define_method(rb_cPathname, "expand_path", path_expand_path, -1);
- rb_define_method(rb_cPathname, "split", path_split, 0);
- rb_define_method(rb_cPathname, "blockdev?", path_blockdev_p, 0);
- rb_define_method(rb_cPathname, "chardev?", path_chardev_p, 0);
- rb_define_method(rb_cPathname, "executable?", path_executable_p, 0);
- rb_define_method(rb_cPathname, "executable_real?", path_executable_real_p, 0);
- rb_define_method(rb_cPathname, "exist?", path_exist_p, 0);
- rb_define_method(rb_cPathname, "grpowned?", path_grpowned_p, 0);
- rb_define_method(rb_cPathname, "directory?", path_directory_p, 0);
- rb_define_method(rb_cPathname, "file?", path_file_p, 0);
- rb_define_method(rb_cPathname, "pipe?", path_pipe_p, 0);
- rb_define_method(rb_cPathname, "socket?", path_socket_p, 0);
- rb_define_method(rb_cPathname, "owned?", path_owned_p, 0);
- rb_define_method(rb_cPathname, "readable?", path_readable_p, 0);
- rb_define_method(rb_cPathname, "world_readable?", path_world_readable_p, 0);
- rb_define_method(rb_cPathname, "readable_real?", path_readable_real_p, 0);
- rb_define_method(rb_cPathname, "setuid?", path_setuid_p, 0);
- rb_define_method(rb_cPathname, "setgid?", path_setgid_p, 0);
- rb_define_method(rb_cPathname, "size", path_size, 0);
- rb_define_method(rb_cPathname, "size?", path_size_p, 0);
- rb_define_method(rb_cPathname, "sticky?", path_sticky_p, 0);
- rb_define_method(rb_cPathname, "symlink?", path_symlink_p, 0);
- rb_define_method(rb_cPathname, "writable?", path_writable_p, 0);
- rb_define_method(rb_cPathname, "world_writable?", path_world_writable_p, 0);
- rb_define_method(rb_cPathname, "writable_real?", path_writable_real_p, 0);
- rb_define_method(rb_cPathname, "zero?", path_zero_p, 0);
- rb_define_method(rb_cPathname, "empty?", path_empty_p, 0);
- rb_define_singleton_method(rb_cPathname, "glob", path_s_glob, -1);
- rb_define_singleton_method(rb_cPathname, "getwd", path_s_getwd, 0);
- rb_define_singleton_method(rb_cPathname, "pwd", path_s_getwd, 0);
- rb_define_method(rb_cPathname, "glob", path_glob, -1);
- rb_define_method(rb_cPathname, "entries", path_entries, 0);
- rb_define_method(rb_cPathname, "mkdir", path_mkdir, -1);
- rb_define_method(rb_cPathname, "rmdir", path_rmdir, 0);
- rb_define_method(rb_cPathname, "opendir", path_opendir, 0);
- rb_define_method(rb_cPathname, "each_entry", path_each_entry, 0);
- rb_define_method(rb_cPathname, "unlink", path_unlink, 0);
- rb_define_method(rb_cPathname, "delete", path_unlink, 0);
- rb_undef_method(rb_cPathname, "=~");
- rb_define_global_function("Pathname", path_f_pathname, 1);
-}
-
-void
-InitVM_pathname(void)
-{
-#undef rb_intern
- id_at_path = rb_intern("@path");
- id_to_path = rb_intern("to_path");
- id_ENOTDIR = rb_intern("ENOTDIR");
- id_atime = rb_intern("atime");
- id_basename = rb_intern("basename");
- id_base = rb_intern("base");
- id_binread = rb_intern("binread");
- id_binwrite = rb_intern("binwrite");
- id_birthtime = rb_intern("birthtime");
- id_blockdev_p = rb_intern("blockdev?");
- id_chardev_p = rb_intern("chardev?");
- id_chmod = rb_intern("chmod");
- id_chown = rb_intern("chown");
- id_ctime = rb_intern("ctime");
- id_directory_p = rb_intern("directory?");
- id_dirname = rb_intern("dirname");
- id_empty_p = rb_intern("empty?");
- id_entries = rb_intern("entries");
- id_executable_p = rb_intern("executable?");
- id_executable_real_p = rb_intern("executable_real?");
- id_exist_p = rb_intern("exist?");
- id_expand_path = rb_intern("expand_path");
- id_extname = rb_intern("extname");
- id_file_p = rb_intern("file?");
- id_fnmatch = rb_intern("fnmatch");
- id_foreach = rb_intern("foreach");
- id_ftype = rb_intern("ftype");
- id_getwd = rb_intern("getwd");
- id_glob = rb_intern("glob");
- id_grpowned_p = rb_intern("grpowned?");
- id_lchmod = rb_intern("lchmod");
- id_lchown = rb_intern("lchown");
- id_link = rb_intern("link");
- id_lstat = rb_intern("lstat");
- id_lutime = rb_intern("lutime");
- id_mkdir = rb_intern("mkdir");
- id_mtime = rb_intern("mtime");
- id_open = rb_intern("open");
- id_owned_p = rb_intern("owned?");
- id_pipe_p = rb_intern("pipe?");
- id_read = rb_intern("read");
- id_readable_p = rb_intern("readable?");
- id_readable_real_p = rb_intern("readable_real?");
- id_readlines = rb_intern("readlines");
- id_readlink = rb_intern("readlink");
- id_realdirpath = rb_intern("realdirpath");
- id_realpath = rb_intern("realpath");
- id_rename = rb_intern("rename");
- id_rmdir = rb_intern("rmdir");
- id_setgid_p = rb_intern("setgid?");
- id_setuid_p = rb_intern("setuid?");
- id_size = rb_intern("size");
- id_size_p = rb_intern("size?");
- id_socket_p = rb_intern("socket?");
- id_split = rb_intern("split");
- id_stat = rb_intern("stat");
- id_sticky_p = rb_intern("sticky?");
- id_sub = rb_intern("sub");
- id_symlink = rb_intern("symlink");
- id_symlink_p = rb_intern("symlink?");
- id_sysopen = rb_intern("sysopen");
- id_truncate = rb_intern("truncate");
- id_unlink = rb_intern("unlink");
- id_utime = rb_intern("utime");
- id_world_readable_p = rb_intern("world_readable?");
- id_world_writable_p = rb_intern("world_writable?");
- id_writable_p = rb_intern("writable?");
- id_writable_real_p = rb_intern("writable_real?");
- id_write = rb_intern("write");
- id_zero_p = rb_intern("zero?");
-}
diff --git a/ext/pathname/pathname.gemspec b/ext/pathname/pathname.gemspec
deleted file mode 100644
index 890bc2fde9..0000000000
--- a/ext/pathname/pathname.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", "ext/lib"].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Tanaka Akira"]
- spec.email = ["akr@fsij.org"]
-
- spec.summary = %q{Representation of the name of a file or directory on the filesystem}
- spec.description = %q{Representation of the name of a file or directory on the filesystem}
- spec.homepage = "https://github.com/ruby/pathname"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = []
- spec.require_paths = ["lib"]
- spec.extensions = %w[ext/pathname/extconf.rb]
-end
diff --git a/ext/psych/depend b/ext/psych/depend
index a4d9ca9a6a..95175841a2 100644
--- a/ext/psych/depend
+++ b/ext/psych/depend
@@ -152,6 +152,7 @@ psych.o: $(hdrdir)/ruby/internal/intern/re.h
psych.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych.o: $(hdrdir)/ruby/internal/intern/select.h
psych.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych.o: $(hdrdir)/ruby/internal/intern/set.h
psych.o: $(hdrdir)/ruby/internal/intern/signal.h
psych.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -329,6 +330,7 @@ psych_emitter.o: $(hdrdir)/ruby/internal/intern/re.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/select.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_emitter.o: $(hdrdir)/ruby/internal/intern/set.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -506,6 +508,7 @@ psych_parser.o: $(hdrdir)/ruby/internal/intern/re.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/select.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_parser.o: $(hdrdir)/ruby/internal/intern/set.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -683,6 +686,7 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/re.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/set.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -860,6 +864,7 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/re.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/ruby.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/set.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/signal.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/sprintf.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/psych/extconf.rb b/ext/psych/extconf.rb
index e7dd0bb60a..589e201c1c 100644
--- a/ext/psych/extconf.rb
+++ b/ext/psych/extconf.rb
@@ -36,8 +36,11 @@ if yaml_source
libyaml = "libyaml.#$LIBEXT"
$cleanfiles << libyaml
$LOCAL_LIBS.prepend("$(LIBYAML) ")
-else # default to pre-installed libyaml
- pkg_config('yaml-0.1')
+
+ # default to pre-installed libyaml
+elsif pkg_config('yaml-0.1')
+ # found with pkg-config
+else
dir_config('libyaml')
find_header('yaml.h') or abort "yaml.h not found"
find_library('yaml', 'yaml_get_version') or abort "libyaml not found"
diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb
index a95393c281..850a6d1937 100644
--- a/ext/psych/lib/psych.rb
+++ b/ext/psych/lib/psych.rb
@@ -23,7 +23,6 @@ require_relative 'psych/parser'
require_relative 'psych/omap'
require_relative 'psych/set'
require_relative 'psych/coder'
-require_relative 'psych/core_ext'
require_relative 'psych/stream'
require_relative 'psych/json/tree_builder'
require_relative 'psych/json/stream'
@@ -270,10 +269,10 @@ module Psych
# YAML documents that are supplied via user input. Instead, please use the
# load method or the safe_load method.
#
- def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false
+ def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
result = parse(yaml, filename: filename)
return fallback unless result
- result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer)
+ result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols)
end
###
@@ -321,13 +320,13 @@ module Psych
# Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"}
# Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
#
- def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
+ def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
result = parse(yaml, filename: filename)
return fallback unless result
class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s),
permitted_symbols.map(&:to_s))
- scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols
visitor = if aliases
Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
else
@@ -367,7 +366,7 @@ module Psych
# Raises a TypeError when `yaml` parameter is NilClass. This method is
# similar to `safe_load` except that `Symbol` objects are allowed by default.
#
- def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false
+ def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true
safe_load yaml, permitted_classes: permitted_classes,
permitted_symbols: permitted_symbols,
aliases: aliases,
@@ -375,7 +374,8 @@ module Psych
fallback: fallback,
symbolize_names: symbolize_names,
freeze: freeze,
- strict_integer: strict_integer
+ strict_integer: strict_integer,
+ parse_symbols: parse_symbols
end
###
@@ -655,6 +655,35 @@ module Psych
end
###
+ # Load multiple documents given in +yaml+. Returns the parsed documents
+ # as a list.
+ #
+ # Example:
+ #
+ # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']
+ #
+ # list = []
+ # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") do |ruby|
+ # list << ruby
+ # end
+ # list # => ['foo', 'bar']
+ #
+ def self.safe_load_stream yaml, filename: nil, permitted_classes: [], aliases: false
+ documents = parse_stream(yaml, filename: filename).children.map do |child|
+ stream = Psych::Nodes::Stream.new
+ stream.children << child
+ safe_load(stream.to_yaml, permitted_classes: permitted_classes, aliases: aliases)
+ end
+
+ if block_given?
+ documents.each { |doc| yield doc }
+ nil
+ else
+ documents
+ end
+ end
+
+ ###
# Load the document contained in +filename+. Returns the yaml contained in
# +filename+ as a Ruby object, or if the file is empty, it returns
# the specified +fallback+ return value, which defaults to +false+.
@@ -761,3 +790,5 @@ module Psych
self.domain_types = {}
# :startdoc:
end
+
+require_relative 'psych/core_ext'
diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb
index 50efc35ee2..c8f509720a 100644
--- a/ext/psych/lib/psych/class_loader.rb
+++ b/ext/psych/lib/psych/class_loader.rb
@@ -6,6 +6,7 @@ module Psych
class ClassLoader # :nodoc:
BIG_DECIMAL = 'BigDecimal'
COMPLEX = 'Complex'
+ DATA = 'Data' unless RUBY_VERSION < "3.2"
DATE = 'Date'
DATE_TIME = 'DateTime'
EXCEPTION = 'Exception'
diff --git a/ext/psych/lib/psych/core_ext.rb b/ext/psych/lib/psych/core_ext.rb
index 0721a133c3..6dfd0f1696 100644
--- a/ext/psych/lib/psych/core_ext.rb
+++ b/ext/psych/lib/psych/core_ext.rb
@@ -14,6 +14,23 @@ class Object
end
end
-if defined?(::IRB)
- require_relative 'y'
+# Up to Ruby 3.4, Set was a regular object and was dumped as such
+# by Pysch.
+# Starting from Ruby 4.0 it's a core class written in C, so we have to implement
+# #encode_with / #init_with to preserve backward compatibility.
+if defined?(::Set) && Set.new.instance_variables.empty?
+ class Set
+ def encode_with(coder)
+ hash = {}
+ each do |m|
+ hash[m] = true
+ end
+ coder["hash"] = hash
+ coder
+ end
+
+ def init_with(coder)
+ replace(coder["hash"].keys)
+ end
+ end
end
diff --git a/ext/psych/lib/psych/nodes/node.rb b/ext/psych/lib/psych/nodes/node.rb
index 6ae5c59148..fc27448f2e 100644
--- a/ext/psych/lib/psych/nodes/node.rb
+++ b/ext/psych/lib/psych/nodes/node.rb
@@ -45,8 +45,8 @@ module Psych
# Convert this node to Ruby.
#
# See also Psych::Visitors::ToRuby
- def to_ruby(symbolize_names: false, freeze: false, strict_integer: false)
- Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer).accept(self)
+ def to_ruby(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true)
+ Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols).accept(self)
end
alias :transform :to_ruby
diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb
index 8cf868f863..6a556fb3b8 100644
--- a/ext/psych/lib/psych/scalar_scanner.rb
+++ b/ext/psych/lib/psych/scalar_scanner.rb
@@ -27,10 +27,11 @@ module Psych
attr_reader :class_loader
# Create a new scanner
- def initialize class_loader, strict_integer: false
+ def initialize class_loader, strict_integer: false, parse_symbols: true
@symbol_cache = {}
@class_loader = class_loader
@strict_integer = strict_integer
+ @parse_symbols = parse_symbols
end
# Tokenize +string+ returning the Ruby object
@@ -72,7 +73,7 @@ module Psych
-Float::INFINITY
elsif string.match?(/^\.nan$/i)
Float::NAN
- elsif string.match?(/^:./)
+ elsif @parse_symbols && string.match?(/^:./)
if string =~ /^:(["'])(.*)\1/
@symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, ''))
else
diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb
index d91563c861..4c7a80d5c8 100644
--- a/ext/psych/lib/psych/versions.rb
+++ b/ext/psych/lib/psych/versions.rb
@@ -2,9 +2,9 @@
module Psych
# The version of Psych you are using
- VERSION = '5.2.3'
+ VERSION = '5.3.1'
if RUBY_ENGINE == 'jruby'
- DEFAULT_SNAKEYAML_VERSION = '2.9'.freeze
+ DEFAULT_SNAKEYAML_VERSION = '2.10'.freeze
end
end
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index f0b4a94e45..475444e589 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -12,9 +12,13 @@ module Psych
###
# This class walks a YAML AST, converting each node to Ruby
class ToRuby < Psych::Visitors::Visitor
- def self.create(symbolize_names: false, freeze: false, strict_integer: false)
+ unless RUBY_VERSION < "3.2"
+ DATA_INITIALIZE = Data.instance_method(:initialize)
+ end
+
+ def self.create(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true)
class_loader = ClassLoader.new
- scanner = ScalarScanner.new class_loader, strict_integer: strict_integer
+ scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols
new(scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze)
end
@@ -96,11 +100,11 @@ module Psych
Float(@ss.tokenize(o.value))
when "!ruby/regexp"
klass = class_loader.regexp
- o.value =~ /^\/(.*)\/([mixn]*)$/m
- source = $1
+ matches = /^\/(?<string>.*)\/(?<options>[mixn]*)$/m.match(o.value)
+ source = matches[:string].gsub('\/', '/')
options = 0
lang = nil
- $2&.each_char do |option|
+ matches[:options].each_char do |option|
case option
when 'x' then options |= Regexp::EXTENDED
when 'i' then options |= Regexp::IGNORECASE
@@ -197,6 +201,32 @@ module Psych
s
end
+ when /^!ruby\/data(-with-ivars)?(?::(.*))?$/
+ data = register(o, resolve_class($2).allocate) if $2
+ members = {}
+
+ if $1 # data-with-ivars
+ ivars = {}
+ o.children.each_slice(2) do |type, vars|
+ case accept(type)
+ when 'members'
+ revive_data_members(members, vars)
+ data ||= allocate_anon_data(o, members)
+ when 'ivars'
+ revive_hash(ivars, vars)
+ end
+ end
+ ivars.each do |ivar, v|
+ data.instance_variable_set ivar, v
+ end
+ else
+ revive_data_members(members, o)
+ end
+ data ||= allocate_anon_data(o, members)
+ DATA_INITIALIZE.bind_call(data, **members)
+ data.freeze
+ data
+
when /^!ruby\/object:?(.*)?$/
name = $1 || 'Object'
@@ -340,6 +370,20 @@ module Psych
list
end
+ def allocate_anon_data node, members
+ klass = class_loader.data.define(*members.keys)
+ register(node, klass.allocate)
+ end
+
+ def revive_data_members hash, o
+ o.children.each_slice(2) do |k,v|
+ name = accept(k)
+ value = accept(v)
+ hash[class_loader.symbolize(name)] = value
+ end
+ hash
+ end
+
def revive_hash hash, o, tagged= false
o.children.each_slice(2) { |k,v|
key = accept(k)
diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb
index a9476df96e..b6c86f4c94 100644
--- a/ext/psych/lib/psych/visitors/yaml_tree.rb
+++ b/ext/psych/lib/psych/visitors/yaml_tree.rb
@@ -73,7 +73,7 @@ module Psych
method = respond_to?(method) ? method : h[klass.superclass]
- raise(TypeError, "Can't dump #{target.class}") unless method
+ raise(TypeError, "can't dump #{klass.name}") unless method
h[klass] = method
end.compare_by_identity
@@ -162,6 +162,44 @@ module Psych
alias :visit_Delegator :visit_Object
+ def visit_Data o
+ ivars = o.instance_variables
+ if ivars.empty?
+ tag = ['!ruby/data', o.class.name].compact.join(':')
+ register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
+ o.members.each do |member|
+ @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
+ accept o.send member
+ end
+ @emitter.end_mapping
+
+ else
+ tag = ['!ruby/data-with-ivars', o.class.name].compact.join(':')
+ node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
+ register(o, node)
+
+ # Dump the members
+ accept 'members'
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ o.members.each do |member|
+ @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
+ accept o.send member
+ end
+ @emitter.end_mapping
+
+ # Dump the ivars
+ accept 'ivars'
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ ivars.each do |ivar|
+ accept ivar.to_s
+ accept o.instance_variable_get ivar
+ end
+ @emitter.end_mapping
+
+ @emitter.end_mapping
+ end
+ end unless RUBY_VERSION < "3.2"
+
def visit_Struct o
tag = ['!ruby/struct', o.class.name].compact.join(':')
diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c
index ffe0c69c7f..3ab0138b52 100644
--- a/ext/psych/psych_to_ruby.c
+++ b/ext/psych/psych_to_ruby.c
@@ -10,7 +10,11 @@ static VALUE build_exception(VALUE self, VALUE klass, VALUE mesg)
{
VALUE e = rb_obj_alloc(klass);
+#ifdef TRUFFLERUBY
+ rb_exc_set_message(e, mesg);
+#else
rb_iv_set(e, "mesg", mesg);
+#endif
return e;
}
diff --git a/ext/pty/depend b/ext/pty/depend
index adecfff862..8fa018d084 100644
--- a/ext/pty/depend
+++ b/ext/pty/depend
@@ -138,6 +138,7 @@ pty.o: $(hdrdir)/ruby/internal/intern/re.h
pty.o: $(hdrdir)/ruby/internal/intern/ruby.h
pty.o: $(hdrdir)/ruby/internal/intern/select.h
pty.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+pty.o: $(hdrdir)/ruby/internal/intern/set.h
pty.o: $(hdrdir)/ruby/internal/intern/signal.h
pty.o: $(hdrdir)/ruby/internal/intern/sprintf.h
pty.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -172,6 +173,7 @@ pty.o: $(hdrdir)/ruby/ruby.h
pty.o: $(hdrdir)/ruby/st.h
pty.o: $(hdrdir)/ruby/subst.h
pty.o: $(hdrdir)/ruby/util.h
+pty.o: $(top_srcdir)/id_table.h
pty.o: $(top_srcdir)/internal.h
pty.o: $(top_srcdir)/internal/array.h
pty.o: $(top_srcdir)/internal/compilers.h
diff --git a/ext/rbconfig/sizeof/depend b/ext/rbconfig/sizeof/depend
index 5f75fa8c76..7e6c950769 100644
--- a/ext/rbconfig/sizeof/depend
+++ b/ext/rbconfig/sizeof/depend
@@ -142,6 +142,7 @@ limits.o: $(hdrdir)/ruby/internal/intern/re.h
limits.o: $(hdrdir)/ruby/internal/intern/ruby.h
limits.o: $(hdrdir)/ruby/internal/intern/select.h
limits.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+limits.o: $(hdrdir)/ruby/internal/intern/set.h
limits.o: $(hdrdir)/ruby/internal/intern/signal.h
limits.o: $(hdrdir)/ruby/internal/intern/sprintf.h
limits.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -301,6 +302,7 @@ sizes.o: $(hdrdir)/ruby/internal/intern/re.h
sizes.o: $(hdrdir)/ruby/internal/intern/ruby.h
sizes.o: $(hdrdir)/ruby/internal/intern/select.h
sizes.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sizes.o: $(hdrdir)/ruby/internal/intern/set.h
sizes.o: $(hdrdir)/ruby/internal/intern/signal.h
sizes.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sizes.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/ripper/depend b/ext/ripper/depend
index 9cca2d315e..944da25ee9 100644
--- a/ext/ripper/depend
+++ b/ext/ripper/depend
@@ -181,6 +181,7 @@ eventids1.o: $(hdrdir)/ruby/internal/intern/re.h
eventids1.o: $(hdrdir)/ruby/internal/intern/ruby.h
eventids1.o: $(hdrdir)/ruby/internal/intern/select.h
eventids1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+eventids1.o: $(hdrdir)/ruby/internal/intern/set.h
eventids1.o: $(hdrdir)/ruby/internal/intern/signal.h
eventids1.o: $(hdrdir)/ruby/internal/intern/sprintf.h
eventids1.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -352,6 +353,7 @@ eventids2.o: $(hdrdir)/ruby/internal/intern/re.h
eventids2.o: $(hdrdir)/ruby/internal/intern/ruby.h
eventids2.o: $(hdrdir)/ruby/internal/intern/select.h
eventids2.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+eventids2.o: $(hdrdir)/ruby/internal/intern/set.h
eventids2.o: $(hdrdir)/ruby/internal/intern/signal.h
eventids2.o: $(hdrdir)/ruby/internal/intern/sprintf.h
eventids2.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -532,6 +534,7 @@ ripper.o: $(hdrdir)/ruby/internal/intern/re.h
ripper.o: $(hdrdir)/ruby/internal/intern/ruby.h
ripper.o: $(hdrdir)/ruby/internal/intern/select.h
ripper.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ripper.o: $(hdrdir)/ruby/internal/intern/set.h
ripper.o: $(hdrdir)/ruby/internal/intern/signal.h
ripper.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ripper.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -575,12 +578,14 @@ ripper.o: $(top_srcdir)/ccan/container_of/container_of.h
ripper.o: $(top_srcdir)/ccan/list/list.h
ripper.o: $(top_srcdir)/ccan/str/str.h
ripper.o: $(top_srcdir)/constant.h
+ripper.o: $(top_srcdir)/encindex.h
ripper.o: $(top_srcdir)/id_table.h
ripper.o: $(top_srcdir)/internal.h
ripper.o: $(top_srcdir)/internal/array.h
ripper.o: $(top_srcdir)/internal/basic_operators.h
ripper.o: $(top_srcdir)/internal/bignum.h
ripper.o: $(top_srcdir)/internal/bits.h
+ripper.o: $(top_srcdir)/internal/box.h
ripper.o: $(top_srcdir)/internal/compile.h
ripper.o: $(top_srcdir)/internal/compilers.h
ripper.o: $(top_srcdir)/internal/complex.h
@@ -598,8 +603,10 @@ ripper.o: $(top_srcdir)/internal/re.h
ripper.o: $(top_srcdir)/internal/ruby_parser.h
ripper.o: $(top_srcdir)/internal/sanitizers.h
ripper.o: $(top_srcdir)/internal/serial.h
+ripper.o: $(top_srcdir)/internal/set_table.h
ripper.o: $(top_srcdir)/internal/static_assert.h
ripper.o: $(top_srcdir)/internal/string.h
+ripper.o: $(top_srcdir)/internal/struct.h
ripper.o: $(top_srcdir)/internal/symbol.h
ripper.o: $(top_srcdir)/internal/thread.h
ripper.o: $(top_srcdir)/internal/variable.h
@@ -770,6 +777,7 @@ ripper_init.o: $(hdrdir)/ruby/internal/intern/re.h
ripper_init.o: $(hdrdir)/ruby/internal/intern/ruby.h
ripper_init.o: $(hdrdir)/ruby/internal/intern/select.h
ripper_init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ripper_init.o: $(hdrdir)/ruby/internal/intern/set.h
ripper_init.o: $(hdrdir)/ruby/internal/intern/signal.h
ripper_init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ripper_init.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/ripper/lib/ripper/lexer.rb b/ext/ripper/lib/ripper/lexer.rb
index 870c79857b..9b849dfeae 100644
--- a/ext/ripper/lib/ripper/lexer.rb
+++ b/ext/ripper/lib/ripper/lexer.rb
@@ -68,7 +68,7 @@ class Ripper
when 0, :to_int
@to_int
when 1, :to_s
- @event
+ @to_s
else
nil
end
diff --git a/ext/socket/depend b/ext/socket/depend
index 750bb0734f..77f6239a3d 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -151,6 +151,7 @@ ancdata.o: $(hdrdir)/ruby/internal/intern/re.h
ancdata.o: $(hdrdir)/ruby/internal/intern/ruby.h
ancdata.o: $(hdrdir)/ruby/internal/intern/select.h
ancdata.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/set.h
ancdata.o: $(hdrdir)/ruby/internal/intern/signal.h
ancdata.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ancdata.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -192,9 +193,12 @@ ancdata.o: $(top_srcdir)/ccan/check_type/check_type.h
ancdata.o: $(top_srcdir)/ccan/container_of/container_of.h
ancdata.o: $(top_srcdir)/ccan/list/list.h
ancdata.o: $(top_srcdir)/ccan/str/str.h
+ancdata.o: $(top_srcdir)/encindex.h
+ancdata.o: $(top_srcdir)/id_table.h
ancdata.o: $(top_srcdir)/internal.h
ancdata.o: $(top_srcdir)/internal/array.h
ancdata.o: $(top_srcdir)/internal/basic_operators.h
+ancdata.o: $(top_srcdir)/internal/box.h
ancdata.o: $(top_srcdir)/internal/compilers.h
ancdata.o: $(top_srcdir)/internal/error.h
ancdata.o: $(top_srcdir)/internal/gc.h
@@ -202,6 +206,7 @@ ancdata.o: $(top_srcdir)/internal/imemo.h
ancdata.o: $(top_srcdir)/internal/io.h
ancdata.o: $(top_srcdir)/internal/sanitizers.h
ancdata.o: $(top_srcdir)/internal/serial.h
+ancdata.o: $(top_srcdir)/internal/set_table.h
ancdata.o: $(top_srcdir)/internal/static_assert.h
ancdata.o: $(top_srcdir)/internal/string.h
ancdata.o: $(top_srcdir)/internal/thread.h
@@ -362,6 +367,7 @@ basicsocket.o: $(hdrdir)/ruby/internal/intern/re.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/select.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/set.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -403,9 +409,12 @@ basicsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
basicsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
basicsocket.o: $(top_srcdir)/ccan/list/list.h
basicsocket.o: $(top_srcdir)/ccan/str/str.h
+basicsocket.o: $(top_srcdir)/encindex.h
+basicsocket.o: $(top_srcdir)/id_table.h
basicsocket.o: $(top_srcdir)/internal.h
basicsocket.o: $(top_srcdir)/internal/array.h
basicsocket.o: $(top_srcdir)/internal/basic_operators.h
+basicsocket.o: $(top_srcdir)/internal/box.h
basicsocket.o: $(top_srcdir)/internal/compilers.h
basicsocket.o: $(top_srcdir)/internal/error.h
basicsocket.o: $(top_srcdir)/internal/gc.h
@@ -413,6 +422,7 @@ basicsocket.o: $(top_srcdir)/internal/imemo.h
basicsocket.o: $(top_srcdir)/internal/io.h
basicsocket.o: $(top_srcdir)/internal/sanitizers.h
basicsocket.o: $(top_srcdir)/internal/serial.h
+basicsocket.o: $(top_srcdir)/internal/set_table.h
basicsocket.o: $(top_srcdir)/internal/static_assert.h
basicsocket.o: $(top_srcdir)/internal/string.h
basicsocket.o: $(top_srcdir)/internal/thread.h
@@ -573,6 +583,7 @@ constants.o: $(hdrdir)/ruby/internal/intern/re.h
constants.o: $(hdrdir)/ruby/internal/intern/ruby.h
constants.o: $(hdrdir)/ruby/internal/intern/select.h
constants.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+constants.o: $(hdrdir)/ruby/internal/intern/set.h
constants.o: $(hdrdir)/ruby/internal/intern/signal.h
constants.o: $(hdrdir)/ruby/internal/intern/sprintf.h
constants.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -614,9 +625,12 @@ constants.o: $(top_srcdir)/ccan/check_type/check_type.h
constants.o: $(top_srcdir)/ccan/container_of/container_of.h
constants.o: $(top_srcdir)/ccan/list/list.h
constants.o: $(top_srcdir)/ccan/str/str.h
+constants.o: $(top_srcdir)/encindex.h
+constants.o: $(top_srcdir)/id_table.h
constants.o: $(top_srcdir)/internal.h
constants.o: $(top_srcdir)/internal/array.h
constants.o: $(top_srcdir)/internal/basic_operators.h
+constants.o: $(top_srcdir)/internal/box.h
constants.o: $(top_srcdir)/internal/compilers.h
constants.o: $(top_srcdir)/internal/error.h
constants.o: $(top_srcdir)/internal/gc.h
@@ -624,6 +638,7 @@ constants.o: $(top_srcdir)/internal/imemo.h
constants.o: $(top_srcdir)/internal/io.h
constants.o: $(top_srcdir)/internal/sanitizers.h
constants.o: $(top_srcdir)/internal/serial.h
+constants.o: $(top_srcdir)/internal/set_table.h
constants.o: $(top_srcdir)/internal/static_assert.h
constants.o: $(top_srcdir)/internal/string.h
constants.o: $(top_srcdir)/internal/thread.h
@@ -785,6 +800,7 @@ ifaddr.o: $(hdrdir)/ruby/internal/intern/re.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/ruby.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/select.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/set.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/signal.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -826,9 +842,12 @@ ifaddr.o: $(top_srcdir)/ccan/check_type/check_type.h
ifaddr.o: $(top_srcdir)/ccan/container_of/container_of.h
ifaddr.o: $(top_srcdir)/ccan/list/list.h
ifaddr.o: $(top_srcdir)/ccan/str/str.h
+ifaddr.o: $(top_srcdir)/encindex.h
+ifaddr.o: $(top_srcdir)/id_table.h
ifaddr.o: $(top_srcdir)/internal.h
ifaddr.o: $(top_srcdir)/internal/array.h
ifaddr.o: $(top_srcdir)/internal/basic_operators.h
+ifaddr.o: $(top_srcdir)/internal/box.h
ifaddr.o: $(top_srcdir)/internal/compilers.h
ifaddr.o: $(top_srcdir)/internal/error.h
ifaddr.o: $(top_srcdir)/internal/gc.h
@@ -836,6 +855,7 @@ ifaddr.o: $(top_srcdir)/internal/imemo.h
ifaddr.o: $(top_srcdir)/internal/io.h
ifaddr.o: $(top_srcdir)/internal/sanitizers.h
ifaddr.o: $(top_srcdir)/internal/serial.h
+ifaddr.o: $(top_srcdir)/internal/set_table.h
ifaddr.o: $(top_srcdir)/internal/static_assert.h
ifaddr.o: $(top_srcdir)/internal/string.h
ifaddr.o: $(top_srcdir)/internal/thread.h
@@ -996,6 +1016,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1037,9 +1058,12 @@ init.o: $(top_srcdir)/ccan/check_type/check_type.h
init.o: $(top_srcdir)/ccan/container_of/container_of.h
init.o: $(top_srcdir)/ccan/list/list.h
init.o: $(top_srcdir)/ccan/str/str.h
+init.o: $(top_srcdir)/encindex.h
+init.o: $(top_srcdir)/id_table.h
init.o: $(top_srcdir)/internal.h
init.o: $(top_srcdir)/internal/array.h
init.o: $(top_srcdir)/internal/basic_operators.h
+init.o: $(top_srcdir)/internal/box.h
init.o: $(top_srcdir)/internal/compilers.h
init.o: $(top_srcdir)/internal/error.h
init.o: $(top_srcdir)/internal/gc.h
@@ -1047,6 +1071,7 @@ init.o: $(top_srcdir)/internal/imemo.h
init.o: $(top_srcdir)/internal/io.h
init.o: $(top_srcdir)/internal/sanitizers.h
init.o: $(top_srcdir)/internal/serial.h
+init.o: $(top_srcdir)/internal/set_table.h
init.o: $(top_srcdir)/internal/static_assert.h
init.o: $(top_srcdir)/internal/string.h
init.o: $(top_srcdir)/internal/thread.h
@@ -1207,6 +1232,7 @@ ipsocket.o: $(hdrdir)/ruby/internal/intern/re.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/select.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/set.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1248,9 +1274,12 @@ ipsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
ipsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
ipsocket.o: $(top_srcdir)/ccan/list/list.h
ipsocket.o: $(top_srcdir)/ccan/str/str.h
+ipsocket.o: $(top_srcdir)/encindex.h
+ipsocket.o: $(top_srcdir)/id_table.h
ipsocket.o: $(top_srcdir)/internal.h
ipsocket.o: $(top_srcdir)/internal/array.h
ipsocket.o: $(top_srcdir)/internal/basic_operators.h
+ipsocket.o: $(top_srcdir)/internal/box.h
ipsocket.o: $(top_srcdir)/internal/compilers.h
ipsocket.o: $(top_srcdir)/internal/error.h
ipsocket.o: $(top_srcdir)/internal/gc.h
@@ -1258,6 +1287,7 @@ ipsocket.o: $(top_srcdir)/internal/imemo.h
ipsocket.o: $(top_srcdir)/internal/io.h
ipsocket.o: $(top_srcdir)/internal/sanitizers.h
ipsocket.o: $(top_srcdir)/internal/serial.h
+ipsocket.o: $(top_srcdir)/internal/set_table.h
ipsocket.o: $(top_srcdir)/internal/static_assert.h
ipsocket.o: $(top_srcdir)/internal/string.h
ipsocket.o: $(top_srcdir)/internal/thread.h
@@ -1418,6 +1448,7 @@ option.o: $(hdrdir)/ruby/internal/intern/re.h
option.o: $(hdrdir)/ruby/internal/intern/ruby.h
option.o: $(hdrdir)/ruby/internal/intern/select.h
option.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+option.o: $(hdrdir)/ruby/internal/intern/set.h
option.o: $(hdrdir)/ruby/internal/intern/signal.h
option.o: $(hdrdir)/ruby/internal/intern/sprintf.h
option.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1459,9 +1490,12 @@ option.o: $(top_srcdir)/ccan/check_type/check_type.h
option.o: $(top_srcdir)/ccan/container_of/container_of.h
option.o: $(top_srcdir)/ccan/list/list.h
option.o: $(top_srcdir)/ccan/str/str.h
+option.o: $(top_srcdir)/encindex.h
+option.o: $(top_srcdir)/id_table.h
option.o: $(top_srcdir)/internal.h
option.o: $(top_srcdir)/internal/array.h
option.o: $(top_srcdir)/internal/basic_operators.h
+option.o: $(top_srcdir)/internal/box.h
option.o: $(top_srcdir)/internal/compilers.h
option.o: $(top_srcdir)/internal/error.h
option.o: $(top_srcdir)/internal/gc.h
@@ -1469,6 +1503,7 @@ option.o: $(top_srcdir)/internal/imemo.h
option.o: $(top_srcdir)/internal/io.h
option.o: $(top_srcdir)/internal/sanitizers.h
option.o: $(top_srcdir)/internal/serial.h
+option.o: $(top_srcdir)/internal/set_table.h
option.o: $(top_srcdir)/internal/static_assert.h
option.o: $(top_srcdir)/internal/string.h
option.o: $(top_srcdir)/internal/thread.h
@@ -1629,6 +1664,7 @@ raddrinfo.o: $(hdrdir)/ruby/internal/intern/re.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/ruby.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/select.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/set.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/signal.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/sprintf.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1670,9 +1706,12 @@ raddrinfo.o: $(top_srcdir)/ccan/check_type/check_type.h
raddrinfo.o: $(top_srcdir)/ccan/container_of/container_of.h
raddrinfo.o: $(top_srcdir)/ccan/list/list.h
raddrinfo.o: $(top_srcdir)/ccan/str/str.h
+raddrinfo.o: $(top_srcdir)/encindex.h
+raddrinfo.o: $(top_srcdir)/id_table.h
raddrinfo.o: $(top_srcdir)/internal.h
raddrinfo.o: $(top_srcdir)/internal/array.h
raddrinfo.o: $(top_srcdir)/internal/basic_operators.h
+raddrinfo.o: $(top_srcdir)/internal/box.h
raddrinfo.o: $(top_srcdir)/internal/compilers.h
raddrinfo.o: $(top_srcdir)/internal/error.h
raddrinfo.o: $(top_srcdir)/internal/gc.h
@@ -1680,6 +1719,7 @@ raddrinfo.o: $(top_srcdir)/internal/imemo.h
raddrinfo.o: $(top_srcdir)/internal/io.h
raddrinfo.o: $(top_srcdir)/internal/sanitizers.h
raddrinfo.o: $(top_srcdir)/internal/serial.h
+raddrinfo.o: $(top_srcdir)/internal/set_table.h
raddrinfo.o: $(top_srcdir)/internal/static_assert.h
raddrinfo.o: $(top_srcdir)/internal/string.h
raddrinfo.o: $(top_srcdir)/internal/thread.h
@@ -1840,6 +1880,7 @@ socket.o: $(hdrdir)/ruby/internal/intern/re.h
socket.o: $(hdrdir)/ruby/internal/intern/ruby.h
socket.o: $(hdrdir)/ruby/internal/intern/select.h
socket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+socket.o: $(hdrdir)/ruby/internal/intern/set.h
socket.o: $(hdrdir)/ruby/internal/intern/signal.h
socket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
socket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1881,9 +1922,12 @@ socket.o: $(top_srcdir)/ccan/check_type/check_type.h
socket.o: $(top_srcdir)/ccan/container_of/container_of.h
socket.o: $(top_srcdir)/ccan/list/list.h
socket.o: $(top_srcdir)/ccan/str/str.h
+socket.o: $(top_srcdir)/encindex.h
+socket.o: $(top_srcdir)/id_table.h
socket.o: $(top_srcdir)/internal.h
socket.o: $(top_srcdir)/internal/array.h
socket.o: $(top_srcdir)/internal/basic_operators.h
+socket.o: $(top_srcdir)/internal/box.h
socket.o: $(top_srcdir)/internal/compilers.h
socket.o: $(top_srcdir)/internal/error.h
socket.o: $(top_srcdir)/internal/gc.h
@@ -1891,6 +1935,7 @@ socket.o: $(top_srcdir)/internal/imemo.h
socket.o: $(top_srcdir)/internal/io.h
socket.o: $(top_srcdir)/internal/sanitizers.h
socket.o: $(top_srcdir)/internal/serial.h
+socket.o: $(top_srcdir)/internal/set_table.h
socket.o: $(top_srcdir)/internal/static_assert.h
socket.o: $(top_srcdir)/internal/string.h
socket.o: $(top_srcdir)/internal/thread.h
@@ -2051,6 +2096,7 @@ sockssocket.o: $(hdrdir)/ruby/internal/intern/re.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/select.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/set.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/signal.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2092,9 +2138,12 @@ sockssocket.o: $(top_srcdir)/ccan/check_type/check_type.h
sockssocket.o: $(top_srcdir)/ccan/container_of/container_of.h
sockssocket.o: $(top_srcdir)/ccan/list/list.h
sockssocket.o: $(top_srcdir)/ccan/str/str.h
+sockssocket.o: $(top_srcdir)/encindex.h
+sockssocket.o: $(top_srcdir)/id_table.h
sockssocket.o: $(top_srcdir)/internal.h
sockssocket.o: $(top_srcdir)/internal/array.h
sockssocket.o: $(top_srcdir)/internal/basic_operators.h
+sockssocket.o: $(top_srcdir)/internal/box.h
sockssocket.o: $(top_srcdir)/internal/compilers.h
sockssocket.o: $(top_srcdir)/internal/error.h
sockssocket.o: $(top_srcdir)/internal/gc.h
@@ -2102,6 +2151,7 @@ sockssocket.o: $(top_srcdir)/internal/imemo.h
sockssocket.o: $(top_srcdir)/internal/io.h
sockssocket.o: $(top_srcdir)/internal/sanitizers.h
sockssocket.o: $(top_srcdir)/internal/serial.h
+sockssocket.o: $(top_srcdir)/internal/set_table.h
sockssocket.o: $(top_srcdir)/internal/static_assert.h
sockssocket.o: $(top_srcdir)/internal/string.h
sockssocket.o: $(top_srcdir)/internal/thread.h
@@ -2262,6 +2312,7 @@ tcpserver.o: $(hdrdir)/ruby/internal/intern/re.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/select.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/set.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/signal.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2303,9 +2354,12 @@ tcpserver.o: $(top_srcdir)/ccan/check_type/check_type.h
tcpserver.o: $(top_srcdir)/ccan/container_of/container_of.h
tcpserver.o: $(top_srcdir)/ccan/list/list.h
tcpserver.o: $(top_srcdir)/ccan/str/str.h
+tcpserver.o: $(top_srcdir)/encindex.h
+tcpserver.o: $(top_srcdir)/id_table.h
tcpserver.o: $(top_srcdir)/internal.h
tcpserver.o: $(top_srcdir)/internal/array.h
tcpserver.o: $(top_srcdir)/internal/basic_operators.h
+tcpserver.o: $(top_srcdir)/internal/box.h
tcpserver.o: $(top_srcdir)/internal/compilers.h
tcpserver.o: $(top_srcdir)/internal/error.h
tcpserver.o: $(top_srcdir)/internal/gc.h
@@ -2313,6 +2367,7 @@ tcpserver.o: $(top_srcdir)/internal/imemo.h
tcpserver.o: $(top_srcdir)/internal/io.h
tcpserver.o: $(top_srcdir)/internal/sanitizers.h
tcpserver.o: $(top_srcdir)/internal/serial.h
+tcpserver.o: $(top_srcdir)/internal/set_table.h
tcpserver.o: $(top_srcdir)/internal/static_assert.h
tcpserver.o: $(top_srcdir)/internal/string.h
tcpserver.o: $(top_srcdir)/internal/thread.h
@@ -2473,6 +2528,7 @@ tcpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/set.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2514,9 +2570,12 @@ tcpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
tcpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
tcpsocket.o: $(top_srcdir)/ccan/list/list.h
tcpsocket.o: $(top_srcdir)/ccan/str/str.h
+tcpsocket.o: $(top_srcdir)/encindex.h
+tcpsocket.o: $(top_srcdir)/id_table.h
tcpsocket.o: $(top_srcdir)/internal.h
tcpsocket.o: $(top_srcdir)/internal/array.h
tcpsocket.o: $(top_srcdir)/internal/basic_operators.h
+tcpsocket.o: $(top_srcdir)/internal/box.h
tcpsocket.o: $(top_srcdir)/internal/compilers.h
tcpsocket.o: $(top_srcdir)/internal/error.h
tcpsocket.o: $(top_srcdir)/internal/gc.h
@@ -2524,6 +2583,7 @@ tcpsocket.o: $(top_srcdir)/internal/imemo.h
tcpsocket.o: $(top_srcdir)/internal/io.h
tcpsocket.o: $(top_srcdir)/internal/sanitizers.h
tcpsocket.o: $(top_srcdir)/internal/serial.h
+tcpsocket.o: $(top_srcdir)/internal/set_table.h
tcpsocket.o: $(top_srcdir)/internal/static_assert.h
tcpsocket.o: $(top_srcdir)/internal/string.h
tcpsocket.o: $(top_srcdir)/internal/thread.h
@@ -2684,6 +2744,7 @@ udpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/set.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2725,9 +2786,12 @@ udpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
udpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
udpsocket.o: $(top_srcdir)/ccan/list/list.h
udpsocket.o: $(top_srcdir)/ccan/str/str.h
+udpsocket.o: $(top_srcdir)/encindex.h
+udpsocket.o: $(top_srcdir)/id_table.h
udpsocket.o: $(top_srcdir)/internal.h
udpsocket.o: $(top_srcdir)/internal/array.h
udpsocket.o: $(top_srcdir)/internal/basic_operators.h
+udpsocket.o: $(top_srcdir)/internal/box.h
udpsocket.o: $(top_srcdir)/internal/compilers.h
udpsocket.o: $(top_srcdir)/internal/error.h
udpsocket.o: $(top_srcdir)/internal/gc.h
@@ -2735,6 +2799,7 @@ udpsocket.o: $(top_srcdir)/internal/imemo.h
udpsocket.o: $(top_srcdir)/internal/io.h
udpsocket.o: $(top_srcdir)/internal/sanitizers.h
udpsocket.o: $(top_srcdir)/internal/serial.h
+udpsocket.o: $(top_srcdir)/internal/set_table.h
udpsocket.o: $(top_srcdir)/internal/static_assert.h
udpsocket.o: $(top_srcdir)/internal/string.h
udpsocket.o: $(top_srcdir)/internal/thread.h
@@ -2895,6 +2960,7 @@ unixserver.o: $(hdrdir)/ruby/internal/intern/re.h
unixserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
unixserver.o: $(hdrdir)/ruby/internal/intern/select.h
unixserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/set.h
unixserver.o: $(hdrdir)/ruby/internal/intern/signal.h
unixserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
unixserver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2936,9 +3002,12 @@ unixserver.o: $(top_srcdir)/ccan/check_type/check_type.h
unixserver.o: $(top_srcdir)/ccan/container_of/container_of.h
unixserver.o: $(top_srcdir)/ccan/list/list.h
unixserver.o: $(top_srcdir)/ccan/str/str.h
+unixserver.o: $(top_srcdir)/encindex.h
+unixserver.o: $(top_srcdir)/id_table.h
unixserver.o: $(top_srcdir)/internal.h
unixserver.o: $(top_srcdir)/internal/array.h
unixserver.o: $(top_srcdir)/internal/basic_operators.h
+unixserver.o: $(top_srcdir)/internal/box.h
unixserver.o: $(top_srcdir)/internal/compilers.h
unixserver.o: $(top_srcdir)/internal/error.h
unixserver.o: $(top_srcdir)/internal/gc.h
@@ -2946,6 +3015,7 @@ unixserver.o: $(top_srcdir)/internal/imemo.h
unixserver.o: $(top_srcdir)/internal/io.h
unixserver.o: $(top_srcdir)/internal/sanitizers.h
unixserver.o: $(top_srcdir)/internal/serial.h
+unixserver.o: $(top_srcdir)/internal/set_table.h
unixserver.o: $(top_srcdir)/internal/static_assert.h
unixserver.o: $(top_srcdir)/internal/string.h
unixserver.o: $(top_srcdir)/internal/thread.h
@@ -3106,6 +3176,7 @@ unixsocket.o: $(hdrdir)/ruby/internal/intern/re.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/select.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/set.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3147,9 +3218,12 @@ unixsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
unixsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
unixsocket.o: $(top_srcdir)/ccan/list/list.h
unixsocket.o: $(top_srcdir)/ccan/str/str.h
+unixsocket.o: $(top_srcdir)/encindex.h
+unixsocket.o: $(top_srcdir)/id_table.h
unixsocket.o: $(top_srcdir)/internal.h
unixsocket.o: $(top_srcdir)/internal/array.h
unixsocket.o: $(top_srcdir)/internal/basic_operators.h
+unixsocket.o: $(top_srcdir)/internal/box.h
unixsocket.o: $(top_srcdir)/internal/compilers.h
unixsocket.o: $(top_srcdir)/internal/error.h
unixsocket.o: $(top_srcdir)/internal/gc.h
@@ -3157,6 +3231,7 @@ unixsocket.o: $(top_srcdir)/internal/imemo.h
unixsocket.o: $(top_srcdir)/internal/io.h
unixsocket.o: $(top_srcdir)/internal/sanitizers.h
unixsocket.o: $(top_srcdir)/internal/serial.h
+unixsocket.o: $(top_srcdir)/internal/set_table.h
unixsocket.o: $(top_srcdir)/internal/static_assert.h
unixsocket.o: $(top_srcdir)/internal/string.h
unixsocket.o: $(top_srcdir)/internal/thread.h
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index d44ce31b0a..a814e21c3a 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -704,6 +704,7 @@ SRC
have_func("pthread_create")
have_func("pthread_detach")
+ have_func("pthread_attr_setdetachstate")
$VPATH << '$(topdir)' << '$(top_srcdir)'
create_makefile("socket")
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index bf0d90129f..9a65490b1d 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -62,9 +62,6 @@
#endif
#include <unistd.h>
#else
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
@@ -171,9 +168,7 @@ static const char *const ai_errlist[] = {
#define GET_CANONNAME(ai, str) \
if (pai->ai_flags & AI_CANONNAME) {\
- if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
- strcpy((ai)->ai_canonname, (str));\
- } else {\
+ if (((ai)->ai_canonname = strdup(str)) == NULL) {\
error = EAI_MEMORY;\
goto free;\
}\
diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c
index ae5284fab6..98da8c1647 100644
--- a/ext/socket/getnameinfo.c
+++ b/ext/socket/getnameinfo.c
@@ -55,9 +55,6 @@
#endif
#endif
#ifdef _WIN32
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#define snprintf _snprintf
@@ -158,16 +155,14 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
/* what we should do? */
} else if (flags & NI_NUMERICSERV) {
snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
- if (strlen(numserv) + 1 > servlen)
+ if (strlcpy(serv, numserv, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, numserv);
} else {
#if defined(HAVE_GETSERVBYPORT)
struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
if (sp) {
- if (strlen(sp->s_name) + 1 > servlen)
+ if (strlcpy(serv, sp->s_name, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, sp->s_name);
} else
return ENI_NOSERVNAME;
#else
@@ -202,9 +197,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_SYSTEM;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
} else {
#ifdef INET6
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
@@ -218,13 +212,12 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
p = strchr(hp->h_name, '.');
if (p) *p = '\0';
}
- if (strlen(hp->h_name) + 1 > hostlen) {
+ if (strlcpy(host, hp->h_name, hostlen) >= hostlen) {
#ifdef INET6
freehostent(hp);
#endif
return ENI_MEMORY;
}
- strcpy(host, hp->h_name);
#ifdef INET6
freehostent(hp);
#endif
@@ -234,9 +227,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_NOHOSTNAME;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
}
}
return SUCCESS;
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 8e405609ba..b761d601c3 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -473,7 +473,7 @@ rsock_socket(int domain, int type, int proto)
/* emulate blocking connect behavior on EINTR or non-blocking socket */
static int
-wait_connectable(VALUE self, VALUE timeout)
+wait_connectable(VALUE self, VALUE timeout, const struct sockaddr *sockaddr, int len)
{
int sockerr;
socklen_t sockerrlen;
@@ -514,7 +514,10 @@ wait_connectable(VALUE self, VALUE timeout)
VALUE result = rb_io_wait(self, RB_INT2NUM(RUBY_IO_READABLE|RUBY_IO_WRITABLE), timeout);
if (result == Qfalse) {
- rb_raise(rb_eIOTimeoutError, "Connect timed out!");
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)sockaddr, len, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ VALUE message = rb_sprintf("user specified timeout for %" PRIsVALUE, addr_str);
+ rb_raise(rb_eIOTimeoutError, "%" PRIsVALUE, message);
}
int revents = RB_NUM2INT(result);
@@ -603,7 +606,7 @@ rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, V
#ifdef EINPROGRESS
case EINPROGRESS:
#endif
- return wait_connectable(self, timeout);
+ return wait_connectable(self, timeout, sockaddr, len);
}
}
return status;
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index 4dfd9c8a56..931a1a629c 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -23,8 +23,25 @@ struct inetsock_arg
int type;
VALUE resolv_timeout;
VALUE connect_timeout;
+ VALUE open_timeout;
};
+void
+rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port)
+{
+ VALUE message;
+
+ if (ai && ai->ai_addr) {
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)ai->ai_addr, (socklen_t)ai->ai_addrlen, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE, addr_str);
+ } else {
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE " port %" PRIsVALUE, host, port);
+ }
+
+ rb_raise(rb_eIOTimeoutError, "%" PRIsVALUE, message);
+}
+
static VALUE
inetsock_cleanup(VALUE v)
{
@@ -45,6 +62,13 @@ inetsock_cleanup(VALUE v)
}
static VALUE
+current_clocktime(void)
+{
+ VALUE clock_monotnic_const = rb_const_get(rb_mProcess, rb_intern("CLOCK_MONOTONIC"));
+ return rb_funcall(rb_mProcess, rb_intern("clock_gettime"), 1, clock_monotnic_const);
+}
+
+static VALUE
init_inetsock_internal(VALUE v)
{
struct inetsock_arg *arg = (void *)v;
@@ -54,12 +78,18 @@ init_inetsock_internal(VALUE v)
int status = 0, local = 0;
int family = AF_UNSPEC;
const char *syscall = 0;
+ VALUE resolv_timeout = arg->resolv_timeout;
VALUE connect_timeout = arg->connect_timeout;
+ VALUE open_timeout = arg->open_timeout;
+ VALUE timeout;
+ VALUE starts_at;
+
+ timeout = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
+ starts_at = current_clocktime();
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
family, SOCK_STREAM,
- (type == INET_SERVER) ? AI_PASSIVE : 0);
-
+ (type == INET_SERVER) ? AI_PASSIVE : 0, timeout);
/*
* Maybe also accept a local address
@@ -67,7 +97,7 @@ init_inetsock_internal(VALUE v)
if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv,
- family, SOCK_STREAM, 0);
+ family, SOCK_STREAM, 0, timeout);
}
VALUE io = Qnil;
@@ -122,8 +152,18 @@ init_inetsock_internal(VALUE v)
syscall = "bind(2)";
}
+ if (NIL_P(open_timeout)) {
+ timeout = connect_timeout;
+ } else {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(res, arg->remote.host, arg->remote.serv);
+ }
+ }
+
if (status >= 0) {
- status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), connect_timeout);
+ status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), timeout);
syscall = "connect(2)";
}
}
@@ -172,8 +212,16 @@ init_inetsock_internal(VALUE v)
#if FAST_FALLBACK_INIT_INETSOCK_IMPL == 0
VALUE
-rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE _fast_fallback, VALUE _test_mode_settings)
+rsock_init_inetsock(
+ VALUE self, VALUE remote_host, VALUE remote_serv,
+ VALUE local_host, VALUE local_serv, int type,
+ VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
+ VALUE _fast_fallback, VALUE _test_mode_settings)
{
+ if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
+ rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
+ }
+
struct inetsock_arg arg;
arg.self = self;
arg.io = Qnil;
@@ -186,6 +234,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
arg.type = type;
arg.resolv_timeout = resolv_timeout;
arg.connect_timeout = connect_timeout;
+ arg.open_timeout = open_timeout;
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
inetsock_cleanup, (VALUE)&arg);
}
@@ -209,6 +258,21 @@ is_specified_ip_address(const char *hostname)
inet_pton(AF_INET, hostname, &ipv4addr) == 1);
}
+static int
+is_local_port_fixed(const char *portp)
+{
+ if (!portp) return 0;
+
+ char *endp;
+ errno = 0;
+ long port = strtol(portp, &endp, 10);
+
+ if (endp == portp) return 0;
+ if (errno == ERANGE) return 0;
+
+ return port > 0;
+}
+
struct fast_fallback_inetsock_arg
{
VALUE self;
@@ -221,6 +285,7 @@ struct fast_fallback_inetsock_arg
int type;
VALUE resolv_timeout;
VALUE connect_timeout;
+ VALUE open_timeout;
const char *hostp, *portp;
int *families;
@@ -380,12 +445,22 @@ select_expires_at(
struct timeval *resolution_delay,
struct timeval *connection_attempt_delay,
struct timeval *user_specified_resolv_timeout_at,
- struct timeval *user_specified_connect_timeout_at
-) {
+ struct timeval *user_specified_connect_timeout_at,
+ struct timeval *user_specified_open_timeout_at)
+{
if (any_addrinfos(resolution_store)) {
- return resolution_delay ? resolution_delay : connection_attempt_delay;
+ struct timeval *delay;
+ delay = resolution_delay ? resolution_delay : connection_attempt_delay;
+
+ if (user_specified_open_timeout_at &&
+ timercmp(user_specified_open_timeout_at, delay, <)) {
+ return user_specified_open_timeout_at;
+ }
+ return delay;
}
+ if (user_specified_open_timeout_at) return user_specified_open_timeout_at;
+
struct timeval *timeout = NULL;
if (user_specified_resolv_timeout_at) {
@@ -474,7 +549,8 @@ in_progress_fds(int fds_size)
}
static void
-remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd) {
+remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd)
+{
int i, j;
for (i = 0; i < *fds_size; i++) {
@@ -503,6 +579,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
VALUE io = arg->io;
VALUE resolv_timeout = arg->resolv_timeout;
VALUE connect_timeout = arg->connect_timeout;
+ VALUE open_timeout = arg->open_timeout;
VALUE test_mode_settings = arg->test_mode_settings;
struct addrinfo *remote_ai = NULL, *local_ai = NULL;
int connected_fd = -1, status = 0, local_status = 0;
@@ -549,7 +626,16 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct timeval *user_specified_resolv_timeout_at = NULL;
struct timeval user_specified_connect_timeout_storage;
struct timeval *user_specified_connect_timeout_at = NULL;
+ struct timeval user_specified_open_timeout_storage;
+ struct timeval *user_specified_open_timeout_at = NULL;
struct timespec now = current_clocktime_ts();
+ VALUE starts_at = current_clocktime();
+
+ if (!NIL_P(open_timeout)) {
+ struct timeval open_timeout_tv = rb_time_interval(open_timeout);
+ user_specified_open_timeout_storage = add_ts_to_tv(open_timeout_tv, now);
+ user_specified_open_timeout_at = &user_specified_open_timeout_storage;
+ }
/* start of hostname resolution */
if (arg->family_size == 1) {
@@ -557,12 +643,15 @@ init_fast_fallback_inetsock_internal(VALUE v)
arg->getaddrinfo_shared = NULL;
int family = arg->families[0];
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
+
arg->remote.res = rsock_addrinfo(
arg->remote.host,
arg->remote.serv,
family,
SOCK_STREAM,
- 0
+ 0,
+ t
);
if (family == AF_INET6) {
@@ -640,7 +729,6 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (raddrinfo_pthread_create(&threads[i], fork_safe_do_fast_fallback_getaddrinfo, arg->getaddrinfo_entries[i]) != 0) {
rsock_raise_resolution_error("getaddrinfo(3)", EAI_AGAIN);
}
- pthread_detach(threads[i]);
}
if (NIL_P(resolv_timeout)) {
@@ -769,14 +857,26 @@ init_fast_fallback_inetsock_internal(VALUE v)
status = connect(fd, remote_ai->ai_addr, remote_ai->ai_addrlen);
last_family = remote_ai->ai_family;
} else {
- if (!NIL_P(connect_timeout)) {
- user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
- user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ VALUE timeout = Qnil;
+
+ if (!NIL_P(open_timeout)) {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
+ }
+ if (NIL_P(timeout)) {
+ if (!NIL_P(connect_timeout)) {
+ user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
+ user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ }
+ timeout =
+ (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
+ Qnil : tv_to_seconds(user_specified_connect_timeout_at);
}
- VALUE timeout =
- (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
- Qnil : tv_to_seconds(user_specified_connect_timeout_at);
io = arg->io = rsock_init_sock(arg->self, fd);
status = rsock_connect(io, remote_ai->ai_addr, remote_ai->ai_addrlen, 0, timeout);
}
@@ -848,7 +948,8 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_delay_expires_at,
connection_attempt_delay_expires_at,
user_specified_resolv_timeout_at,
- user_specified_connect_timeout_at
+ user_specified_connect_timeout_at,
+ user_specified_open_timeout_at
);
if (ends_at) {
delay = tv_to_timeout(ends_at, now);
@@ -1101,6 +1202,10 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
}
+ if (is_timeout_tv(user_specified_open_timeout_at, now)) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
+
if (!any_addrinfos(&resolution_store)) {
if (!in_progress_fds(arg->connection_attempt_fds_size) &&
resolution_store.is_all_finished) {
@@ -1122,9 +1227,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_store.is_all_finished) &&
(is_timeout_tv(user_specified_connect_timeout_at, now) ||
!in_progress_fds(arg->connection_attempt_fds_size))) {
- VALUE errno_module = rb_const_get(rb_cObject, rb_intern("Errno"));
- VALUE etimedout_error = rb_const_get(errno_module, rb_intern("ETIMEDOUT"));
- rb_raise(etimedout_error, "user specified timeout");
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
}
}
}
@@ -1159,13 +1262,19 @@ fast_fallback_inetsock_cleanup(VALUE v)
getaddrinfo_shared->notify = -1;
int shared_need_free = 0;
- int need_free[2] = { 0, 0 };
+ struct addrinfo *ais[arg->family_size];
+ for (int i = 0; i < arg->family_size; i++) ais[i] = NULL;
rb_nativethread_lock_lock(&getaddrinfo_shared->lock);
{
for (int i = 0; i < arg->family_size; i++) {
- if (arg->getaddrinfo_entries[i] && --(arg->getaddrinfo_entries[i]->refcount) == 0) {
- need_free[i] = 1;
+ struct fast_fallback_getaddrinfo_entry *getaddrinfo_entry = arg->getaddrinfo_entries[i];
+
+ if (!getaddrinfo_entry) continue;
+
+ if (--(getaddrinfo_entry->refcount) == 0) {
+ ais[i] = getaddrinfo_entry->ai;
+ getaddrinfo_entry->ai = NULL;
}
}
if (--(getaddrinfo_shared->refcount) == 0) {
@@ -1175,9 +1284,7 @@ fast_fallback_inetsock_cleanup(VALUE v)
rb_nativethread_lock_unlock(&getaddrinfo_shared->lock);
for (int i = 0; i < arg->family_size; i++) {
- if (arg->getaddrinfo_entries[i] && need_free[i]) {
- free_fast_fallback_getaddrinfo_entry(&arg->getaddrinfo_entries[i]);
- }
+ if (ais[i]) freeaddrinfo(ais[i]);
}
if (getaddrinfo_shared && shared_need_free) {
free_fast_fallback_getaddrinfo_shared(&getaddrinfo_shared);
@@ -1210,17 +1317,27 @@ fast_fallback_inetsock_cleanup(VALUE v)
}
VALUE
-rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE fast_fallback, VALUE test_mode_settings)
+rsock_init_inetsock(
+ VALUE self, VALUE remote_host, VALUE remote_serv,
+ VALUE local_host, VALUE local_serv, int type,
+ VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
+ VALUE fast_fallback, VALUE test_mode_settings)
{
+ if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
+ rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
+ }
+
if (type == INET_CLIENT && FAST_FALLBACK_INIT_INETSOCK_IMPL == 1 && RTEST(fast_fallback)) {
struct rb_addrinfo *local_res = NULL;
- char *hostp, *portp;
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ char *hostp, *portp, *local_portp;
+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], local_pbuf[NI_MAXSERV];
int additional_flags = 0;
+ int local_flags = 0;
hostp = raddrinfo_host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags);
portp = raddrinfo_port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags);
+ local_portp = raddrinfo_port_str(local_serv, local_pbuf, sizeof(local_pbuf), &local_flags);
- if (!is_specified_ip_address(hostp)) {
+ if (!is_specified_ip_address(hostp) && !is_local_port_fixed(local_portp)) {
int target_families[2] = { 0, 0 };
int resolving_family_size = 0;
@@ -1228,16 +1345,18 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
* Maybe also accept a local address
*/
if (!NIL_P(local_host) || !NIL_P(local_serv)) {
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
local_res = rsock_addrinfo(
local_host,
local_serv,
AF_UNSPEC,
SOCK_STREAM,
- 0
+ 0,
+ t
);
struct addrinfo *tmp_p = local_res->ai;
- for (tmp_p; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
+ for (; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
if (target_families[0] == 0 && tmp_p->ai_family == AF_INET6) {
target_families[0] = AF_INET6;
resolving_family_size++;
@@ -1267,6 +1386,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
fast_fallback_arg.type = type;
fast_fallback_arg.resolv_timeout = resolv_timeout;
fast_fallback_arg.connect_timeout = connect_timeout;
+ fast_fallback_arg.open_timeout = open_timeout;
fast_fallback_arg.hostp = hostp;
fast_fallback_arg.portp = portp;
fast_fallback_arg.additional_flags = additional_flags;
@@ -1303,6 +1423,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
arg.type = type;
arg.resolv_timeout = resolv_timeout;
arg.connect_timeout = connect_timeout;
+ arg.open_timeout = open_timeout;
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
inetsock_cleanup, (VALUE)&arg);
@@ -1488,7 +1609,7 @@ static VALUE
ip_s_getaddress(VALUE obj, VALUE host)
{
union_sockaddr addr;
- struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, Qnil);
socklen_t len = res->ai->ai_addrlen;
/* just take the first one */
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 60dd45bd4f..36fcceaee9 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -62,7 +62,7 @@ class Addrinfo
break
when :wait_writable
sock.wait_writable(timeout) or
- raise Errno::ETIMEDOUT, 'user specified timeout'
+ raise Errno::ETIMEDOUT, "user specified timeout for #{self.ip_address}:#{self.ip_port}"
end while true
else
sock.connect(self)
@@ -599,6 +599,7 @@ class Socket < BasicSocket
__accept_nonblock(exception)
end
+ # :stopdoc:
RESOLUTION_DELAY = 0.05
private_constant :RESOLUTION_DELAY
@@ -616,6 +617,7 @@ class Socket < BasicSocket
IPV6_ADDRESS_FORMAT = /\A(?i:(?:(?:[0-9A-F]{1,4}:){7}(?:[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){6}(?:[0-9A-F]{1,4}|:(?:[0-9A-F]{1,4}:){1,5}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){5}(?:(?::[0-9A-F]{1,4}){1,2}|:(?:[0-9A-F]{1,4}:){1,4}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){4}(?:(?::[0-9A-F]{1,4}){1,3}|:(?:[0-9A-F]{1,4}:){1,3}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){3}(?:(?::[0-9A-F]{1,4}){1,4}|:(?:[0-9A-F]{1,4}:){1,2}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){2}(?:(?::[0-9A-F]{1,4}){1,5}|:(?:[0-9A-F]{1,4}:)[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){1}(?:(?::[0-9A-F]{1,4}){1,6}|:(?:[0-9A-F]{1,4}:){0,5}[0-9A-F]{1,4}|:)|(?:::(?:[0-9A-F]{1,4}:){0,7}[0-9A-F]{1,4}|::)))(?:%.+)?\z/
private_constant :IPV6_ADDRESS_FORMAT
+ # :startdoc:
# :call-seq:
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
@@ -643,6 +645,7 @@ class Socket < BasicSocket
#
# [:resolv_timeout] Specifies the timeout in seconds from when the hostname resolution starts.
# [:connect_timeout] This method sequentially attempts connecting to all candidate destination addresses.<br>The +connect_timeout+ specifies the timeout in seconds from the start of the connection attempt to the last candidate.<br>By default, all connection attempts continue until the timeout occurs.<br>When +fast_fallback:false+ is explicitly specified,<br>a timeout is set for each connection attempt and any connection attempt that exceeds its timeout will be canceled.
+ # [:open_timeout] Specifies the timeout in seconds from the start of the method execution.<br>If this timeout is reached while there are still addresses that have not yet been attempted for connection, no further attempts will be made.<br>If this option is specified together with other timeout options, an +ArgumentError+ will be raised.
# [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (enabled by default).
#
# If a block is given, the block is called with the socket.
@@ -656,11 +659,15 @@ class Socket < BasicSocket
# sock.close_write
# puts sock.read
# }
- def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
- sock = if fast_fallback && !(host && ip_address?(host))
- tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
+ if open_timeout && (connect_timeout || resolv_timeout)
+ raise ArgumentError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout"
+ end
+
+ sock = if fast_fallback && !(host && ip_address?(host)) && !(local_port && local_port.to_i != 0)
+ tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
else
- tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
end
if block_given?
@@ -674,9 +681,10 @@ class Socket < BasicSocket
end
end
- def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil)
+ # :stopdoc:
+ def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil)
if local_host || local_port
- local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: resolv_timeout)
+ local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: open_timeout || resolv_timeout)
resolving_family_names = local_addrinfos.map { |lai| ADDRESS_FAMILIES.key(lai.afamily) }.uniq
else
local_addrinfos = []
@@ -689,15 +697,17 @@ class Socket < BasicSocket
is_windows_environment ||= (RUBY_PLATFORM =~ /mswin|mingw|cygwin/)
now = current_clock_time
+ starts_at = now
resolution_delay_expires_at = nil
connection_attempt_delay_expires_at = nil
user_specified_connect_timeout_at = nil
+ user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil
last_error = nil
last_error_from_thread = false
if resolving_family_names.size == 1
family_name = resolving_family_names.first
- addrinfos = Addrinfo.getaddrinfo(host, port, family_name, :STREAM, timeout: resolv_timeout)
+ addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[:family_name], :STREAM, timeout: open_timeout || resolv_timeout)
resolution_store.add_resolved(family_name, addrinfos)
hostname_resolution_result = nil
hostname_resolution_notifier = nil
@@ -714,7 +724,6 @@ class Socket < BasicSocket
thread
}
)
-
user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY
end
@@ -726,7 +735,7 @@ class Socket < BasicSocket
if local_addrinfos.any?
local_addrinfo = local_addrinfos.find { |lai| lai.afamily == addrinfo.afamily }
- if local_addrinfo.nil? # Connecting addrinfoと同じアドレスファミリのLocal addrinfoがない
+ if local_addrinfo.nil?
if resolution_store.any_addrinfos?
# Try other Addrinfo in next "while"
next
@@ -748,9 +757,16 @@ class Socket < BasicSocket
socket.bind(local_addrinfo) if local_addrinfo
result = socket.connect_nonblock(addrinfo, exception: false)
else
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
result = socket = local_addrinfo ?
- addrinfo.connect_from(local_addrinfo, timeout: connect_timeout) :
- addrinfo.connect(timeout: connect_timeout)
+ addrinfo.connect_from(local_addrinfo, timeout:) :
+ addrinfo.connect(timeout:)
end
if result == :wait_writable
@@ -784,7 +800,10 @@ class Socket < BasicSocket
ends_at =
if resolution_store.any_addrinfos?
- resolution_delay_expires_at || connection_attempt_delay_expires_at
+ [(resolution_delay_expires_at || connection_attempt_delay_expires_at),
+ user_specified_open_timeout_at].compact.min
+ elsif user_specified_open_timeout_at
+ user_specified_open_timeout_at
else
[user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max
end
@@ -885,6 +904,10 @@ class Socket < BasicSocket
end
end
+ if expired?(now, user_specified_open_timeout_at)
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
+ end
+
if resolution_store.empty_addrinfos?
if connecting_sockets.empty? && resolution_store.resolved_all_families?
if last_error_from_thread
@@ -896,7 +919,7 @@ class Socket < BasicSocket
if (expired?(now, user_specified_resolv_timeout_at) || resolution_store.resolved_all_families?) &&
(expired?(now, user_specified_connect_timeout_at) || connecting_sockets.empty?)
- raise Errno::ETIMEDOUT, 'user specified timeout'
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
end
end
end
@@ -911,17 +934,21 @@ class Socket < BasicSocket
connecting_socket.close
end
end
+ private_class_method :tcp_with_fast_fallback
- def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
last_error = nil
ret = nil
local_addr_list = nil
if local_host != nil || local_port != nil
- local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
+ local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil, timeout: open_timeout || resolv_timeout)
end
- Addrinfo.foreach(host, port, nil, :STREAM, timeout: resolv_timeout) {|ai|
+ timeout = open_timeout ? open_timeout : resolv_timeout
+ starts_at = current_clock_time
+
+ Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai|
if local_addr_list
local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
next unless local_addr
@@ -929,9 +956,17 @@ class Socket < BasicSocket
local_addr = nil
end
begin
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
+
sock = local_addr ?
- ai.connect_from(local_addr, timeout: connect_timeout) :
- ai.connect(timeout: connect_timeout)
+ ai.connect_from(local_addr, timeout:) :
+ ai.connect(timeout:)
rescue SystemCallError
last_error = $!
next
@@ -1090,7 +1125,6 @@ class Socket < BasicSocket
end
private_constant :HostnameResolutionStore
- # :stopdoc:
def self.ip_sockets_port0(ai_list, reuseaddr)
sockets = []
begin
@@ -1123,9 +1157,7 @@ class Socket < BasicSocket
end
sockets
end
- class << self
- private :ip_sockets_port0
- end
+ private_class_method :ip_sockets_port0
def self.tcp_server_sockets_port0(host)
ai_list = Addrinfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE)
@@ -1553,13 +1585,18 @@ class Socket < BasicSocket
end
end
- class << self
- private
-
- def unix_socket_abstract_name?(path)
- /linux/ =~ RUBY_PLATFORM && /\A(\0|\z)/ =~ path
+ # :stopdoc:
+ if RUBY_PLATFORM.include?("linux")
+ def self.unix_socket_abstract_name?(path)
+ path.empty? or path.start_with?("\0")
+ end
+ else
+ def self.unix_socket_abstract_name?(path)
+ false
end
end
+ private_class_method :unix_socket_abstract_name?
+ # :startdoc:
# creates a UNIX socket server on _path_.
# It calls the block for each socket accepted.
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index ac47b5b256..6cdf5c6abc 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -293,10 +293,22 @@ rb_freeaddrinfo(struct rb_addrinfo *ai)
xfree(ai);
}
+static int
+rsock_value_timeout_to_msec(VALUE timeout)
+{
+ double seconds = NUM2DBL(timeout);
+ if (seconds < 0) rb_raise(rb_eArgError, "timeout must not be negative");
+
+ double msec = seconds * 1000.0;
+ if (msec > UINT_MAX) rb_raise(rb_eArgError, "timeout too large");
+
+ return (unsigned int)(msec + 0.5);
+}
+
#if GETADDRINFO_IMPL == 0
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
return getaddrinfo(hostp, portp, hints, ai);
}
@@ -334,7 +346,7 @@ fork_safe_getaddrinfo(void *arg)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
struct getaddrinfo_arg arg;
MEMZERO(&arg, struct getaddrinfo_arg, 1);
@@ -352,13 +364,14 @@ struct getaddrinfo_arg
char *node, *service;
struct addrinfo hints;
struct addrinfo *ai;
- int err, gai_errno, refcount, done, cancelled;
+ int err, gai_errno, refcount, done, cancelled, timedout;
rb_nativethread_lock_t lock;
rb_nativethread_cond_t cond;
+ int timeout;
};
static struct getaddrinfo_arg *
-allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints)
+allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, int timeout)
{
size_t hostp_offset = sizeof(struct getaddrinfo_arg);
size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0);
@@ -374,7 +387,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (hostp) {
arg->node = buf + hostp_offset;
- strcpy(arg->node, hostp);
+ memcpy(arg->node, hostp, portp_offset - hostp_offset);
}
else {
arg->node = NULL;
@@ -382,7 +395,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (portp) {
arg->service = buf + portp_offset;
- strcpy(arg->service, portp);
+ memcpy(arg->service, portp, bufsize - portp_offset);
}
else {
arg->service = NULL;
@@ -392,7 +405,8 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
arg->ai = NULL;
arg->refcount = 2;
- arg->done = arg->cancelled = 0;
+ arg->done = arg->cancelled = arg->timedout = 0;
+ arg->timeout = timeout;
rb_nativethread_lock_initialize(&arg->lock);
rb_native_cond_initialize(&arg->cond);
@@ -451,7 +465,19 @@ wait_getaddrinfo(void *ptr)
struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
rb_nativethread_lock_lock(&arg->lock);
while (!arg->done && !arg->cancelled) {
- rb_native_cond_wait(&arg->cond, &arg->lock);
+ long msec = arg->timeout;
+ if (msec == 0) {
+ arg->cancelled = 1;
+ arg->timedout = 1;
+ } else if (msec > 0) {
+ rb_native_cond_timedwait(&arg->cond, &arg->lock, msec);
+ if (!arg->done) {
+ arg->cancelled = 1;
+ arg->timedout = 1;
+ }
+ } else {
+ rb_native_cond_wait(&arg->cond, &arg->lock);
+ }
}
rb_nativethread_lock_unlock(&arg->lock);
return 0;
@@ -473,13 +499,49 @@ int
raddrinfo_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg)
{
int limit = 3, ret;
+ int saved_errno;
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ pthread_attr_t attr;
+ pthread_attr_t *attr_p = &attr;
+ int err;
+ int init_retries = 0;
+ int init_retries_max = 3;
+retry_attr_init:
+ if ((err = pthread_attr_init(attr_p)) != 0) {
+ if (err == ENOMEM && init_retries < init_retries_max) {
+ init_retries++;
+ rb_gc();
+ goto retry_attr_init;
+ }
+ return err;
+ }
+ if ((err = pthread_attr_setdetachstate(attr_p, PTHREAD_CREATE_DETACHED)) != 0) {
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ errno = saved_errno;
+ return err; // EINVAL - shouldn't happen
+ }
+#else
+ pthread_attr_t *attr_p = NULL;
+#endif
do {
// It is said that pthread_create may fail spuriously, so we follow the JDK and retry several times.
//
// https://bugs.openjdk.org/browse/JDK-8268605
// https://github.com/openjdk/jdk/commit/e35005d5ce383ddd108096a3079b17cb0bcf76f1
- ret = pthread_create(th, 0, start_routine, arg);
+ ret = pthread_create(th, attr_p, start_routine, arg);
} while (ret == EAGAIN && limit-- > 0);
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ if (ret != 0) {
+ errno = saved_errno;
+ }
+#else
+ if (ret == 0) {
+ pthread_detach(th); // this can race with shutdown routine of thread in some glibc versions
+ }
+#endif
return ret;
}
@@ -490,16 +552,16 @@ fork_safe_do_getaddrinfo(void *ptr)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int timeout)
{
int retry;
struct getaddrinfo_arg *arg;
- int err = 0, gai_errno = 0;
+ int err = 0, gai_errno = 0, timedout = 0;
start:
retry = 0;
- arg = allocate_getaddrinfo_arg(hostp, portp, hints);
+ arg = allocate_getaddrinfo_arg(hostp, portp, hints, timeout);
if (!arg) {
return EAI_MEMORY;
}
@@ -511,7 +573,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg);
@@ -525,6 +586,7 @@ start:
}
else if (arg->cancelled) {
retry = 1;
+ timedout = arg->timedout;
}
else {
// If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getaddrinfo.
@@ -538,6 +600,16 @@ start:
if (need_free) free_getaddrinfo_arg(arg);
+ if (timedout) {
+ if (arg->ai) {
+ rsock_raise_user_specified_timeout(arg->ai, Qnil, Qnil);
+ } else {
+ VALUE host = rb_str_new_cstr(hostp);
+ VALUE port = rb_str_new_cstr(portp);
+ rsock_raise_user_specified_timeout(NULL, host, port);
+ }
+ }
+
// If the current thread is interrupted by asynchronous exception, the following raises the exception.
// But if the current thread is interrupted by timer thread, the following returns; we need to manually retry.
rb_thread_check_ints();
@@ -552,6 +624,10 @@ start:
#endif
+#define GETNAMEINFO_WONT_BLOCK(host, serv, flags) \
+ ((!(host) || ((flags) & NI_NUMERICHOST)) && \
+ (!(serv) || ((flags) & NI_NUMERICSERV)))
+
#if GETADDRINFO_IMPL == 0
int
@@ -559,7 +635,7 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags)
{
- return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
}
#elif GETADDRINFO_IMPL == 1
@@ -589,6 +665,10 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags)
{
+ if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) {
+ return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+ }
+
struct getnameinfo_arg arg;
int ret;
arg.sa = sa;
@@ -715,7 +795,11 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
{
int retry;
struct getnameinfo_arg *arg;
- int err, gni_errno = 0;
+ int err = 0, gni_errno = 0;
+
+ if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) {
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
+ }
start:
retry = 0;
@@ -732,7 +816,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getnameinfo, arg, cancel_getnameinfo, arg);
@@ -941,7 +1024,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service,
}
struct rb_addrinfo*
-rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
+rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout)
{
struct rb_addrinfo* res = NULL;
struct addrinfo *ai;
@@ -976,7 +1059,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
}
if (!resolved) {
- error = rb_getaddrinfo(hostp, portp, hints, &ai);
+ int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout);
+ error = rb_getaddrinfo(hostp, portp, hints, &ai, t);
if (error == 0) {
res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
res->allocated_by_malloc = 0;
@@ -1009,7 +1093,7 @@ rsock_fd_family(int fd)
}
struct rb_addrinfo*
-rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
+rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout)
{
struct addrinfo hints;
@@ -1017,7 +1101,7 @@ rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
hints.ai_family = family;
hints.ai_socktype = socktype;
hints.ai_flags = flags;
- return rsock_getaddrinfo(host, port, &hints, 1);
+ return rsock_getaddrinfo(host, port, &hints, 1, timeout);
}
VALUE
@@ -1211,6 +1295,7 @@ addrinfo_memsize(const void *ptr)
static const rb_data_type_t addrinfo_type = {
"socket/addrinfo",
{addrinfo_mark, addrinfo_free, addrinfo_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED,
};
static VALUE
@@ -1248,7 +1333,7 @@ alloc_addrinfo(void)
}
static void
-init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
+init_addrinfo(VALUE self, rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
int pfamily, int socktype, int protocol,
VALUE canonname, VALUE inspectname)
{
@@ -1260,8 +1345,8 @@ init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
rai->pfamily = pfamily;
rai->socktype = socktype;
rai->protocol = protocol;
- rai->canonname = canonname;
- rai->inspectname = inspectname;
+ RB_OBJ_WRITE(self, &rai->canonname, canonname);
+ RB_OBJ_WRITE(self, &rai->inspectname, inspectname);
}
VALUE
@@ -1274,7 +1359,7 @@ rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
a = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(a) = rai = alloc_addrinfo();
- init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname);
+ init_addrinfo(a, rai, addr, len, family, socktype, protocol, canonname, inspectname);
return a;
}
@@ -1299,7 +1384,7 @@ call_getaddrinfo(VALUE node, VALUE service,
hints.ai_flags = NUM2INT(flags);
}
- res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
+ res = rsock_getaddrinfo(node, service, &hints, socktype_hack, timeout);
if (res == NULL)
rb_raise(rb_eSocket, "host not found");
@@ -1309,7 +1394,7 @@ call_getaddrinfo(VALUE node, VALUE service,
static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res);
static void
-init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
+init_addrinfo_getaddrinfo(VALUE self, rb_addrinfo_t *rai, VALUE node, VALUE service,
VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
VALUE inspectnode, VALUE inspectservice)
{
@@ -1323,7 +1408,7 @@ init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
OBJ_FREEZE(canonname);
}
- init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen,
+ init_addrinfo(self, rai, res->ai->ai_addr, res->ai->ai_addrlen,
NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
canonname, inspectname);
@@ -1435,7 +1520,7 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
static void
-init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
+init_unix_addrinfo(VALUE self, rb_addrinfo_t *rai, VALUE path, int socktype)
{
struct sockaddr_un un;
socklen_t len;
@@ -1451,7 +1536,7 @@ init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
len = rsock_unix_sockaddr_len(path);
- init_addrinfo(rai, (struct sockaddr *)&un, len,
+ init_addrinfo(self, rai, (struct sockaddr *)&un, len,
PF_UNIX, socktype, 0, Qnil, Qnil);
}
@@ -1555,7 +1640,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
flags |= AI_NUMERICSERV;
#endif
- init_addrinfo_getaddrinfo(rai, numericnode, service,
+ init_addrinfo_getaddrinfo(self, rai, numericnode, service,
INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
INT2NUM(flags),
nodename, service);
@@ -1567,7 +1652,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE path = rb_ary_entry(sockaddr_ary, 1);
StringValue(path);
- init_unix_addrinfo(rai, path, SOCK_STREAM);
+ init_unix_addrinfo(self, rai, path, SOCK_STREAM);
break;
}
#endif
@@ -1580,7 +1665,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
StringValue(sockaddr_arg);
sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
- init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
+ init_addrinfo(self, rai, sockaddr_ptr, sockaddr_len,
i_pfamily, i_socktype, i_protocol,
canonname, inspectname);
}
@@ -2169,7 +2254,7 @@ addrinfo_mload(VALUE self, VALUE ary)
}
DATA_PTR(self) = rai = alloc_addrinfo();
- init_addrinfo(rai, &ss.addr, len,
+ init_addrinfo(self, rai, &ss.addr, len,
pfamily, socktype, protocol,
canonname, inspectname);
return self;
@@ -2937,7 +3022,7 @@ addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
addr = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(addr) = rai = alloc_addrinfo();
- init_unix_addrinfo(rai, path, socktype);
+ init_unix_addrinfo(self, rai, path, socktype);
return addr;
}
@@ -3038,22 +3123,13 @@ free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shared **
*shared = NULL;
}
-void
-free_fast_fallback_getaddrinfo_entry(struct fast_fallback_getaddrinfo_entry **entry)
-{
- if ((*entry)->ai) {
- freeaddrinfo((*entry)->ai);
- (*entry)->ai = NULL;
- }
- *entry = NULL;
-}
-
static void *
do_fast_fallback_getaddrinfo(void *ptr)
{
struct fast_fallback_getaddrinfo_entry *entry = (struct fast_fallback_getaddrinfo_entry *)ptr;
struct fast_fallback_getaddrinfo_shared *shared = entry->shared;
- int err = 0, need_free = 0, shared_need_free = 0;
+ int err = 0, shared_need_free = 0;
+ struct addrinfo *ai = NULL;
sigset_t set;
sigemptyset(&set);
@@ -3102,14 +3178,15 @@ do_fast_fallback_getaddrinfo(void *ptr)
entry->err = errno;
entry->has_syserr = true;
}
- if (--(entry->refcount) == 0) need_free = 1;
+ if (--(entry->refcount) == 0) {
+ ai = entry->ai;
+ entry->ai = NULL;
+ }
if (--(shared->refcount) == 0) shared_need_free = 1;
}
rb_nativethread_lock_unlock(&shared->lock);
- if (need_free && entry) {
- free_fast_fallback_getaddrinfo_entry(&entry);
- }
+ if (ai) freeaddrinfo(ai);
if (shared_need_free && shared) {
free_fast_fallback_getaddrinfo_shared(&shared);
}
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 54a5381da4..2ec3ab335a 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -292,8 +292,8 @@ extern VALUE rb_eResolution;
#ifdef SOCKS
extern VALUE rb_cSOCKSSocket;
# ifndef SOCKS5
-void SOCKSinit();
-int Rconnect();
+void SOCKSinit(char *);
+int Rconnect(int, const struct sockaddr *, socklen_t);
# endif
#endif
@@ -327,8 +327,8 @@ void rb_freeaddrinfo(struct rb_addrinfo *ai);
VALUE rsock_freeaddrinfo(VALUE arg);
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
int rsock_fd_family(int fd);
-struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags);
-struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack);
+struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout);
+struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout);
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len);
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len);
@@ -355,7 +355,7 @@ int rsock_socket(int domain, int type, int proto);
int rsock_detect_cloexec(int fd);
VALUE rsock_init_sock(VALUE sock, int fd);
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
-VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE fast_fallback, VALUE test_mode_settings);
+VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout, VALUE fast_fallback, VALUE test_mode_settings);
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server);
struct rsock_send_arg {
@@ -453,6 +453,8 @@ void free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shar
# endif
#endif
+NORETURN(void rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port));
+
void rsock_init_basicsocket(void);
void rsock_init_ipsocket(void);
void rsock_init_tcpsocket(void);
@@ -507,8 +509,6 @@ extern ID tcp_fast_fallback;
const char *inet_ntop(int, const void *, char *, size_t);
#elif defined __MINGW32__
# define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
-#elif defined _MSC_VER && RUBY_MSVCRT_VERSION < 90
-const char *WSAAPI inet_ntop(int, const void *, char *, size_t);
#endif
#endif
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 8f593ca0bd..a8e5ae8119 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -965,7 +965,7 @@ sock_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, sock_sockaddr);
}
@@ -1183,7 +1183,7 @@ sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _)
norevlookup = rsock_do_not_reverse_lookup;
}
- res = rsock_getaddrinfo(host, port, &hints, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
ret = make_addrinfo(res, norevlookup);
rb_freeaddrinfo(res);
@@ -1279,7 +1279,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
/* af */
hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
- res = rsock_getaddrinfo(host, port, &hints, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
sap = res->ai->ai_addr;
salen = res->ai->ai_addrlen;
}
@@ -1335,7 +1335,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
- struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, Qnil);
VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
rb_freeaddrinfo(res);
diff --git a/ext/socket/sockssocket.c b/ext/socket/sockssocket.c
index 1031812bef..30860ea257 100644
--- a/ext/socket/sockssocket.c
+++ b/ext/socket/sockssocket.c
@@ -30,11 +30,12 @@ socks_init(VALUE sock, VALUE host, VALUE port)
static int init = 0;
if (init == 0) {
- SOCKSinit("ruby");
+ char progname[] = "ruby";
+ SOCKSinit(progname);
init = 1;
}
- return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil, Qfalse, Qnil);
+ return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil, Qnil, Qfalse, Qnil);
}
#ifdef SOCKS5
diff --git a/ext/socket/tcpserver.c b/ext/socket/tcpserver.c
index 8206fe46a9..0069f3c703 100644
--- a/ext/socket/tcpserver.c
+++ b/ext/socket/tcpserver.c
@@ -36,7 +36,7 @@ tcp_svr_init(int argc, VALUE *argv, VALUE sock)
VALUE hostname, port;
rb_scan_args(argc, argv, "011", &hostname, &port);
- return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil, Qfalse, Qnil);
+ return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil, Qnil, Qfalse, Qnil);
}
/*
diff --git a/ext/socket/tcpsocket.c b/ext/socket/tcpsocket.c
index 28527f632f..7ce536e0af 100644
--- a/ext/socket/tcpsocket.c
+++ b/ext/socket/tcpsocket.c
@@ -12,7 +12,7 @@
/*
* call-seq:
- * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, fast_fallback: true)
+ * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, open_timeout: nil, fast_fallback: true)
*
* Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
* and +local_port+ are specified, then those parameters are used on the local
@@ -35,6 +35,7 @@
*
* [:resolv_timeout] Specifies the timeout in seconds from when the hostname resolution starts.
* [:connect_timeout] This method sequentially attempts connecting to all candidate destination addresses.<br>The +connect_timeout+ specifies the timeout in seconds from the start of the connection attempt to the last candidate.<br>By default, all connection attempts continue until the timeout occurs.<br>When +fast_fallback:false+ is explicitly specified,<br>a timeout is set for each connection attempt and any connection attempt that exceeds its timeout will be canceled.
+ * [:open_timeout] Specifies the timeout in seconds from the start of the method execution.<br>If this timeout is reached while there are still addresses that have not yet been attempted for connection, no further attempts will be made.<br>If this option is specified together with other timeout options, an +ArgumentError+ will be raised.
* [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (enabled by default).
*/
static VALUE
@@ -43,29 +44,32 @@ tcp_init(int argc, VALUE *argv, VALUE sock)
VALUE remote_host, remote_serv;
VALUE local_host, local_serv;
VALUE opt;
- static ID keyword_ids[4];
- VALUE kwargs[4];
+ static ID keyword_ids[5];
+ VALUE kwargs[5];
VALUE resolv_timeout = Qnil;
VALUE connect_timeout = Qnil;
+ VALUE open_timeout = Qnil;
VALUE fast_fallback = Qnil;
VALUE test_mode_settings = Qnil;
if (!keyword_ids[0]) {
CONST_ID(keyword_ids[0], "resolv_timeout");
CONST_ID(keyword_ids[1], "connect_timeout");
- CONST_ID(keyword_ids[2], "fast_fallback");
- CONST_ID(keyword_ids[3], "test_mode_settings");
+ CONST_ID(keyword_ids[2], "open_timeout");
+ CONST_ID(keyword_ids[3], "fast_fallback");
+ CONST_ID(keyword_ids[4], "test_mode_settings");
}
rb_scan_args(argc, argv, "22:", &remote_host, &remote_serv,
&local_host, &local_serv, &opt);
if (!NIL_P(opt)) {
- rb_get_kwargs(opt, keyword_ids, 0, 4, kwargs);
+ rb_get_kwargs(opt, keyword_ids, 0, 5, kwargs);
if (kwargs[0] != Qundef) { resolv_timeout = kwargs[0]; }
if (kwargs[1] != Qundef) { connect_timeout = kwargs[1]; }
- if (kwargs[2] != Qundef) { fast_fallback = kwargs[2]; }
- if (kwargs[3] != Qundef) { test_mode_settings = kwargs[3]; }
+ if (kwargs[2] != Qundef) { open_timeout = kwargs[2]; }
+ if (kwargs[3] != Qundef) { fast_fallback = kwargs[3]; }
+ if (kwargs[4] != Qundef) { test_mode_settings = kwargs[4]; }
}
if (fast_fallback == Qnil) {
@@ -75,8 +79,8 @@ tcp_init(int argc, VALUE *argv, VALUE sock)
return rsock_init_inetsock(sock, remote_host, remote_serv,
local_host, local_serv, INET_CLIENT,
- resolv_timeout, connect_timeout, fast_fallback,
- test_mode_settings);
+ resolv_timeout, connect_timeout, open_timeout,
+ fast_fallback, test_mode_settings);
}
static VALUE
@@ -109,7 +113,7 @@ tcp_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("TCPSocket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, tcp_sockaddr);
}
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index a984933c9f..b2bc925538 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -84,7 +84,7 @@ udp_connect(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
int result = (int)rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -129,7 +129,7 @@ udp_bind(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
VALUE result = rb_ensure(udp_bind_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -212,7 +212,7 @@ udp_send(int argc, VALUE *argv, VALUE sock)
GetOpenFile(sock, arg.fptr);
arg.sarg.fd = arg.fptr->fd;
arg.sarg.flags = NUM2INT(flags);
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, Qnil);
ret = rb_ensure(udp_send_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index 31e2acee04..2ec9376074 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -42,11 +42,12 @@ unixsock_path_value(VALUE path)
}
}
#endif
+ path = rb_get_path(path);
#ifdef _WIN32
/* UNIXSocket requires UTF-8 per spec. */
path = rb_str_export_to_enc(path, rb_utf8_encoding());
#endif
- return rb_get_path(path);
+ return path;
}
VALUE
diff --git a/ext/stringio/depend b/ext/stringio/depend
index b9fba7e9fa..3a82ad0a11 100644
--- a/ext/stringio/depend
+++ b/ext/stringio/depend
@@ -138,6 +138,7 @@ stringio.o: $(hdrdir)/ruby/internal/intern/re.h
stringio.o: $(hdrdir)/ruby/internal/intern/ruby.h
stringio.o: $(hdrdir)/ruby/internal/intern/select.h
stringio.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+stringio.o: $(hdrdir)/ruby/internal/intern/set.h
stringio.o: $(hdrdir)/ruby/internal/intern/signal.h
stringio.o: $(hdrdir)/ruby/internal/intern/sprintf.h
stringio.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -171,5 +172,6 @@ stringio.o: $(hdrdir)/ruby/oniguruma.h
stringio.o: $(hdrdir)/ruby/ruby.h
stringio.o: $(hdrdir)/ruby/st.h
stringio.o: $(hdrdir)/ruby/subst.h
+stringio.o: $(hdrdir)/ruby/version.h
stringio.o: stringio.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index 2be3d4037a..cc2294a795 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -13,13 +13,14 @@
**********************************************************************/
static const char *const
-STRINGIO_VERSION = "3.1.6";
+STRINGIO_VERSION = "3.2.1.dev";
#include <stdbool.h>
#include "ruby.h"
#include "ruby/io.h"
#include "ruby/encoding.h"
+#include "ruby/version.h"
#if defined(HAVE_FCNTL_H) || defined(_WIN32)
#include <fcntl.h>
#elif defined(HAVE_SYS_FCNTL_H)
@@ -35,6 +36,19 @@ STRINGIO_VERSION = "3.1.6";
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
#endif
+static inline bool
+str_chilled_p(VALUE str)
+{
+#if (RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 4) || RUBY_API_VERSION_MAJOR >= 4
+ // Do not attempt to modify chilled strings on Ruby 3.4+
+ // RUBY_FL_USER2 == STR_CHILLED_LITERAL
+ // RUBY_FL_USER3 == STR_CHILLED_SYMBOL_TO_S
+ return FL_TEST_RAW(str, RUBY_FL_USER2 | RUBY_FL_USER3);
+#else
+ return false;
+#endif
+}
+
#ifndef HAVE_TYPE_RB_IO_MODE_T
typedef int rb_io_mode_t;
#endif
@@ -189,6 +203,18 @@ check_modifiable(struct StringIO *ptr)
}
}
+static inline bool
+outside_p(struct StringIO *ptr, long pos)
+{
+ return NIL_P(ptr->string) || pos >= RSTRING_LEN(ptr->string);
+}
+
+static inline bool
+eos_p(struct StringIO *ptr)
+{
+ return outside_p(ptr, ptr->pos);
+}
+
static VALUE
strio_s_allocate(VALUE klass)
{
@@ -199,17 +225,32 @@ strio_s_allocate(VALUE klass)
* call-seq:
* StringIO.new(string = '', mode = 'r+') -> new_stringio
*
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
- *
* Returns a new \StringIO instance formed from +string+ and +mode+;
- * see {Access Modes}[rdoc-ref:File@Access+Modes]:
+ * the instance should be closed when no longer needed:
*
- * strio = StringIO.new # => #<StringIO>
+ * strio = StringIO.new
+ * strio.string # => ""
+ * strio.closed_read? # => false
+ * strio.closed_write? # => false
* strio.close
*
- * The instance should be closed when no longer needed.
+ * If +string+ is frozen, the default +mode+ is <tt>'r'</tt>:
+ *
+ * strio = StringIO.new('foo'.freeze)
+ * strio.string # => "foo"
+ * strio.closed_read? # => false
+ * strio.closed_write? # => true
+ * strio.close
*
- * Related: StringIO.open (accepts block; closes automatically).
+ * Argument +mode+ must be a valid
+ * {Access Mode}[rdoc-ref:File@Access+Modes],
+ * which may be a string or an integer constant:
+ *
+ * StringIO.new('foo', 'w+')
+ * StringIO.new('foo', File::RDONLY)
+ *
+ * Related: StringIO.open
+ * (passes the \StringIO object to the block; closes the object automatically on block exit).
*/
static VALUE
strio_initialize(int argc, VALUE *argv, VALUE self)
@@ -344,23 +385,20 @@ strio_finalize(VALUE self)
/*
* call-seq:
- * StringIO.open(string = '', mode = 'r+') {|strio| ... }
- *
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
+ * StringIO.open(string = '', mode = 'r+') -> new_stringio
+ * StringIO.open(string = '', mode = 'r+') {|strio| ... } -> object
*
- * Creates a new \StringIO instance formed from +string+ and +mode+;
- * see {Access Modes}[rdoc-ref:File@Access+Modes].
+ * Creates new \StringIO instance by calling <tt>StringIO.new(string, mode)</tt>.
*
- * With no block, returns the new instance:
+ * With no block given, returns the new instance:
*
* strio = StringIO.open # => #<StringIO>
*
- * With a block, calls the block with the new instance
+ * With a block given, calls the block with the new instance
* and returns the block's value;
- * closes the instance on block exit.
+ * closes the instance on block exit:
*
- * StringIO.open {|strio| p strio }
- * # => #<StringIO>
+ * StringIO.open('foo') {|strio| strio.string.upcase } # => "FOO"
*
* Related: StringIO.new.
*/
@@ -386,7 +424,7 @@ strio_s_new(int argc, VALUE *argv, VALUE klass)
}
/*
- * Returns +false+. Just for compatibility to IO.
+ * Returns +false+; for compatibility with IO.
*/
static VALUE
strio_false(VALUE self)
@@ -396,7 +434,7 @@ strio_false(VALUE self)
}
/*
- * Returns +nil+. Just for compatibility to IO.
+ * Returns +nil+; for compatibility with IO.
*/
static VALUE
strio_nil(VALUE self)
@@ -406,7 +444,7 @@ strio_nil(VALUE self)
}
/*
- * Returns an object itself. Just for compatibility to IO.
+ * Returns +self+; for compatibility with IO.
*/
static VALUE
strio_self(VALUE self)
@@ -416,7 +454,7 @@ strio_self(VALUE self)
}
/*
- * Returns 0. Just for compatibility to IO.
+ * Returns 0; for compatibility with IO.
*/
static VALUE
strio_0(VALUE self)
@@ -476,7 +514,7 @@ strio_get_string(VALUE self)
* call-seq:
* string = other_string -> other_string
*
- * Assigns the underlying string as +other_string+, and sets position to zero;
+ * Replaces the stored string with +other_string+, and sets the position to zero;
* returns +other_string+:
*
* StringIO.open('foo') do |strio|
@@ -490,7 +528,7 @@ strio_get_string(VALUE self)
* "foo"
* "bar"
*
- * Related: StringIO#string (returns the underlying string).
+ * Related: StringIO#string (returns the stored string).
*/
static VALUE
strio_set_string(VALUE self, VALUE string)
@@ -511,11 +549,16 @@ strio_set_string(VALUE self, VALUE string)
* call-seq:
* close -> nil
*
- * Closes +self+ for both reading and writing.
+ * Closes +self+ for both reading and writing; returns +nil+:
*
- * Raises IOError if reading or writing is attempted.
+ * strio = StringIO.new
+ * strio.closed? # => false
+ * strio.close # => nil
+ * strio.closed? # => true
+ * strio.read # Raises IOError: not opened for reading
+ * strio.write # Raises IOError: not opened for writing
*
- * Related: StringIO#close_read, StringIO#close_write.
+ * Related: StringIO#close_read, StringIO#close_write, StringIO.closed?.
*/
static VALUE
strio_close(VALUE self)
@@ -529,9 +572,16 @@ strio_close(VALUE self)
* call-seq:
* close_read -> nil
*
- * Closes +self+ for reading; closed-write setting remains unchanged.
+ * Closes +self+ for reading;
+ * closed-write setting remains unchanged;
+ * returns +nil+:
*
- * Raises IOError if reading is attempted.
+ * strio = StringIO.new
+ * strio.closed_read? # => false
+ * strio.close_read # => nil
+ * strio.closed_read? # => true
+ * strio.closed_write? # => false
+ * strio.read # Raises IOError: not opened for reading
*
* Related: StringIO#close, StringIO#close_write.
*/
@@ -550,11 +600,16 @@ strio_close_read(VALUE self)
* call-seq:
* close_write -> nil
*
- * Closes +self+ for writing; closed-read setting remains unchanged.
+ * Closes +self+ for writing; closed-read setting remains unchanged; returns +nil+:
*
- * Raises IOError if writing is attempted.
+ * strio = StringIO.new
+ * strio.closed_write? # => false
+ * strio.close_write # => nil
+ * strio.closed_write? # => true
+ * strio.closed_read? # => false
+ * strio.write('foo') # Raises IOError: not opened for writing
*
- * Related: StringIO#close, StringIO#close_read.
+ * Related: StringIO#close, StringIO#close_read, StringIO#closed_write?.
*/
static VALUE
strio_close_write(VALUE self)
@@ -571,8 +626,16 @@ strio_close_write(VALUE self)
* call-seq:
* closed? -> true or false
*
- * Returns +true+ if +self+ is closed for both reading and writing,
- * +false+ otherwise.
+ * Returns whether +self+ is closed for both reading and writing:
+ *
+ * strio = StringIO.new
+ * strio.closed? # => false # Open for reading and writing.
+ * strio.close_read
+ * strio.closed? # => false # Still open for writing.
+ * strio.close_write
+ * strio.closed? # => true # Now closed for both.
+ *
+ * Related: StringIO.closed_read?, StringIO.closed_write?.
*/
static VALUE
strio_closed(VALUE self)
@@ -586,7 +649,14 @@ strio_closed(VALUE self)
* call-seq:
* closed_read? -> true or false
*
- * Returns +true+ if +self+ is closed for reading, +false+ otherwise.
+ * Returns whether +self+ is closed for reading:
+ *
+ * strio = StringIO.new
+ * strio.closed_read? # => false
+ * strio.close_read
+ * strio.closed_read? # => true
+ *
+ * Related: StringIO#closed?, StringIO#closed_write?, StringIO#close_read.
*/
static VALUE
strio_closed_read(VALUE self)
@@ -600,7 +670,14 @@ strio_closed_read(VALUE self)
* call-seq:
* closed_write? -> true or false
*
- * Returns +true+ if +self+ is closed for writing, +false+ otherwise.
+ * Returns whether +self+ is closed for writing:
+ *
+ * strio = StringIO.new
+ * strio.closed_write? # => false
+ * strio.close_write
+ * strio.closed_write? # => true
+ *
+ * Related: StringIO#close_write, StringIO#closed?, StringIO#closed_read?.
*/
static VALUE
strio_closed_write(VALUE self)
@@ -614,19 +691,26 @@ static struct StringIO *
strio_to_read(VALUE self)
{
struct StringIO *ptr = readable(self);
- if (NIL_P(ptr->string)) return NULL;
- if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
- return NULL;
+ if (eos_p(ptr)) return NULL;
+ return ptr;
}
/*
* call-seq:
* eof? -> true or false
*
- * Returns +true+ if positioned at end-of-stream, +false+ otherwise;
- * see {Position}[rdoc-ref:IO@Position].
+ * Returns whether +self+ is positioned at end-of-stream:
+ *
+ * strio = StringIO.new('foo')
+ * strio.pos # => 0
+ * strio.eof? # => false
+ * strio.read # => "foo"
+ * strio.pos # => 3
+ * strio.eof? # => true
+ * strio.close_read
+ * strio.eof? # Raises IOError: not opened for reading
*
- * Raises IOError if the stream is not opened for reading.
+ * Related: StringIO#pos.
*/
static VALUE
strio_eof(VALUE self)
@@ -663,7 +747,7 @@ strio_copy(VALUE copy, VALUE orig)
* lineno -> current_line_number
*
* Returns the current line number in +self+;
- * see {Line Number}[rdoc-ref:IO@Line+Number].
+ * see {Line Number}[rdoc-ref:StringIO@Line+Number].
*/
static VALUE
strio_get_lineno(VALUE self)
@@ -676,7 +760,7 @@ strio_get_lineno(VALUE self)
* lineno = new_line_number -> new_line_number
*
* Sets the current line number in +self+ to the given +new_line_number+;
- * see {Line Number}[rdoc-ref:IO@Line+Number].
+ * see {Line Number}[rdoc-ref:StringIO@Line+Number].
*/
static VALUE
strio_set_lineno(VALUE self, VALUE lineno)
@@ -690,7 +774,7 @@ strio_set_lineno(VALUE self, VALUE lineno)
* binmode -> self
*
* Sets the data mode in +self+ to binary mode;
- * see {Data Mode}[rdoc-ref:File@Data+Mode].
+ * see {Data Mode}[rdoc-ref:StringIO@Data+Mode].
*
*/
static VALUE
@@ -751,7 +835,7 @@ strio_reopen(int argc, VALUE *argv, VALUE self)
* pos -> stream_position
*
* Returns the current position (in bytes);
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:StringIO@Position].
*/
static VALUE
strio_get_pos(VALUE self)
@@ -764,7 +848,7 @@ strio_get_pos(VALUE self)
* pos = new_position -> new_position
*
* Sets the current position (in bytes);
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:StringIO@Position].
*/
static VALUE
strio_set_pos(VALUE self, VALUE pos)
@@ -799,9 +883,9 @@ strio_rewind(VALUE self)
* call-seq:
* seek(offset, whence = SEEK_SET) -> 0
*
- * Sets the current position to the given integer +offset+ (in bytes),
+ * Sets the position to the given integer +offset+ (in bytes),
* with respect to a given constant +whence+;
- * see {Position}[rdoc-ref:IO@Position].
+ * see {IO#seek}[rdoc-ref:IO#seek].
*/
static VALUE
strio_seek(int argc, VALUE *argv, VALUE self)
@@ -823,7 +907,11 @@ strio_seek(int argc, VALUE *argv, VALUE self)
offset = ptr->pos;
break;
case 2:
- offset = RSTRING_LEN(ptr->string);
+ if (NIL_P(ptr->string)) {
+ offset = 0;
+ } else {
+ offset = RSTRING_LEN(ptr->string);
+ }
break;
default:
error_inval("invalid whence");
@@ -856,10 +944,9 @@ strio_get_sync(VALUE self)
* call-seq:
* each_byte {|byte| ... } -> self
*
- * With a block given, calls the block with each remaining byte in the stream;
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
+ * :include: stringio/each_byte.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_char, StringIO#each_codepoint, StringIO#each_line.
*/
static VALUE
strio_each_byte(VALUE self)
@@ -877,10 +964,10 @@ strio_each_byte(VALUE self)
/*
* call-seq:
- * getc -> character or nil
+ * getc -> character, byte, or nil
+ *
+ * :include: stringio/getc.rdoc
*
- * Reads and returns the next character from the stream;
- * see {Character IO}[rdoc-ref:IO@Character+IO].
*/
static VALUE
strio_getc(VALUE self)
@@ -892,7 +979,7 @@ strio_getc(VALUE self)
int len;
char *p;
- if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
+ if (eos_p(ptr)) {
return Qnil;
}
p = RSTRING_PTR(str)+pos;
@@ -903,17 +990,17 @@ strio_getc(VALUE self)
/*
* call-seq:
- * getbyte -> byte or nil
+ * getbyte -> integer or nil
+ *
+ * :include: stringio/getbyte.rdoc
*
- * Reads and returns the next 8-bit byte from the stream;
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
*/
static VALUE
strio_getbyte(VALUE self)
{
struct StringIO *ptr = readable(self);
int c;
- if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
+ if (eos_p(ptr)) {
return Qnil;
}
c = RSTRING_PTR(ptr->string)[ptr->pos++];
@@ -1082,12 +1169,11 @@ strio_readbyte(VALUE self)
/*
* call-seq:
- * each_char {|c| ... } -> self
+ * each_char {|char| ... } -> self
*
- * With a block given, calls the block with each remaining character in the stream;
- * see {Character IO}[rdoc-ref:IO@Character+IO].
+ * :include: stringio/each_char.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_byte, StringIO#each_codepoint, StringIO#each_line.
*/
static VALUE
strio_each_char(VALUE self)
@@ -1106,10 +1192,9 @@ strio_each_char(VALUE self)
* call-seq:
* each_codepoint {|codepoint| ... } -> self
*
- * With a block given, calls the block with each remaining codepoint in the stream;
- * see {Codepoint IO}[rdoc-ref:IO@Codepoint+IO].
+ * :include: stringio/each_codepoint.rdoc
*
- * With no block given, returns an enumerator.
+ * Related: StringIO#each_byte, StringIO#each_char, StringIO#each_line.
*/
static VALUE
strio_each_codepoint(VALUE self)
@@ -1343,9 +1428,8 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
* gets(limit, chomp: false) -> string or nil
* gets(sep, limit, chomp: false) -> string or nil
*
- * Reads and returns a line from the stream;
- * assigns the return value to <tt>$_</tt>;
- * see {Line IO}[rdoc-ref:IO@Line+IO].
+ * :include: stringio/gets.rdoc
+ *
*/
static VALUE
strio_gets(int argc, VALUE *argv, VALUE self)
@@ -1382,15 +1466,15 @@ strio_readline(int argc, VALUE *argv, VALUE self)
}
/*
+ * :markup: markdown
+ *
* call-seq:
* each_line(sep = $/, chomp: false) {|line| ... } -> self
* each_line(limit, chomp: false) {|line| ... } -> self
* each_line(sep, limit, chomp: false) {|line| ... } -> self
*
- * Calls the block with each remaining line read from the stream;
- * does nothing if already at end-of-file;
- * returns +self+.
- * See {Line IO}[rdoc-ref:IO@Line+IO].
+ * :include: stringio/each_line.md
+ *
*/
static VALUE
strio_each(int argc, VALUE *argv, VALUE self)
@@ -1531,9 +1615,10 @@ strio_write(VALUE self, VALUE str)
/*
* call-seq:
- * strio.putc(obj) -> obj
+ * putc(object) -> object
+ *
+ * :include: stringio/putc.rdoc
*
- * See IO#putc.
*/
static VALUE
strio_putc(VALUE self, VALUE ch)
@@ -1565,9 +1650,10 @@ strio_putc(VALUE self, VALUE ch)
/*
* call-seq:
- * strio.read([length [, outbuf]]) -> string, outbuf, or nil
+ * read(maxlen = nil, out_string = nil) → new_string, out_string, or nil
+ *
+ * :include: stringio/read.rdoc
*
- * See IO#read.
*/
static VALUE
strio_read(int argc, VALUE *argv, VALUE self)
@@ -1591,10 +1677,9 @@ strio_read(int argc, VALUE *argv, VALUE self)
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
- if (len > 0 &&
- (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
+ if (eos_p(ptr)) {
if (!NIL_P(str)) rb_str_resize(str, 0);
- return Qnil;
+ return len > 0 ? Qnil : rb_str_new(0, 0);
}
binary = 1;
break;
@@ -1640,10 +1725,10 @@ strio_read(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * pread(maxlen, offset) -> string
- * pread(maxlen, offset, out_string) -> string
+ * pread(maxlen, offset, out_string = nil) -> new_string or out_string
+ *
+ * :include: stringio/pread.rdoc
*
- * See IO#pread.
*/
static VALUE
strio_pread(int argc, VALUE *argv, VALUE self)
@@ -1670,7 +1755,7 @@ strio_pread(int argc, VALUE *argv, VALUE self)
struct StringIO *ptr = readable(self);
- if (offset >= RSTRING_LEN(ptr->string)) {
+ if (outside_p(ptr, offset)) {
rb_eof_error();
}
@@ -1760,10 +1845,10 @@ strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * strio.length -> integer
- * strio.size -> integer
+ * size -> integer
+ *
+ * :include: stringio/size.rdoc
*
- * Returns the size of the buffer string.
*/
static VALUE
strio_size(VALUE self)
@@ -1801,12 +1886,20 @@ strio_truncate(VALUE self, VALUE len)
}
/*
- * call-seq:
- * strio.external_encoding => encoding
+ * call-seq:
+ * external_encoding -> encoding or nil
+ *
+ * Returns an Encoding object that represents the encoding of the string;
+ * see {Encodings}[rdoc-ref:StringIO@Encodings]:
+ *
+ * strio = StringIO.new('foo')
+ * strio.external_encoding # => #<Encoding:UTF-8>
+ *
+ * Returns +nil+ if +self+ has no string and is in write mode:
+ *
+ * strio = StringIO.new(nil, 'w+')
+ * strio.external_encoding # => nil
*
- * Returns the Encoding object that represents the encoding of the file.
- * If the stream is write mode and no encoding is specified, returns
- * +nil+.
*/
static VALUE
@@ -1818,10 +1911,9 @@ strio_external_encoding(VALUE self)
/*
* call-seq:
- * strio.internal_encoding => encoding
+ * internal_encoding -> nil
*
- * Returns the Encoding of the internal string if conversion is
- * specified. Otherwise returns +nil+.
+ * Returns +nil+; for compatibility with IO.
*/
static VALUE
@@ -1864,7 +1956,7 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
}
}
ptr->enc = enc;
- if (!NIL_P(ptr->string) && WRITABLE(self)) {
+ if (!NIL_P(ptr->string) && WRITABLE(self) && !str_chilled_p(ptr->string)) {
rb_enc_associate(ptr->string, enc);
}
@@ -1890,16 +1982,9 @@ strio_set_encoding_by_bom(VALUE self)
}
/*
- * \IO streams for strings, with access similar to
- * {IO}[rdoc-ref:IO];
- * see {IO}[rdoc-ref:IO].
- *
- * === About the Examples
- *
- * Examples on this page assume that \StringIO has been required:
- *
- * require 'stringio'
+ * :markup: markdown
*
+ * :include: stringio/stringio.md
*/
void
Init_stringio(void)
@@ -1907,7 +1992,7 @@ Init_stringio(void)
#undef rb_intern
#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
+ rb_ext_ractor_safe(true);
#endif
VALUE StringIO = rb_define_class("StringIO", rb_cObject);
@@ -1999,7 +2084,9 @@ Init_stringio(void)
rb_define_method(StringIO, "set_encoding_by_bom", strio_set_encoding_by_bom, 0);
{
+ /* :stopdoc: */
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
+ /* :startdoc: */
rb_define_method(mReadable, "readchar", strio_readchar, 0);
rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
rb_define_method(mReadable, "readline", strio_readline, -1);
@@ -2009,7 +2096,9 @@ Init_stringio(void)
rb_include_module(StringIO, mReadable);
}
{
+ /* :stopdoc: */
VALUE mWritable = rb_define_module_under(rb_cIO, "generic_writable");
+ /* :startdoc: */
rb_define_method(mWritable, "<<", strio_addstr, 1);
rb_define_method(mWritable, "print", strio_print, -1);
rb_define_method(mWritable, "printf", strio_printf, -1);
diff --git a/ext/strscan/depend b/ext/strscan/depend
index 8dbae206d4..b40a025230 100644
--- a/ext/strscan/depend
+++ b/ext/strscan/depend
@@ -138,6 +138,7 @@ strscan.o: $(hdrdir)/ruby/internal/intern/re.h
strscan.o: $(hdrdir)/ruby/internal/intern/ruby.h
strscan.o: $(hdrdir)/ruby/internal/intern/select.h
strscan.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+strscan.o: $(hdrdir)/ruby/internal/intern/set.h
strscan.o: $(hdrdir)/ruby/internal/intern/signal.h
strscan.o: $(hdrdir)/ruby/internal/intern/sprintf.h
strscan.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/strscan/extconf.rb b/ext/strscan/extconf.rb
index bd65606a4e..d2e9343cbc 100644
--- a/ext/strscan/extconf.rb
+++ b/ext/strscan/extconf.rb
@@ -2,8 +2,9 @@
require 'mkmf'
if RUBY_ENGINE == 'ruby'
$INCFLAGS << " -I$(top_srcdir)" if $extmk
- have_func("onig_region_memsize", "ruby.h")
- have_func("rb_reg_onig_match", "ruby.h")
+ have_func("onig_region_memsize(NULL)")
+ have_func("rb_reg_onig_match", "ruby/re.h")
+ have_func("rb_deprecate_constant")
create_makefile 'strscan'
else
File.write('Makefile', dummy_makefile("").join)
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index c6432fcd5b..935fce19df 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -22,7 +22,15 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
#include <stdbool.h>
-#define STRSCAN_VERSION "3.1.3"
+#define STRSCAN_VERSION "3.1.7.dev"
+
+
+#ifdef HAVE_RB_DEPRECATE_CONSTANT
+/* In ruby 3.0, defined but exposed in external headers */
+extern void rb_deprecate_constant(VALUE mod, const char *name);
+#else
+# define rb_deprecate_constant(mod, name) ((void)0)
+#endif
/* =======================================================================
Data Type Definitions
@@ -30,7 +38,6 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
static VALUE StringScanner;
static VALUE ScanError;
-static ID id_byteslice;
static int usascii_encindex, utf8_encindex, binary_encindex;
@@ -97,7 +104,6 @@ static VALUE strscan_init_copy _((VALUE vself, VALUE vorig));
static VALUE strscan_s_mustc _((VALUE self));
static VALUE strscan_terminate _((VALUE self));
-static VALUE strscan_clear _((VALUE self));
static VALUE strscan_get_string _((VALUE self));
static VALUE strscan_set_string _((VALUE self, VALUE str));
static VALUE strscan_concat _((VALUE self, VALUE str));
@@ -119,14 +125,11 @@ static VALUE strscan_search_full _((VALUE self, VALUE re,
static void adjust_registers_to_matched _((struct strscanner *p));
static VALUE strscan_getch _((VALUE self));
static VALUE strscan_get_byte _((VALUE self));
-static VALUE strscan_getbyte _((VALUE self));
static VALUE strscan_peek _((VALUE self, VALUE len));
-static VALUE strscan_peep _((VALUE self, VALUE len));
static VALUE strscan_scan_base10_integer _((VALUE self));
static VALUE strscan_unscan _((VALUE self));
static VALUE strscan_bol_p _((VALUE self));
static VALUE strscan_eos_p _((VALUE self));
-static VALUE strscan_empty_p _((VALUE self));
static VALUE strscan_rest_p _((VALUE self));
static VALUE strscan_matched_p _((VALUE self));
static VALUE strscan_matched _((VALUE self));
@@ -209,7 +212,7 @@ strscan_memsize(const void *ptr)
static const rb_data_type_t strscanner_type = {
"StringScanner",
{strscan_mark, strscan_free, strscan_memsize},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
static VALUE
@@ -273,7 +276,7 @@ strscan_initialize(int argc, VALUE *argv, VALUE self)
p->fixed_anchor_p = false;
}
StringValue(str);
- p->str = str;
+ RB_OBJ_WRITE(self, &p->str, str);
return self;
}
@@ -303,7 +306,7 @@ strscan_init_copy(VALUE vself, VALUE vorig)
orig = check_strscan(vorig);
if (self != orig) {
self->flags = orig->flags;
- self->str = orig->str;
+ RB_OBJ_WRITE(vself, &self->str, orig->str);
self->prev = orig->prev;
self->curr = orig->curr;
if (rb_reg_region_copy(&self->regs, &orig->regs))
@@ -386,21 +389,6 @@ strscan_terminate(VALUE self)
}
/*
- * call-seq:
- * clear -> self
- *
- * This method is obsolete; use the equivalent method StringScanner#terminate.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_clear(VALUE self)
-{
- rb_warning("StringScanner#clear is obsolete; use #terminate instead");
- return strscan_terminate(self);
-}
-
-/*
* :markup: markdown
* :include: strscan/link_refs.txt
*
@@ -467,7 +455,7 @@ strscan_set_string(VALUE self, VALUE str)
struct strscanner *p = check_strscan(self);
StringValue(str);
- p->str = str;
+ RB_OBJ_WRITE(self, &p->str, str);
p->curr = 0;
CLEAR_MATCH_STATUS(p);
return str;
@@ -712,7 +700,7 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
if (RB_TYPE_P(pattern, T_REGEXP)) {
OnigPosition ret;
- p->regex = pattern;
+ RB_OBJ_WRITE(self, &p->regex, pattern);
ret = rb_reg_onig_match(p->regex,
p->str,
headonly ? strscan_match : strscan_search,
@@ -1219,22 +1207,6 @@ strscan_get_byte(VALUE self)
}
/*
- * call-seq:
- * getbyte
- *
- * Equivalent to #get_byte.
- * This method is obsolete; use #get_byte instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_getbyte(VALUE self)
-{
- rb_warning("StringScanner#getbyte is obsolete; use #get_byte instead");
- return strscan_get_byte(self);
-}
-
-/*
* :markup: markdown
* :include: strscan/link_refs.txt
*
@@ -1269,22 +1241,6 @@ strscan_peek(VALUE self, VALUE vlen)
return extract_beg_len(p, p->curr, len);
}
-/*
- * call-seq:
- * peep
- *
- * Equivalent to #peek.
- * This method is obsolete; use #peek instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_peep(VALUE self, VALUE vlen)
-{
- rb_warning("StringScanner#peep is obsolete; use #peek instead");
- return strscan_peek(self, vlen);
-}
-
static VALUE
strscan_parse_integer(struct strscanner *p, int base, long len)
{
@@ -1322,11 +1278,12 @@ strscan_must_ascii_compat(VALUE str)
rb_must_asciicompat(str);
}
+/* :nodoc: */
static VALUE
strscan_scan_base10_integer(VALUE self)
{
char *ptr;
- long len = 0;
+ long len = 0, remaining_len;
struct strscanner *p;
GET_SCANNER(self, p);
@@ -1336,7 +1293,7 @@ strscan_scan_base10_integer(VALUE self)
ptr = CURPTR(p);
- long remaining_len = S_RESTLEN(p);
+ remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
@@ -1359,11 +1316,12 @@ strscan_scan_base10_integer(VALUE self)
return strscan_parse_integer(p, 10, len);
}
+/* :nodoc: */
static VALUE
strscan_scan_base16_integer(VALUE self)
{
char *ptr;
- long len = 0;
+ long len = 0, remaining_len;
struct strscanner *p;
GET_SCANNER(self, p);
@@ -1373,7 +1331,7 @@ strscan_scan_base16_integer(VALUE self)
ptr = CURPTR(p);
- long remaining_len = S_RESTLEN(p);
+ remaining_len = S_RESTLEN(p);
if (remaining_len <= 0) {
return Qnil;
@@ -1526,26 +1484,9 @@ strscan_eos_p(VALUE self)
/*
* call-seq:
- * empty?
- *
- * Equivalent to #eos?.
- * This method is obsolete, use #eos? instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_empty_p(VALUE self)
-{
- rb_warning("StringScanner#empty? is obsolete; use #eos? instead");
- return strscan_eos_p(self);
-}
-
-/*
- * call-seq:
* rest?
*
* Returns true if and only if there is more data in the string. See #eos?.
- * This method is obsolete; use #eos? instead.
*
* s = StringScanner.new('test string')
* # These two are opposites
@@ -1673,7 +1614,7 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
(const unsigned char* )name_end,
regs);
if (num >= 1) {
- return num;
+ return num;
}
}
rb_enc_raise(enc, rb_eIndexError, "undefined group name reference: %.*s",
@@ -2053,22 +1994,6 @@ strscan_rest_size(VALUE self)
return INT2FIX(i);
}
-/*
- * call-seq:
- * restsize
- *
- * <tt>s.restsize</tt> is equivalent to <tt>s.rest_size</tt>.
- * This method is obsolete; use #rest_size instead.
- */
-
- /* :nodoc: */
-static VALUE
-strscan_restsize(VALUE self)
-{
- rb_warning("StringScanner#restsize is obsolete; use #rest_size instead");
- return strscan_rest_size(self);
-}
-
#define INSPECT_LENGTH 5
/*
@@ -2211,7 +2136,10 @@ named_captures_iter(const OnigUChar *name,
VALUE value = RUBY_Qnil;
int i;
for (i = 0; i < back_num; i++) {
- value = strscan_aref(data->self, INT2NUM(back_refs[i]));
+ VALUE v = strscan_aref(data->self, INT2NUM(back_refs[i]));
+ if (!RB_NIL_P(v)) {
+ value = v;
+ }
}
rb_hash_aset(data->captures, key, value);
return 0;
@@ -2265,6 +2193,13 @@ strscan_named_captures(VALUE self)
======================================================================= */
/*
+ * Document-class: StringScanner::Error
+ *
+ * The error class for StringScanner.
+ * See StringScanner#unscan.
+ */
+
+/*
* Document-class: StringScanner
*
* :markup: markdown
@@ -2284,8 +2219,6 @@ Init_strscan(void)
ID id_scanerr = rb_intern("ScanError");
VALUE tmp;
- id_byteslice = rb_intern("byteslice");
-
usascii_encindex = rb_usascii_encindex();
utf8_encindex = rb_utf8_encindex();
binary_encindex = rb_ascii8bit_encindex();
@@ -2294,6 +2227,7 @@ Init_strscan(void)
ScanError = rb_define_class_under(StringScanner, "Error", rb_eStandardError);
if (!rb_const_defined(rb_cObject, id_scanerr)) {
rb_const_set(rb_cObject, id_scanerr, ScanError);
+ rb_deprecate_constant(rb_cObject, "ScanError");
}
tmp = rb_str_new2(STRSCAN_VERSION);
rb_obj_freeze(tmp);
@@ -2301,6 +2235,7 @@ Init_strscan(void)
tmp = rb_str_new2("$Id$");
rb_obj_freeze(tmp);
rb_const_set(StringScanner, rb_intern("Id"), tmp);
+ rb_deprecate_constant(StringScanner, "Id");
rb_define_alloc_func(StringScanner, strscan_s_allocate);
rb_define_private_method(StringScanner, "initialize", strscan_initialize, -1);
@@ -2308,7 +2243,6 @@ Init_strscan(void)
rb_define_singleton_method(StringScanner, "must_C_version", strscan_s_mustc, 0);
rb_define_method(StringScanner, "reset", strscan_reset, 0);
rb_define_method(StringScanner, "terminate", strscan_terminate, 0);
- rb_define_method(StringScanner, "clear", strscan_clear, 0);
rb_define_method(StringScanner, "string", strscan_get_string, 0);
rb_define_method(StringScanner, "string=", strscan_set_string, 1);
rb_define_method(StringScanner, "concat", strscan_concat, 1);
@@ -2333,11 +2267,9 @@ Init_strscan(void)
rb_define_method(StringScanner, "getch", strscan_getch, 0);
rb_define_method(StringScanner, "get_byte", strscan_get_byte, 0);
- rb_define_method(StringScanner, "getbyte", strscan_getbyte, 0);
rb_define_method(StringScanner, "scan_byte", strscan_scan_byte, 0);
rb_define_method(StringScanner, "peek", strscan_peek, 1);
rb_define_method(StringScanner, "peek_byte", strscan_peek_byte, 0);
- rb_define_method(StringScanner, "peep", strscan_peep, 1);
rb_define_private_method(StringScanner, "scan_base10_integer", strscan_scan_base10_integer, 0);
rb_define_private_method(StringScanner, "scan_base16_integer", strscan_scan_base16_integer, 0);
@@ -2347,7 +2279,6 @@ Init_strscan(void)
rb_define_method(StringScanner, "beginning_of_line?", strscan_bol_p, 0);
rb_alias(StringScanner, rb_intern("bol?"), rb_intern("beginning_of_line?"));
rb_define_method(StringScanner, "eos?", strscan_eos_p, 0);
- rb_define_method(StringScanner, "empty?", strscan_empty_p, 0);
rb_define_method(StringScanner, "rest?", strscan_rest_p, 0);
rb_define_method(StringScanner, "matched?", strscan_matched_p, 0);
@@ -2362,7 +2293,6 @@ Init_strscan(void)
rb_define_method(StringScanner, "rest", strscan_rest, 0);
rb_define_method(StringScanner, "rest_size", strscan_rest_size, 0);
- rb_define_method(StringScanner, "restsize", strscan_restsize, 0);
rb_define_method(StringScanner, "inspect", strscan_inspect, 0);
diff --git a/ext/win32/lib/win32/registry.rb b/ext/win32/lib/win32/registry.rb
index d0cbb6afcf..734d6987a2 100644
--- a/ext/win32/lib/win32/registry.rb
+++ b/ext/win32/lib/win32/registry.rb
@@ -2,83 +2,74 @@
require 'fiddle/import'
module Win32
-
-=begin rdoc
-= Win32 Registry
-
-win32/registry is registry accessor library for Win32 platform.
-It uses importer to call Win32 Registry APIs.
-
-== example
- Win32::Registry::HKEY_CURRENT_USER.open('SOFTWARE\foo') do |reg|
- value = reg['foo'] # read a value
- value = reg['foo', Win32::Registry::REG_SZ] # read a value with type
- type, value = reg.read('foo') # read a value
- reg['foo'] = 'bar' # write a value
- reg['foo', Win32::Registry::REG_SZ] = 'bar' # write a value with type
- reg.write('foo', Win32::Registry::REG_SZ, 'bar') # write a value
-
- reg.each_value { |name, type, data| ... } # Enumerate values
- reg.each_key { |key, wtime| ... } # Enumerate subkeys
-
- reg.delete_value(name) # Delete a value
- reg.delete_key(name) # Delete a subkey
- reg.delete_key(name, true) # Delete a subkey recursively
- end
-
-= Reference
-
-== Win32::Registry class
-
---- info
-
---- num_keys
-
---- max_key_length
-
---- num_values
-
---- max_value_name_length
-
---- max_value_length
-
---- descriptor_length
-
---- wtime
- Returns an item of key information.
-
-=== constants
---- HKEY_CLASSES_ROOT
-
---- HKEY_CURRENT_USER
-
---- HKEY_LOCAL_MACHINE
-
---- HKEY_PERFORMANCE_DATA
-
---- HKEY_CURRENT_CONFIG
-
---- HKEY_DYN_DATA
-
- Win32::Registry object whose key is predefined key.
-For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/predefined_keys.asp] article.
-
-=end rdoc
-
+ # :stopdoc:
WCHAR = Encoding::UTF_16LE
WCHAR_NUL = "\0".encode(WCHAR).freeze
WCHAR_CR = "\r".encode(WCHAR).freeze
WCHAR_SIZE = WCHAR_NUL.bytesize
LOCALE = Encoding::UTF_8
+ # :startdoc:
+
+ # win32/registry is registry accessor library for Win32 platform.
+ # It uses importer to call Win32 Registry APIs.
+ #
+ # == example
+ # Win32::Registry::HKEY_CURRENT_USER.open('SOFTWARE\foo') do |reg|
+ # value = reg['foo'] # read a value
+ # value = reg['foo', Win32::Registry::REG_SZ] # read a value with type
+ # type, value = reg.read('foo') # read a value
+ # reg['foo'] = 'bar' # write a value
+ # reg['foo', Win32::Registry::REG_SZ] = 'bar' # write a value with type
+ # reg.write('foo', Win32::Registry::REG_SZ, 'bar') # write a value
+ #
+ # reg.each_value { |name, type, data| ... } # Enumerate values
+ # reg.each_key { |key, wtime| ... } # Enumerate subkeys
+ #
+ # reg.delete_value(name) # Delete a value
+ # reg.delete_key(name) # Delete a subkey
+ # reg.delete_key(name, true) # Delete a subkey recursively
+ # end
+ #
+ # == Predefined keys
+ #
+ # * +HKEY_CLASSES_ROOT+
+ # * +HKEY_CURRENT_USER+
+ # * +HKEY_LOCAL_MACHINE+
+ # * +HKEY_PERFORMANCE_DATA+
+ # * +HKEY_CURRENT_CONFIG+
+ # * +HKEY_DYN_DATA+
+ #
+ # Win32::Registry object whose key is predefined key.
+ # For detail, see the article[https://learn.microsoft.com/en-us/windows/win32/sysinfo/predefined-keys].
+ #
+ # == Value types
+ #
+ # * +REG_NONE+
+ # * +REG_SZ+
+ # * +REG_EXPAND_SZ+
+ # * +REG_BINARY+
+ # * +REG_DWORD+
+ # * +REG_DWORD_BIG_ENDIAN+
+ # * +REG_LINK+
+ # * +REG_MULTI_SZ+
+ # * +REG_RESOURCE_LIST+
+ # * +REG_FULL_RESOURCE_DESCRIPTOR+
+ # * +REG_RESOURCE_REQUIREMENTS_LIST+
+ # * +REG_QWORD+
+ #
+ # For detail, see the article[https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types].
+ #
class Registry
+ # :stopdoc:
+
#
# For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/registry.asp].
#
# --- HKEY_*
#
- # Predefined key ((*handle*)).
+ # Predefined key *handle*.
# These are Integer, not Win32::Registry.
#
# --- REG_*
@@ -100,6 +91,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# If the key is created newly or opened existing key.
# See also Registry#disposition method.
module Constants
+ # :stopdoc:
HKEY_CLASSES_ROOT = 0x80000000
HKEY_CURRENT_USER = 0x80000001
HKEY_LOCAL_MACHINE = 0x80000002
@@ -115,7 +107,6 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
REG_EXPAND_SZ = 2
REG_BINARY = 3
REG_DWORD = 4
- REG_DWORD_LITTLE_ENDIAN = 4
REG_DWORD_BIG_ENDIAN = 5
REG_LINK = 6
REG_MULTI_SZ = 7
@@ -163,16 +154,23 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end
include Constants
include Enumerable
+ # :startdoc:
#
# Error
#
class Error < ::StandardError
+ # :stopdoc:
module Kernel32
extend Fiddle::Importer
dlload "kernel32.dll"
end
FormatMessageW = Kernel32.extern "int FormatMessageW(int, void *, int, int, void *, int, void *)", :stdcall
+ # :startdoc:
+
+ # new(code) -> error object
+ #
+ # Initializes the message for Win32 API error +code+.
def initialize(code)
@code = code
buff = WCHAR_NUL * 1024
@@ -190,6 +188,8 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end
super msg
end
+
+ # Win32 API error code.
attr_reader :code
end
@@ -197,6 +197,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# Predefined Keys
#
class PredefinedKey < Registry
+ # :stopdoc:
def initialize(hkey, keyname)
@hkey = Fiddle::Pointer.new(hkey)
@parent = nil
@@ -224,6 +225,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# Win32 APIs
#
module API
+ # :stopdoc:
include Constants
extend Fiddle::Importer
dlload "advapi32.dll"
@@ -367,12 +369,14 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
unpackdw(secdescs), unpackqw(wtime) ]
end
end
+ # :startdoc:
#
- # Replace %\w+% into the environment value of what is contained between the %'s
+ # Replace <tt>%</tt>-enclosed substrings in +str+ into the
+ # environment value of what is contained between the <tt>%</tt>s.
# This method is used for REG_EXPAND_SZ.
#
- # For detail, see expandEnvironmentStrings[http://msdn.microsoft.com/library/en-us/sysinfo/base/expandenvironmentstrings.asp] \Win32 \API.
+ # For detail, see ExpandEnvironmentStrings[https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-expandenvironmentstringsw] \Win32 \API.
#
def self.expand_environ(str)
str.gsub(Regexp.compile("%([^%]+)%".encode(str.encoding))) {
@@ -392,21 +396,21 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end.freeze
#
- # Convert registry type value to readable string.
+ # Convert registry type value +type+ to readable string.
#
def self.type2name(type)
@@type2name[type] || type.to_s
end
#
- # Convert 64-bit FILETIME integer into Time object.
+ # Convert 64-bit FILETIME integer +wtime+ into Time object.
#
def self.wtime2time(wtime)
Time.at((wtime - 116444736000000000) / 10000000)
end
#
- # Convert Time object or Integer object into 64-bit FILETIME.
+ # Convert Time object or Integer object +time+ into 64-bit FILETIME.
#
def self.time2wtime(time)
time.to_i * 10000000 + 116444736000000000
@@ -418,16 +422,19 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
private_class_method :new
#
- # --- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
+ # call-seq:
+ # open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
+ # open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED) { |reg| ... }
#
- # --- Registry.open(key, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED) { |reg| ... }
+ # Open the registry key +subkey+ under +key+.
+ # +key+ is Win32::Registry object of parent key.
+ # You can use {predefined key}[rdoc-ref:Win32::Registry@Predefined+keys] +HKEY_+*.
+ # +desired+ and +opt+ is access mask and key option.
#
- # Open the registry key subkey under key.
- # key is Win32::Registry object of parent key.
- # You can use predefined key HKEY_* (see Constants)
- # desired and opt is access mask and key option.
# For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/regopenkeyex.asp].
- # If block is given, the key is closed automatically.
+ #
+ # If block is given, the key +reg+ is yielded and closed
+ # automatically after the block exists.
def self.open(hkey, subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED)
subkey = subkey.chomp('\\')
newkey = API.OpenKey(hkey.instance_variable_get(:@hkey), subkey, opt, desired)
@@ -444,17 +451,19 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end
#
- # --- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
- #
- # --- Registry.create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED) { |reg| ... }
+ # call-seq:
+ # create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
+ # create(key, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED) { |reg| ... }
#
- # Create or open the registry key subkey under key.
- # You can use predefined key HKEY_* (see Constants)
+ # Create or open the registry key +subkey+ under +key+.
+ # You can use {predefined key}[rdoc-ref:Win32::Registry@Predefined+keys] +HKEY_+*.
+ # +desired+ and +opt+ is access mask and key option.
#
- # If subkey is already exists, key is opened and Registry#created?
+ # If +subkey+ is already exists, key is opened and Registry#created?
# method will return false.
#
- # If block is given, the key is closed automatically.
+ # If block is given, the key +reg+ is yielded and closed
+ # automatically after the block exists.
#
def self.create(hkey, subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED)
newkey, disp = API.CreateKey(hkey.instance_variable_get(:@hkey), subkey, opt, desired)
@@ -476,7 +485,9 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
@@final = proc { |hkey| proc { API.CloseKey(hkey[0]) if hkey[0] } }
#
- # initialize
+ # :nodoc:
+ #
+ # Use self.open, self.create, #open and #create.
#
def initialize(hkey, parent, keyname, disposition)
@hkey = Fiddle::Pointer.new(hkey)
@@ -487,7 +498,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
ObjectSpace.define_finalizer self, @@final.call(@hkeyfinal)
end
- # Win32::Registry object of parent key, or nil if predefeined key.
+ # Win32::Registry object of parent key, or nil if predefined key.
attr_reader :parent
# Same as subkey value of Registry.open or
# Registry.create method.
@@ -501,7 +512,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end
#
- # Returns if key is created ((*newly*)).
+ # Returns +true+ if key is created *newly*.
# (see Registry.create) -- basically you call create
# then when you call created? on the instance returned
# it will tell if it was successful or not
@@ -518,7 +529,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end
#
- # Full path of key such as 'HKEY_CURRENT_USER\SOFTWARE\foo\bar'.
+ # Full path of key such as <tt>'HKEY_CURRENT_USER\SOFTWARE\foo\bar'</tt>.
#
def name
parent = self
@@ -529,6 +540,9 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
name
end
+ #
+ # Retruns inspected string
+ #
def inspect
"\#<Win32::Registry key=#{name.inspect}>"
end
@@ -541,14 +555,14 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end
#
- # Same as Win32::Registry.open (self, subkey, desired, opt)
+ # Same as Win32::Registry.open(self, subkey, desired, opt)
#
def open(subkey, desired = KEY_READ, opt = REG_OPTION_RESERVED, &blk)
self.class.open(self, subkey, desired, opt, &blk)
end
#
- # Same as Win32::Registry.create (self, subkey, desired, opt)
+ # Same as Win32::Registry.create(self, subkey, desired, opt)
#
def create(subkey, desired = KEY_ALL_ACCESS, opt = REG_OPTION_RESERVED, &blk)
self.class.create(self, subkey, desired, opt, &blk)
@@ -571,7 +585,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# For each value it yields key, type and data.
#
# key is a String which contains name of key.
- # type is a type contant kind of Win32::Registry::REG_*
+ # type is a type constant kind of +Win32::Registry::REG_+*
# data is the value of this key.
#
def each_value
@@ -640,21 +654,23 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
end
# Read a registry value named name and return array of
- # [ type, data ].
- # When name is nil, the `default' value is read.
- # type is value type. (see Win32::Registry::Constants module)
- # data is value data, its class is:
- # :REG_SZ, REG_EXPAND_SZ
+ # <tt>[ type, data ]</tt>.
+ # When name is +nil+, the `default' value is read.
+ #
+ # +type+ is {value type}[rdoc-ref:Win32::Registry@Value+types].
+ #
+ # +data+ is value data, its class is:
+ # REG_SZ, REG_EXPAND_SZ::
# String
- # :REG_MULTI_SZ
+ # REG_MULTI_SZ::
# Array of String
- # :REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD
+ # REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD::
# Integer
- # :REG_BINARY, REG_NONE
+ # REG_BINARY, REG_NONE::
# String (contains binary data)
#
- # When rtype is specified, the value type must be included by
- # rtype array, or TypeError is raised.
+ # When _rtype_ is specified, the value type must be included by
+ # _rtype_ array, or +TypeError+ is raised.
def read(name, *rtype)
type, data = API.QueryValue(@hkey, name)
unless rtype.empty? or rtype.include?(type)
@@ -687,9 +703,9 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# If the value type is REG_EXPAND_SZ, returns value data whose environment
# variables are replaced.
# If the value type is neither REG_SZ, REG_MULTI_SZ, REG_DWORD,
- # REG_DWORD_BIG_ENDIAN, nor REG_QWORD, TypeError is raised.
+ # REG_DWORD_BIG_ENDIAN, nor REG_QWORD, +TypeError+ is raised.
#
- # The meaning of rtype is the same as for the #read method.
+ # The meaning of _rtype_ is the same as for the #read method.
#
def [](name, *rtype)
type, data = read(name, *rtype)
@@ -706,7 +722,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
# registry value named name.
#
- # If the values type does not match, TypeError is raised.
+ # If the values type does not match, +TypeError+ is raised.
def read_s(name)
read(name, REG_SZ)[1]
end
@@ -715,7 +731,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# Read a REG_SZ or REG_EXPAND_SZ registry value named name.
#
# If the value type is REG_EXPAND_SZ, environment variables are replaced.
- # Unless the value type is REG_SZ or REG_EXPAND_SZ, TypeError is raised.
+ # Unless the value type is REG_SZ or REG_EXPAND_SZ, +TypeError+ is raised.
#
def read_s_expand(name)
type, data = read(name, REG_SZ, REG_EXPAND_SZ)
@@ -730,7 +746,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
# registry value named name.
#
- # If the values type does not match, TypeError is raised.
+ # If the values type does not match, +TypeError+ is raised.
#
def read_i(name)
read(name, REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_QWORD)[1]
@@ -740,7 +756,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# Read a REG_SZ(read_s), REG_DWORD(read_i), or REG_BINARY(read_bin)
# registry value named name.
#
- # If the values type does not match, TypeError is raised.
+ # If the values type does not match, +TypeError+ is raised.
#
def read_bin(name)
read(name, REG_BINARY)[1]
@@ -750,7 +766,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
# Write data to a registry value named name.
# When name is nil, write to the `default' value.
#
- # type is type value. (see Registry::Constants module)
+ # +type+ is {value type}[rdoc-ref:Win32::Registry@Value+types].
# Class of data must be same as which #read
# method returns.
#
@@ -779,11 +795,12 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
#
# If wtype is specified, the value type is it.
# Otherwise, the value type is depend on class of value:
- # :Integer
+ #
+ # Integer::
# REG_DWORD
- # :String
+ # String::
# REG_SZ
- # :Array
+ # Array::
# REG_MULTI_SZ
#
def []=(name, rtype, value = nil)
@@ -880,19 +897,19 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
#
# Returns key information as Array of:
- # :num_keys
+ # num_keys::
# The number of subkeys.
- # :max_key_length
+ # max_key_length::
# Maximum length of name of subkeys.
- # :num_values
+ # num_values::
# The number of values.
- # :max_value_name_length
+ # max_value_name_length::
# Maximum length of name of values.
- # :max_value_length
+ # max_value_length::
# Maximum length of value of values.
- # :descriptor_length
+ # descriptor_length::
# Length of security descriptor.
- # :wtime
+ # wtime::
# Last write time as FILETIME(64-bit integer)
#
# For detail, see RegQueryInfoKey[http://msdn.microsoft.com/library/en-us/sysinfo/base/regqueryinfokey.asp] Win32 API.
diff --git a/ext/win32/lib/win32/resolv.rb b/ext/win32/lib/win32/resolv.rb
index 67762da375..8d631a2140 100644
--- a/ext/win32/lib/win32/resolv.rb
+++ b/ext/win32/lib/win32/resolv.rb
@@ -4,8 +4,23 @@
=end
+require 'win32/resolv.so'
+
module Win32
module Resolv
+ # Error at Win32 API
+ class Error < StandardError
+ # +code+ Win32 Error code
+ # +message+ Formatted message for +code+
+ def initialize(code, message)
+ super(message)
+ @code = code
+ end
+
+ # Win32 error code
+ attr_reader :code
+ end
+
def self.get_hosts_path
path = get_hosts_dir
path = File.expand_path('hosts', path)
@@ -29,115 +44,62 @@ module Win32
end
[ search, nameserver ]
end
- end
-end
-
-begin
- require 'win32/resolv.so'
-rescue LoadError
-end
-
-module Win32
-#====================================================================
-# Windows NT
-#====================================================================
- module Resolv
- begin
- require 'win32/registry'
- module SZ
- refine Registry do
- # ad hoc workaround for broken registry
- def read_s(key)
- type, str = read(key)
- unless type == Registry::REG_SZ
- warn "Broken registry, #{name}\\#{key} was #{Registry.type2name(type)}, ignored"
- return String.new
- end
- str
- end
- end
- end
- using SZ
- rescue LoadError
- require "open3"
- end
-
- TCPIP_NT = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters'
class << self
private
def get_hosts_dir
- get_item_property(TCPIP_NT, 'DataBasePath', expand: true)
+ tcpip_params do |params|
+ params.value('DataBasePath')
+ end
end
def get_info
search = nil
nameserver = get_dns_server_list
- slist = get_item_property(TCPIP_NT, 'SearchList')
- search = slist.split(/,\s*/) unless slist.empty?
+ tcpip_params do |params|
+ slist = params.value('SearchList')
+ search = slist.split(/,\s*/) if slist and !slist.empty?
- if add_search = search.nil?
- search = []
- nvdom = get_item_property(TCPIP_NT, 'NV Domain')
+ if add_search = search.nil?
+ search = []
+ domain = params.value('Domain')
- unless nvdom.empty?
- @search = [ nvdom ]
- udmnd = get_item_property(TCPIP_NT, 'UseDomainNameDevolution').to_i
- if udmnd != 0
- if /^\w+\./ =~ nvdom
- devo = $'
+ if domain and !domain.empty?
+ search = [ domain ]
+ udmnd = params.value('UseDomainNameDevolution')
+ if udmnd&.nonzero?
+ if /^\w+\./ =~ domain
+ devo = $'
+ end
end
end
end
- end
- ifs = if defined?(Win32::Registry)
- Registry::HKEY_LOCAL_MACHINE.open(TCPIP_NT + '\Interfaces') do |reg|
- reg.keys
- rescue Registry::Error
- []
- end
- else
- cmd = "Get-ChildItem 'HKLM:\\#{TCPIP_NT}\\Interfaces' | ForEach-Object { $_.PSChildName }"
- output, _ = Open3.capture2('powershell', '-Command', cmd)
- output.split(/\n+/)
+ params.open('Interfaces') do |reg|
+ reg.each_key do |iface|
+ next unless ns = %w[NameServer DhcpNameServer].find do |key|
+ ns = iface.value(key)
+ break ns.split(/[,\s]\s*/) if ns and !ns.empty?
end
- ifs.each do |iface|
- next unless ns = %w[NameServer DhcpNameServer].find do |key|
- ns = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
- break ns.split(/[,\s]\s*/) unless ns.empty?
- end
+ next if (nameserver & ns).empty?
- next if (nameserver & ns).empty?
-
- if add_search
- [ 'Domain', 'DhcpDomain' ].each do |key|
- dom = get_item_property(TCPIP_NT + '\Interfaces' + "\\#{iface}", key)
- unless dom.empty?
- search.concat(dom.split(/,\s*/))
- break
+ if add_search
+ [ 'Domain', 'DhcpDomain' ].each do |key|
+ dom = iface.value(key)
+ if dom and !dom.empty?
+ search.concat(dom.split(/,\s*/))
+ break
+ end
+ end
end
end
end
- end
- search << devo if add_search and devo
- [ search.uniq, nameserver.uniq ]
- end
- def get_item_property(path, name, expand: false)
- if defined?(Win32::Registry)
- Registry::HKEY_LOCAL_MACHINE.open(path) do |reg|
- expand ? reg.read_s_expand(name) : reg.read_s(name)
- rescue Registry::Error
- ""
- end
- else
- cmd = "Get-ItemProperty -Path 'HKLM:\\#{path}' -Name '#{name}' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty '#{name}'"
- output, _ = Open3.capture2('powershell', '-Command', cmd)
- output.strip
+ search << devo if add_search and devo
end
+ [ search.uniq, nameserver.uniq ]
end
end
end
diff --git a/ext/win32/resolv/extconf.rb b/ext/win32/resolv/extconf.rb
index 4afbf8a4f6..5ee4c0d7c4 100644
--- a/ext/win32/resolv/extconf.rb
+++ b/ext/win32/resolv/extconf.rb
@@ -1,5 +1,6 @@
require 'mkmf'
-if RUBY_ENGINE == "ruby" and have_library('iphlpapi', 'GetNetworkParams')
+if RUBY_ENGINE == "ruby" and have_library('iphlpapi', 'GetNetworkParams', ['windows.h', 'iphlpapi.h'])
+ have_library('advapi32', 'RegGetValueW', ['windows.h'])
create_makefile('win32/resolv')
else
File.write('Makefile', "all clean install:\n\t@echo Done: $(@)\n")
diff --git a/ext/win32/resolv/resolv.c b/ext/win32/resolv/resolv.c
index af678e1f17..b2d377df9f 100644
--- a/ext/win32/resolv/resolv.c
+++ b/ext/win32/resolv/resolv.c
@@ -1,24 +1,56 @@
#include <ruby.h>
#include <ruby/encoding.h>
#include <windows.h>
+#include <windns.h>
#ifndef NTDDI_VERSION
#define NTDDI_VERSION 0x06000000
#endif
#include <iphlpapi.h>
+#ifndef numberof
+#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
+#endif
+
static VALUE
w32error_make_error(DWORD e)
{
- VALUE code = ULONG2NUM(e);
- return rb_class_new_instance(1, &code, rb_path2class("Win32::Resolv::Error"));
+ char buffer[512], *p;
+ DWORD source = 0;
+ VALUE args[2];
+ if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ buffer, sizeof(buffer), NULL)) {
+ snprintf(buffer, sizeof(buffer), "Unknown Error %lu", (unsigned long)e);
+ }
+ p = buffer;
+ while ((p = strpbrk(p, "\r\n")) != NULL) {
+ memmove(p, p + 1, strlen(p));
+ if (!p[1]) {
+ p[0] = '\0';
+ break;
+ }
+ }
+ args[0] = ULONG2NUM(e);
+ args[1] = rb_str_new_cstr(buffer);
+ return rb_class_new_instance(2, args, rb_path2class("Win32::Resolv::Error"));
}
-NORETURN(static void w32error_raise(DWORD e));
-
static void
-w32error_raise(DWORD e)
+w32error_check(DWORD e)
+{
+ if (e != NO_ERROR) {
+ rb_exc_raise(w32error_make_error(e));
+ }
+}
+
+static VALUE
+wchar_to_utf8(const WCHAR *w, int n)
{
- rb_exc_raise(w32error_make_error(e));
+ int clen = WideCharToMultiByte(CP_UTF8, 0, w, n, NULL, 0, NULL, NULL);
+ VALUE str = rb_enc_str_new(NULL, clen, rb_utf8_encoding());
+ WideCharToMultiByte(CP_UTF8, 0, w, n, RSTRING_PTR(str), clen, NULL, NULL);
+ return str;
}
static VALUE
@@ -30,9 +62,7 @@ get_dns_server_list(VALUE self)
VALUE buf, nameservers = Qnil;
ret = GetNetworkParams(NULL, &buflen);
- if (ret != NO_ERROR && ret != ERROR_BUFFER_OVERFLOW) {
- w32error_raise(ret);
- }
+ if (ret != ERROR_BUFFER_OVERFLOW) w32error_check(ret);
fixedinfo = ALLOCV(buf, buflen);
ret = GetNetworkParams(fixedinfo, &buflen);
if (ret == NO_ERROR) {
@@ -46,18 +76,181 @@ get_dns_server_list(VALUE self)
} while ((ipaddr = ipaddr->Next) != NULL);
}
ALLOCV_END(buf);
- if (ret != NO_ERROR) w32error_raise(ret);
+ w32error_check(ret);
return nameservers;
}
+
+static const WCHAR TCPIP_Params[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
+
+static void
+hkey_finalize(void *p)
+{
+ RegCloseKey((HKEY)p);
+}
+
+static const rb_data_type_t hkey_type = {
+ "RegKey",
+ {0, hkey_finalize},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+static VALUE
+hkey_close(VALUE self)
+{
+ RegCloseKey((HKEY)DATA_PTR(self));
+ DATA_PTR(self) = 0;
+ return self;
+}
+
+static VALUE reg_key_class;
+
+static VALUE
+reg_open_key(VALUE klass, HKEY hkey, const WCHAR *wname)
+{
+ VALUE k = TypedData_Wrap_Struct(klass, &hkey_type, NULL);
+ DWORD e = RegOpenKeyExW(hkey, wname, 0, KEY_READ, (HKEY *)&DATA_PTR(k));
+ if (e == ERROR_FILE_NOT_FOUND) return Qnil;
+ w32error_check(e);
+ return rb_ensure(rb_yield, k, hkey_close, k);
+}
+
+static VALUE
+tcpip_params_open(VALUE klass)
+{
+ return reg_open_key(reg_key_class, HKEY_LOCAL_MACHINE, TCPIP_Params);
+}
+
+static int
+to_wname(VALUE *name, WCHAR *wname, int wlen)
+{
+ const char *n = StringValueCStr(*name);
+ int nlen = RSTRING_LEN(*name);
+ int len = MultiByteToWideChar(CP_UTF8, 0, n, nlen, wname, wlen - 1);
+ if (len == 0) w32error_check(GetLastError());
+ if (len >= wlen) rb_raise(rb_eArgError, "too long name");
+ wname[len] = L'\0';
+ return len;
+}
+
+static VALUE
+reg_open(VALUE self, VALUE name)
+{
+ HKEY hkey = DATA_PTR(self);
+ WCHAR wname[256];
+ to_wname(&name, wname, numberof(wname));
+ return reg_open_key(CLASS_OF(self), hkey, wname);
+}
+
+
+static VALUE
+reg_each_key(VALUE self)
+{
+ WCHAR wname[256];
+ HKEY hkey = DATA_PTR(self);
+ VALUE k = TypedData_Wrap_Struct(CLASS_OF(self), &hkey_type, NULL);
+ DWORD i, e, n;
+ for (i = 0; n = numberof(wname), (e = RegEnumKeyExW(hkey, i, wname, &n, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS; i++) {
+ e = RegOpenKeyExW(hkey, wname, 0, KEY_READ, (HKEY *)&DATA_PTR(k));
+ w32error_check(e);
+ rb_ensure(rb_yield, k, hkey_close, k);
+ }
+ if (e != ERROR_NO_MORE_ITEMS) w32error_check(e);
+ return self;
+}
+
+static inline DWORD
+swap_dw(DWORD x)
+{
+#if defined(_MSC_VER)
+ return _byteswap_ulong(x);
+#else
+ return __builtin_bswap32(x);
+#endif
+}
+
+static VALUE
+reg_value(VALUE self, VALUE name)
+{
+ HKEY hkey = DATA_PTR(self);
+ DWORD type = 0, size = 0, e;
+ VALUE result, value_buffer;
+ void *buffer;
+ WCHAR wname[256];
+ to_wname(&name, wname, numberof(wname));
+ e = RegGetValueW(hkey, NULL, wname, RRF_RT_ANY, &type, NULL, &size);
+ if (e == ERROR_FILE_NOT_FOUND) return Qnil;
+ w32error_check(e);
+# define get_value_2nd(data, dsize) do { \
+ DWORD type2 = type; \
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_ANY, &type2, data, dsize)); \
+ if (type != type2) { \
+ rb_raise(rb_eRuntimeError, "registry value type changed %lu -> %lu", \
+ (unsigned long)type, (unsigned long)type2); \
+ } \
+ } while (0)
+
+ switch (type) {
+ case REG_DWORD: case REG_DWORD_BIG_ENDIAN:
+ {
+ DWORD d;
+ if (size != sizeof(d)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_REG_DWORD, &type, &d, &size));
+ if (type == REG_DWORD_BIG_ENDIAN) d = swap_dw(d);
+ return ULONG2NUM(d);
+ }
+ case REG_QWORD:
+ {
+ QWORD q;
+ if (size != sizeof(q)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ w32error_check(RegGetValueW(hkey, NULL, wname, RRF_RT_REG_QWORD, &type, &q, &size));
+ return ULL2NUM(q);
+ }
+ case REG_SZ: case REG_MULTI_SZ: case REG_EXPAND_SZ:
+ if (size % sizeof(WCHAR)) rb_raise(rb_eRuntimeError, "invalid size returned: %lu", (unsigned long)size);
+ buffer = ALLOCV_N(char, value_buffer, size);
+ get_value_2nd(buffer, &size);
+ if (type == REG_MULTI_SZ) {
+ const WCHAR *w = (WCHAR *)buffer;
+ result = rb_ary_new();
+ size /= sizeof(WCHAR);
+ size -= 1;
+ for (size_t i = 0; i < size; ++i) {
+ int n = lstrlenW(w+i);
+ rb_ary_push(result, wchar_to_utf8(w+i, n));
+ i += n;
+ }
+ }
+ else {
+ result = wchar_to_utf8((WCHAR *)buffer, lstrlenW((WCHAR *)buffer));
+ }
+ ALLOCV_END(value_buffer);
+ break;
+ default:
+ result = rb_str_new(0, size);
+ get_value_2nd(RSTRING_PTR(result), &size);
+ rb_str_set_len(result, size);
+ break;
+ }
+ return result;
+}
+
void
InitVM_resolv(void)
{
VALUE mWin32 = rb_define_module("Win32");
VALUE resolv = rb_define_module_under(mWin32, "Resolv");
VALUE singl = rb_singleton_class(resolv);
+ VALUE regkey = rb_define_class_under(resolv, "registry key", rb_cObject);
+
+ reg_key_class = regkey;
+ rb_undef_alloc_func(regkey);
rb_define_private_method(singl, "get_dns_server_list", get_dns_server_list, 0);
+ rb_define_private_method(singl, "tcpip_params", tcpip_params_open, 0);
+ rb_define_method(regkey, "open", reg_open, 1);
+ rb_define_method(regkey, "each_key", reg_each_key, 0);
+ rb_define_method(regkey, "value", reg_value, 1);
}
void
diff --git a/ext/win32/win32-registry.gemspec b/ext/win32/win32-registry.gemspec
index d747daf458..9bd57bd7d1 100644
--- a/ext/win32/win32-registry.gemspec
+++ b/ext/win32/win32-registry.gemspec
@@ -1,7 +1,7 @@
# frozen_string_literal: true
Gem::Specification.new do |spec|
spec.name = "win32-registry"
- spec.version = "0.1.0"
+ spec.version = "0.1.2"
spec.authors = ["U.Nakamura"]
spec.email = ["usa@garbagecollect.jp"]
@@ -17,13 +17,10 @@ Gem::Specification.new do |spec|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
excludes = %w[
bin/ test/ spec/ features/ rakelib/
- .git .github .mailmap appveyor Rakefile Gemfile
+ .git* .mailmap appveyor Rakefile Gemfile
]
- spec.files = Dir.chdir(__dir__) do
- `git ls-files -z`.split("\x0").reject do |f|
- File.identical?(f, __FILE__) || f.start_with?(*excludes)
- end
- end
+ git_files = %w[git ls-files -z --] + excludes.map {|x| ":^/#{x}"}
+ spec.files = IO.popen(git_files, chdir: __dir__, &:read).split("\x0")
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
diff --git a/ext/zlib/depend b/ext/zlib/depend
index bdce420264..22e9ca867a 100644
--- a/ext/zlib/depend
+++ b/ext/zlib/depend
@@ -138,6 +138,7 @@ zlib.o: $(hdrdir)/ruby/internal/intern/re.h
zlib.o: $(hdrdir)/ruby/internal/intern/ruby.h
zlib.o: $(hdrdir)/ruby/internal/intern/select.h
zlib.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+zlib.o: $(hdrdir)/ruby/internal/intern/set.h
zlib.o: $(hdrdir)/ruby/internal/intern/signal.h
zlib.o: $(hdrdir)/ruby/internal/intern/sprintf.h
zlib.o: $(hdrdir)/ruby/internal/intern/string.h
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 0b9c4d65ee..7e319cae0d 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -25,7 +25,7 @@
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
#endif
-#define RUBY_ZLIB_VERSION "3.2.1"
+#define RUBY_ZLIB_VERSION "3.2.2"
#ifndef RB_PASS_CALLED_KEYWORDS
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
@@ -1456,6 +1456,7 @@ rb_zstream_finish(VALUE obj)
* call-seq:
* flush_next_in -> input
*
+ * Flushes input buffer and returns all data in that buffer.
*/
static VALUE
rb_zstream_flush_next_in(VALUE obj)
@@ -2444,17 +2445,16 @@ struct gzfile {
#define GZFILE_READ_SIZE 2048
+enum { read_raw_arg_len, read_raw_arg_buf, read_raw_arg__count};
struct read_raw_arg {
VALUE io;
- union {
- const VALUE argv[2]; /* for rb_funcallv */
- struct {
- VALUE len;
- VALUE buf;
- } in;
- } as;
+ const VALUE argv[read_raw_arg__count]; /* for rb_funcallv */
};
+#define read_raw_arg_argc(ra) \
+ ((int)read_raw_arg__count - NIL_P((ra)->argv[read_raw_arg__count - 1]))
+#define read_raw_arg_init(io, len, buf) { io, { len, buf } }
+
static void
gzfile_mark(void *p)
{
@@ -2580,9 +2580,9 @@ gzfile_read_raw_partial(VALUE arg)
{
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
VALUE str;
- int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
+ int argc = read_raw_arg_argc(ra);
- str = rb_funcallv(ra->io, id_readpartial, argc, ra->as.argv);
+ str = rb_funcallv(ra->io, id_readpartial, argc, ra->argv);
Check_Type(str, T_STRING);
return str;
}
@@ -2593,8 +2593,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _)
struct read_raw_arg *ra = (struct read_raw_arg *)arg;
VALUE str = Qnil;
if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
- int argc = NIL_P(ra->as.argv[1]) ? 1 : 2;
- str = rb_funcallv(ra->io, id_read, argc, ra->as.argv);
+ int argc = read_raw_arg_argc(ra);
+ str = rb_funcallv(ra->io, id_read, argc, ra->argv);
if (!NIL_P(str)) {
Check_Type(str, T_STRING);
}
@@ -2605,11 +2605,8 @@ gzfile_read_raw_rescue(VALUE arg, VALUE _)
static VALUE
gzfile_read_raw(struct gzfile *gz, VALUE outbuf)
{
- struct read_raw_arg ra;
-
- ra.io = gz->io;
- ra.as.in.len = INT2FIX(GZFILE_READ_SIZE);
- ra.as.in.buf = outbuf;
+ struct read_raw_arg ra =
+ read_raw_arg_init(gz->io, INT2FIX(GZFILE_READ_SIZE), outbuf);
return rb_rescue2(gzfile_read_raw_partial, (VALUE)&ra,
gzfile_read_raw_rescue, (VALUE)&ra,