Skip to content

Commit

Permalink
Eliminate Object#untaint deprecation warnings on JRuby 9.4.0.0.
Browse files Browse the repository at this point in the history
Despite using the UntaintExt refinement that replaces Object#untaint,
JRuby 9.4.0.0 calls the original Object#untaint method and outputs
warnings as a result:

warning: Object#untaint is deprecated and will be removed in Ruby 3.2

This is caused by the unorthodox `send(:using, UntaintExt)` approach
being used to deal with issues with older JRuby versions (see #114).
JRuby 9.4.0.0 doesn't detect this as using the refinement. This will be
allowed again in JRuby 9.4.1.0 (see jruby/jruby#7599).

Replace the UntaintExt refinement with an untaint method in
RubyCoreSupport (now reinstated having previously been removed in
2.0.0).

Change tests for handling of tainted inputs to skip when taint/untaint
is undefined or a no-op. There's no point in running these tests unless
the inputs are actually tainted. Remove the (test-only) TaintExt
refinement too.

Resolves #145.
  • Loading branch information
philr committed Jan 28, 2023
1 parent 19f984c commit eac33df
Show file tree
Hide file tree
Showing 16 changed files with 125 additions and 83 deletions.
8 changes: 2 additions & 6 deletions lib/tzinfo.rb
Expand Up @@ -17,12 +17,8 @@ def eager_load!
end
end

# Object#untaint is a deprecated no-op in Ruby >= 2.7 and will be removed in
# 3.2. Add a refinement to either silence the warning, or supply the method if
# needed.
if !Object.new.respond_to?(:untaint) || RUBY_VERSION =~ /\A(\d+)\.(\d+)(?:\.|\z)/ && ($1 == '2' && $2.to_i >= 7 || $1.to_i >= 3)
require_relative 'tzinfo/untaint_ext'
end

require_relative 'tzinfo/ruby_core_support'

require_relative 'tzinfo/version'

Expand Down
8 changes: 2 additions & 6 deletions lib/tzinfo/data_sources/posix_time_zone_parser.rb
Expand Up @@ -4,10 +4,6 @@
require 'strscan'

module TZInfo
# Use send as a workaround for erroneous 'wrong number of arguments' errors
# with JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, UntaintExt) if TZInfo.const_defined?(:UntaintExt)

module DataSources
# An {InvalidPosixTimeZone} exception is raised if an invalid POSIX-style
# time zone string is encountered.
Expand Down Expand Up @@ -43,12 +39,12 @@ def parse(tz_string)

s = StringScanner.new(tz_string)
check_scan(s, /([^-+,\d<][^-+,\d]*) | <([^>]+)>/x)
std_abbrev = @string_deduper.dedupe((s[1] || s[2]).untaint)
std_abbrev = @string_deduper.dedupe(RubyCoreSupport.untaint(s[1] || s[2]))
check_scan(s, /([-+]?\d+)(?::(\d+)(?::(\d+))?)?/)
std_offset = get_offset_from_hms(s[1], s[2], s[3])

if s.scan(/([^-+,\d<][^-+,\d]*) | <([^>]+)>/x)
dst_abbrev = @string_deduper.dedupe((s[1] || s[2]).untaint)
dst_abbrev = @string_deduper.dedupe(RubyCoreSupport.untaint(s[1] || s[2]))

if s.scan(/([-+]?\d+)(?::(\d+)(?::(\d+))?)?/)
dst_offset = get_offset_from_hms(s[1], s[2], s[3])
Expand Down
6 changes: 1 addition & 5 deletions lib/tzinfo/data_sources/ruby_data_source.rb
Expand Up @@ -2,10 +2,6 @@
# frozen_string_literal: true

module TZInfo
# Use send as a workaround for erroneous 'wrong number of arguments' errors
# with JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, UntaintExt) if TZInfo.const_defined?(:UntaintExt)

module DataSources
# A {TZInfoDataNotFound} exception is raised if the tzinfo-data gem could
# not be found (i.e. `require 'tzinfo/data'` failed) when selecting the Ruby
Expand Down Expand Up @@ -52,7 +48,7 @@ def initialize
data_file = File.join('', 'tzinfo', 'data.rb')
path = $".reverse_each.detect {|p| p.end_with?(data_file) }
if path
@base_path = File.join(File.dirname(path), 'data').untaint
@base_path = RubyCoreSupport.untaint(File.join(File.dirname(path), 'data'))
else
@base_path = 'tzinfo/data'
end
Expand Down
6 changes: 1 addition & 5 deletions lib/tzinfo/data_sources/zoneinfo_data_source.rb
Expand Up @@ -2,10 +2,6 @@
# frozen_string_literal: true

module TZInfo
# Use send as a workaround for erroneous 'wrong number of arguments' errors
# with JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, UntaintExt) if TZInfo.const_defined?(:UntaintExt)

module DataSources
# An {InvalidZoneinfoDirectory} exception is raised if {ZoneinfoDataSource}
# is initialized with a specific zoneinfo path that is not a valid zoneinfo
Expand Down Expand Up @@ -444,7 +440,7 @@ def enum_timezones(dir, exclude = [], &block)
end

unless entry =~ /\./ || exclude.include?(entry)
entry.untaint
RubyCoreSupport.untaint(entry)
path = dir + [entry]
full_path = File.join(@zoneinfo_dir, *path)

Expand Down
6 changes: 1 addition & 5 deletions lib/tzinfo/data_sources/zoneinfo_reader.rb
Expand Up @@ -2,10 +2,6 @@
# frozen_string_literal: true

module TZInfo
# Use send as a workaround for erroneous 'wrong number of arguments' errors
# with JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, UntaintExt) if TZInfo.const_defined?(:UntaintExt)

module DataSources
# An {InvalidZoneinfoFile} exception is raised if an attempt is made to load
# an invalid zoneinfo file.
Expand Down Expand Up @@ -448,7 +444,7 @@ def parse(file)
abbrev_end = abbrev.index("\0", abbrev_start)
raise InvalidZoneinfoFile, "Missing abbreviation null terminator in file '#{file.path}'." unless abbrev_end

abbr = @string_deduper.dedupe(abbrev[abbrev_start...abbrev_end].force_encoding(Encoding::UTF_8).untaint)
abbr = @string_deduper.dedupe(RubyCoreSupport.untaint(abbrev[abbrev_start...abbrev_end].force_encoding(Encoding::UTF_8)))

TimezoneOffset.new(base_utc_offset, std_offset, abbr)
end
Expand Down
38 changes: 38 additions & 0 deletions lib/tzinfo/ruby_core_support.rb
@@ -0,0 +1,38 @@
module TZInfo

# Methods to support different versions of Ruby.
#
# @private
module RubyCoreSupport #:nodoc:
class << self
# Object#untaint is deprecated and becomes a no-op in Ruby >= 2.7. It has
# been removed from Ruby 3.2.
if !Object.new.respond_to?(:untaint) || RUBY_VERSION =~ /\A(\d+)\.(\d+)(?:\.|\z)/ && ($1 == '2' && $2.to_i >= 7 || $1.to_i >= 3)
# :nocov_functional_untaint:

# Returns the supplied `Object`
#
# @param o [Object] the `Object` to untaint.
# @return [Object] `o`.
def untaint(o)
o
end

# :nocov_functional_untaint:
else
# :nocov_no_functional_untaint:

# Untaints and returns the supplied `Object`.
#
# @param o [Object] the `Object` to untaint.
# @return [Object] `o`.
def untaint(o)
o.untaint
end

# :nocov_no_functional_untaint:
end
end
end
private_constant :RubyCoreSupport
end
18 changes: 0 additions & 18 deletions lib/tzinfo/untaint_ext.rb

This file was deleted.

6 changes: 2 additions & 4 deletions test/data_sources/tc_posix_time_zone_parser.rb
Expand Up @@ -3,10 +3,6 @@

require_relative '../test_utils'

# Use send as a workaround for erroneous 'wrong number of arguments' errors with
# JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, TestUtils::TaintExt) if TestUtils.const_defined?(:TaintExt)

module DataSources
class TCPosixTimeZoneParser < Minitest::Test
include TZInfo
Expand Down Expand Up @@ -259,6 +255,8 @@ def test_returns_deduped_strings
end

def test_parses_tainted_string_in_safe_mode_and_returns_untainted_abbreviations
skip_if_taint_is_undefined_or_no_op

safe_test(unavailable: :skip) do
result = @parser.parse('STD1DST,60,300'.dup.taint)

Expand Down
12 changes: 8 additions & 4 deletions test/data_sources/tc_ruby_data_source.rb
Expand Up @@ -3,10 +3,6 @@

require_relative '../test_utils'

# Use send as a workaround for erroneous 'wrong number of arguments' errors with
# JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, TestUtils::TaintExt) if TestUtils.const_defined?(:TaintExt)

module DataSources
class TCRubyDataSource < Minitest::Test
include TZInfo
Expand Down Expand Up @@ -123,6 +119,8 @@ def test_load_timezone_info_minus
end

def test_load_timezone_info_tainted
skip_if_taint_is_undefined_or_no_op

safe_test(unavailable: :skip) do
identifier = 'Europe/Amsterdam'.dup.taint
assert(identifier.tainted?)
Expand All @@ -133,6 +131,8 @@ def test_load_timezone_info_tainted
end

def test_load_timezone_info_tainted_and_frozen
skip_if_taint_is_undefined_or_no_op

safe_test do
info = @data_source.send(:load_timezone_info, 'Europe/Amsterdam'.dup.taint.freeze)
assert_equal('Europe/Amsterdam', info.identifier)
Expand Down Expand Up @@ -232,6 +232,8 @@ def test_load_country_info_case
end

def test_load_country_info_tainted
skip_if_taint_is_undefined_or_no_op

safe_test(unavailable: :skip) do
code = 'NL'.dup.taint
assert(code.tainted?)
Expand All @@ -242,6 +244,8 @@ def test_load_country_info_tainted
end

def test_load_country_info_tainted_and_frozen
skip_if_taint_is_undefined_or_no_op

safe_test do
info = @data_source.send(:load_country_info, 'NL'.dup.taint.freeze)
assert_equal('NL', info.code)
Expand Down
19 changes: 12 additions & 7 deletions test/data_sources/tc_zoneinfo_data_source.rb
Expand Up @@ -6,17 +6,13 @@
require 'pathname'
require 'tmpdir'

# Use send as a workaround for erroneous 'wrong number of arguments' errors with
# JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, TestUtils::TaintExt) if TestUtils.const_defined?(:TaintExt)
send(:using, TZInfo.const_get(:UntaintExt)) if TZInfo.const_defined?(:UntaintExt)

module DataSources
class TCZoneinfoDataSource < Minitest::Test
include TZInfo
include TZInfo::DataSources

ZONEINFO_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'zoneinfo')).untaint
ZONEINFO_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'zoneinfo'))
RubyCoreSupport.untaint(ZONEINFO_DIR)

