Skip to content

Commit 77fde89

Browse files
committed
[GR-45201] Raise ArgumentError when Time.new is called with argument that doesn't fit in Java Integer
PullRequest: truffleruby/3769
2 parents fed7fe9 + 4d00c2c commit 77fde89

File tree

8 files changed

+202
-225
lines changed

8 files changed

+202
-225
lines changed

lib/truffle/stringio.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def initialize(string = nil, mode = nil, **options)
143143
warn 'StringIO::new() does not take block; use StringIO::open() instead'
144144
end
145145

146-
mode, _binary, _external, _internal, _autoclose, _perm = IO.normalize_options(mode, nil, options)
146+
mode, _binary, _external, _internal, _autoclose, _perm = Truffle::IOOperations.normalize_options(mode, nil, options)
147147

148148
if Primitive.nil?(string)
149149
mode ||= IO::RDWR

src/main/java/org/truffleruby/core/CoreLibrary.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ public boolean isTruffleBootMainMethod(SharedMethodInfo info) {
10011001
"/core/truffle/stat_operations.rb",
10021002
"/core/truffle/string_operations.rb",
10031003
"/core/truffle/backward.rb",
1004+
"/core/truffle/time_operations.rb",
10041005
"/core/truffle/truffleruby.rb",
10051006
"/core/splitter.rb",
10061007
"/core/stat.rb",

src/main/java/org/truffleruby/core/time/TimeNodes.java

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ public abstract static class TimeSFromArrayPrimitiveNode extends PrimitiveArrayA
511511
@Child private TruffleString.FromJavaStringNode fromJavaStringNode;
512512

513513
@Specialization(guards = "(isutc || !isRubyDynamicObject(utcoffset)) || isNil(utcoffset)")
514+
@TruffleBoundary
514515
protected RubyTime timeSFromArray(
515516
RubyClass timeClass,
516517
int sec,
@@ -524,29 +525,7 @@ protected RubyTime timeSFromArray(
524525
boolean isutc,
525526
Object utcoffset) {
526527
final RubyLanguage language = getLanguage();
527-
return buildTime(language, timeClass, sec, min, hour, mday, month, year, nsec, isdst, isutc, utcoffset);
528-
}
529528

530-
@Specialization(guards = "!isInteger(sec) || !isInteger(nsec)")
531-
protected Object timeSFromArrayFallback(
532-
RubyClass timeClass,
533-
Object sec,
534-
int min,
535-
int hour,
536-
int mday,
537-
int month,
538-
int year,
539-
Object nsec,
540-
int isdst,
541-
boolean isutc,
542-
Object utcoffset) {
543-
return FAILURE;
544-
}
545-
546-
@TruffleBoundary
547-
private RubyTime buildTime(RubyLanguage language, RubyClass timeClass, int sec, int min, int hour, int mday,
548-
int month,
549-
int year, int nsec, int isdst, boolean isutc, Object utcoffset) {
550529
if (nsec < 0 || nsec > 999999999 ||
551530
sec < 0 || sec > 60 || // MRI accepts sec=60, whether it is a leap second or not
552531
min < 0 || min > 59 ||

src/main/ruby/truffleruby/core/file.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ def initialize(path_or_fd, mode = nil, perm = nil, **options)
11641164
@path = nil
11651165
else
11661166
path = Truffle::Type.coerce_to_path path_or_fd
1167-
nmode, _binary, _external, _internal, _autoclose, perm = IO.normalize_options(mode, perm, options)
1167+
nmode, _binary, _external, _internal, _autoclose, perm = Truffle::IOOperations.normalize_options(mode, perm, options)
11681168
fd = IO.sysopen(path, nmode, perm)
11691169

11701170
@path = path

src/main/ruby/truffleruby/core/io.rb

Lines changed: 4 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ def self.binwrite(file, string, offset = nil, **options)
337337
default_mode = File::CREAT | File::RDWR | File::BINARY
338338
default_mode |= File::TRUNC unless offset
339339

340-
mode, _binary, external, _internal, _autoclose, perm = IO.normalize_options(nil, nil, options, default_mode)
340+
mode, _binary, external, _internal, _autoclose, perm = Truffle::IOOperations.normalize_options(nil, nil, options, default_mode)
341341

342342
File.open(file, mode, encoding: (external || 'ASCII-8BIT'), perm: perm) do |f|
343343
f.seek(offset) if offset
@@ -502,7 +502,7 @@ def self.write(file, string, offset = nil, **options)
502502
default_mode = File::CREAT | File::WRONLY
503503
default_mode |= File::TRUNC unless offset
504504

505-
mode, _binary, external, _internal, _autoclose, perm = IO.normalize_options(nil, nil, options, default_mode)
505+
mode, _binary, external, _internal, _autoclose, perm = Truffle::IOOperations.normalize_options(nil, nil, options, default_mode)
506506

507507
open_args = [mode]
508508
open_kw = { encoding: (external || 'ASCII-8BIT'), perm: perm }
@@ -569,99 +569,6 @@ def self.try_convert(obj)
569569
Truffle::Type.rb_check_convert_type obj, IO, :to_io
570570
end
571571

572-
def self.normalize_options(mode, perm, options, default_mode = nil)
573-
autoclose = true
574-
575-
if mode
576-
mode = (Truffle::Type.try_convert(mode, Integer, :to_int) or
577-
Truffle::Type.coerce_to(mode, String, :to_str))
578-
end
579-
580-
if options
581-
if optmode = options[:mode]
582-
optmode = (Truffle::Type.try_convert(optmode, Integer, :to_int) or
583-
Truffle::Type.coerce_to(optmode, String, :to_str))
584-
end
585-
586-
if mode && optmode
587-
raise ArgumentError, 'mode specified twice'
588-
end
589-
590-
mode ||= optmode
591-
mode ||= default_mode
592-
593-
if flags = options[:flags]
594-
flags = Truffle::Type.rb_convert_type(flags, Integer, :to_int)
595-
596-
if Primitive.nil?(mode)
597-
mode = flags
598-
elsif Primitive.is_a?(mode, Integer)
599-
mode |= flags
600-
else # it's a String
601-
mode = Truffle::IOOperations.parse_mode(mode)
602-
mode |= flags
603-
end
604-
end
605-
606-
if optperm = options[:perm]
607-
optperm = Truffle::Type.try_convert(optperm, Integer, :to_int)
608-
end
609-
610-
if perm
611-
raise ArgumentError, 'perm specified twice' if optperm
612-
else
613-
perm = optperm
614-
end
615-
616-
autoclose = Primitive.as_boolean(options[:autoclose]) if options.key?(:autoclose)
617-
end
618-
619-
mode ||= default_mode
620-
621-
if Primitive.is_a?(mode, String)
622-
mode, external, internal = mode.split(':', 3)
623-
raise ArgumentError, 'invalid access mode' unless mode
624-
625-
binary = true if mode.include?(?b)
626-
binary = false if mode.include?(?t)
627-
elsif mode
628-
binary = true if (mode & BINARY) != 0
629-
end
630-
631-
if options
632-
if options[:textmode] and options[:binmode]
633-
raise ArgumentError, 'both textmode and binmode specified'
634-
end
635-
636-
if Primitive.nil? binary
637-
binary = options[:binmode]
638-
elsif options.key?(:textmode) or options.key?(:binmode)
639-
raise ArgumentError, 'text/binary mode specified twice'
640-
end
641-
642-
if !external and !internal
643-
external = options[:external_encoding]
644-
internal = options[:internal_encoding]
645-
elsif options[:external_encoding] or options[:internal_encoding] or options[:encoding]
646-
raise ArgumentError, 'encoding specified twice'
647-
end
648-
649-
if !external and !internal
650-
encoding = options[:encoding]
651-
652-
if Primitive.is_a?(encoding, Encoding)
653-
external = encoding
654-
elsif !Primitive.nil?(encoding)
655-
encoding = StringValue(encoding)
656-
external, internal = encoding.split(':', 2)
657-
end
658-
end
659-
end
660-
external = Encoding::BINARY if binary and !external and !internal
661-
perm ||= 0666
662-
[mode, binary, external, internal, autoclose, perm]
663-
end
664-
665572
def self.open(*args, **options)
666573
io = new(*args, **options)
667574

@@ -720,7 +627,7 @@ def self.popen(*args)
720627
end
721628
end
722629

723-
mode, binary, external, internal, _autoclose, _perm = IO.normalize_options(mode, nil, io_options)
630+
mode, binary, external, internal, _autoclose, _perm = Truffle::IOOperations.normalize_options(mode, nil, io_options)
724631
mode_int = Truffle::IOOperations.parse_mode mode
725632

726633
readable = false
@@ -941,7 +848,7 @@ def initialize(fd, mode = nil, **options)
941848
@external = nil
942849
@pid = nil
943850

944-
mode, binary, external, internal, autoclose_tmp, _perm = IO.normalize_options(mode, nil, options)
851+
mode, binary, external, internal, autoclose_tmp, _perm = Truffle::IOOperations.normalize_options(mode, nil, options)
945852

946853
fd = Truffle::Type.coerce_to(fd, Integer, :to_int)
947854
sync = fd == 2 # stderr is always unbuffered, see setvbuf(3)

src/main/ruby/truffleruby/core/time.rb

Lines changed: 6 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@
3737
class Time
3838
include Comparable
3939

40-
MonthValue = {
41-
'JAN' => 1, 'FEB' => 2, 'MAR' => 3, 'APR' => 4, 'MAY' => 5, 'JUN' => 6,
42-
'JUL' => 7, 'AUG' => 8, 'SEP' => 9, 'OCT' =>10, 'NOV' =>11, 'DEC' =>12
43-
}
44-
4540
def inspect
4641
str = strftime('%Y-%m-%d %H:%M:%S')
4742

@@ -371,99 +366,6 @@ def at(sec, sub_sec = undefined, unit = undefined, **kwargs)
371366
time
372367
end
373368

374-
def from_array(sec, min, hour, mday, month, year, nsec, is_dst, is_utc, utc_offset)
375-
time = Primitive.time_s_from_array(self, sec, min, hour, mday, month, year, nsec, is_dst, is_utc, utc_offset)
376-
return time unless Primitive.undefined?(time)
377-
378-
if Primitive.is_a?(sec, String)
379-
sec = sec.to_i
380-
elsif nsec
381-
sec = Truffle::Type.coerce_to(sec || 0, Integer, :to_int)
382-
else
383-
s = Truffle::Type.coerce_to_exact_num(sec || 0)
384-
385-
sec = s.to_i
386-
nsec_frac = s % 1.0
387-
388-
if s < 0 && nsec_frac > 0
389-
sec -= 1
390-
end
391-
392-
nsec = (nsec_frac * 1_000_000_000 + 0.5).to_i
393-
end
394-
395-
nsec ||= 0
396-
sec += nsec / 1_000_000_000
397-
nsec %= 1_000_000_000
398-
399-
from_array(sec, min, hour, mday, month, year, nsec, is_dst, is_utc, utc_offset)
400-
end
401-
private :from_array
402-
403-
def compose(offset, p1, p2 = nil, p3 = nil, p4 = nil, p5 = nil, p6 = nil, p7 = nil,
404-
yday = undefined, is_dst = undefined, tz = undefined)
405-
if Primitive.undefined?(tz)
406-
unless Primitive.undefined?(is_dst)
407-
raise ArgumentError, 'wrong number of arguments (9 for 1..8)'
408-
end
409-
410-
y = p1
411-
m = p2
412-
d = p3
413-
hr = p4
414-
min = p5
415-
sec = p6
416-
usec = p7
417-
is_dst = -1
418-
else
419-
y = p6
420-
m = p5
421-
d = p4
422-
hr = p3
423-
min = p2
424-
sec = p1
425-
usec = 0
426-
is_dst = is_dst ? 1 : 0
427-
end
428-
429-
if Primitive.is_a?(m, String) or m.respond_to?(:to_str)
430-
m = StringValue(m)
431-
m = MonthValue[m.upcase] || m.to_i
432-
433-
raise ArgumentError, 'month argument out of range' unless m
434-
else
435-
m = Truffle::Type.coerce_to(m || 1, Integer, :to_int)
436-
end
437-
438-
y = Primitive.is_a?(y, String) ? y.to_i : Truffle::Type.coerce_to(y, Integer, :to_int)
439-
d = Primitive.is_a?(d, String) ? d.to_i : Truffle::Type.coerce_to(d || 1, Integer, :to_int)
440-
hr = Primitive.is_a?(hr, String) ? hr.to_i : Truffle::Type.coerce_to(hr || 0, Integer, :to_int)
441-
min = Primitive.is_a?(min, String) ? min.to_i : Truffle::Type.coerce_to(min || 0, Integer, :to_int)
442-
443-
nsec = nil
444-
if Primitive.is_a?(usec, String)
445-
nsec = usec.to_i * 1000
446-
elsif usec
447-
nsec = (usec * 1000).to_i
448-
end
449-
450-
case offset
451-
when :utc
452-
is_dst = -1
453-
is_utc = true
454-
offset = nil
455-
when :local
456-
is_utc = false
457-
offset = nil
458-
else
459-
is_dst = -1
460-
is_utc = false
461-
end
462-
463-
from_array(sec, min, hr, d, m, y, nsec, is_dst, is_utc, offset)
464-
end
465-
private :compose
466-
467369
def new(year = undefined, month = nil, day = nil, hour = nil, minute = nil, second = nil, utc_offset = nil, **options)
468370
if utc_offset && options[:in]
469371
raise ArgumentError, 'timezone argument given as positional and keyword arguments'
@@ -474,18 +376,18 @@ def new(year = undefined, month = nil, day = nil, hour = nil, minute = nil, seco
474376
if Primitive.undefined?(year)
475377
utc_offset ? self.now.getlocal(utc_offset) : self.now
476378
elsif Primitive.nil? utc_offset
477-
compose(:local, year, month, day, hour, minute, second)
379+
Truffle::TimeOperations.compose(self, :local, year, month, day, hour, minute, second)
478380
elsif utc_offset == :std
479-
compose(:local, second, minute, hour, day, month, year, nil, nil, false, nil)
381+
Truffle::TimeOperations.compose(self, :local, second, minute, hour, day, month, year, nil, nil, false, nil)
480382
elsif utc_offset == :dst
481-
compose(:local, second, minute, hour, day, month, year, nil, nil, true, nil)
383+
Truffle::TimeOperations.compose(self, :local, second, minute, hour, day, month, year, nil, nil, true, nil)
482384
else
483385
if utc_offset_in_utc?(utc_offset)
484386
utc_offset = :utc
485387
else
486388
utc_offset = Truffle::Type.coerce_to_utc_offset(utc_offset)
487389
end
488-
compose(utc_offset, year, month, day, hour, minute, second)
390+
Truffle::TimeOperations.compose(self, utc_offset, year, month, day, hour, minute, second)
489391
end
490392
end
491393

@@ -508,12 +410,12 @@ def now(**options)
508410
end
509411

510412
def local(*args)
511-
compose(:local, *args)
413+
Truffle::TimeOperations.compose(self, :local, *args)
512414
end
513415
alias_method :mktime, :local
514416

515417
def gm(*args)
516-
compose(:utc, *args)
418+
Truffle::TimeOperations.compose(self, :utc, *args)
517419
end
518420
alias_method :utc, :gm
519421
end

0 commit comments

Comments
 (0)