def setup
@orig_search_path = ZoneinfoDataSource.search_path.clone
Expand Down Expand Up @@ -788,6 +784,8 @@ def test_load_timezone_info_linked_relative_parent_inside
end

def test_load_timezone_info_tainted
skip_if_taint_is_undefined_or_no_op

safe_test(unavailable: :skip) do
identifier = 'Europe/Amsterdam'.dup.taint
assert(identifier.tainted?)
Expand All @@ -798,13 +796,17 @@ def test_load_timezone_info_tainted
end

def test_load_timezone_info_tainted_and_frozen
skip_if_taint_is_undefined_or_no_op

safe_test do
info = @data_source.send(:load_timezone_info, 'Europe/Amsterdam'.dup.taint.freeze)
assert_equal('Europe/Amsterdam', info.identifier)
end
end

def test_load_timezone_info_tainted_zoneinfo_dir_safe_mode
skip_if_taint_is_undefined_or_no_op

safe_test(unavailable: :skip) do
assert_raises(SecurityError) do
ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint)
Expand All @@ -813,6 +815,7 @@ def test_load_timezone_info_tainted_zoneinfo_dir_safe_mode
end

def test_load_timezone_info_tainted_zoneinfo_dir
skip_if_taint_is_undefined_or_no_op
data_source = ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint)
info = data_source.send(:load_timezone_info, 'Europe/London')
assert_kind_of(TransitionsDataTimezoneInfo, info)
Expand Down Expand Up @@ -849,7 +852,7 @@ def get_timezone_filenames(directory)
entries = Dir.glob(File.join(directory, '**', '*'))

entries = entries.select do |file|
file.untaint
RubyCoreSupport.untaint(file)
File.file?(file)
end

Expand Down Expand Up @@ -1149,6 +1152,8 @@ def test_load_country_info_case
end

def test_load_country_info_tainted
skip_if_taint_is_undefined_or_no_op

safe_test(unavailable: :skip) do
code = 'NL'.dup.taint
assert(code.tainted?)
Expand Down
10 changes: 5 additions & 5 deletions test/data_sources/tc_zoneinfo_reader.rb
Expand Up @@ -4,10 +4,6 @@
require_relative '../test_utils'
require 'tempfile'

# Use send as a workaround for erroneous 'wrong number of arguments' errors with
# JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, TZInfo.const_get(:UntaintExt)) if TZInfo.const_defined?(:UntaintExt)

module DataSources
class TCZoneinfoReader < Minitest::Test
include TZInfo
Expand Down Expand Up @@ -1257,14 +1253,16 @@ def test_read_untainted_in_safe_mode
tzif_test(offsets, []) do |path, format|
safe_test do
# Temp file path is tainted with Ruby >= 2.3 & < 2.7. Untaint for this test.
path.untaint
RubyCoreSupport.untaint(path)

assert_equal(o0, @reader.read(path))
end
end
end

def test_read_tainted_in_safe_mode
skip_if_taint_is_undefined_or_no_op

offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}]

tzif_test(offsets, []) do |path, format|
Expand All @@ -1278,6 +1276,8 @@ def test_read_tainted_in_safe_mode
end

def test_read_abbreviations_not_tainted
skip_if_taint_is_undefined_or_no_op

offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}]

tzif_test(offsets, []) do |path, format|
Expand Down
10 changes: 6 additions & 4 deletions test/tc_country.rb
Expand Up @@ -3,10 +3,6 @@

require_relative 'test_utils'

# Use send as a workaround for erroneous 'wrong number of arguments' errors with
# JRuby 9.0.5.0 when calling methods with Java implementations. See #114.
send(:using, TestUtils::TaintExt) if TestUtils.const_defined?(:TaintExt)

class TCCountry < Minitest::Test
include TZInfo

Expand Down Expand Up @@ -48,6 +44,7 @@ def test_get_nil
end

def test_get_tainted_loaded
skip_if_taint_is_undefined_or_no_op
Country.get('GB')

safe_test(unavailable: :skip) do
Expand All @@ -60,6 +57,7 @@ def test_get_tainted_loaded
end

def test_get_tainted_and_frozen_loaded
skip_if_taint_is_undefined_or_no_op
Country.get('GB')

safe_test do
Expand All @@ -69,6 +67,8 @@ def test_get_tainted_and_frozen_loaded
end

def test_get_tainted_not_previously_loaded
skip_if_taint_is_undefined_or_no_op

safe_test(unavailable: :skip) do
code = 'GB'.dup.taint
assert(code.tainted?)
Expand All @@ -79,6 +79,8 @@ def test_get_tainted_not_previously_loaded
end

def test_get_tainted_and_frozen_not_previously_loaded
skip_if_taint_is_undefined_or_no_op

safe_test do
country = Country.get('GB'.dup.taint.freeze)
assert_equal('GB', country.code)
Expand Down

0 comments on commit eac33df

Please sign in to comment.