ruby/timev.h
nagachika cb8d656100 merge revision(s) a84c99468f: [Backport #19575]
Fix crash in Time on 32-bit systems

	[Bug #19575]

	struct vtm is packed causing it to have a size that is not aligned on
	32-bit systems. When allocating it on the stack, it will have unaligned
	addresses which means that the fields won't be marked by the GC when
	scanning the stack (since the GC only marks aligned addresses). This can
	cause crashes when the fields are heap allocated objects like Bignums.

	This commit moves the flags in struct time_object into struct vtm for
	space efficiency and removes the need for packing.

	This is an example of a crash:

	    ruby(rb_print_backtrace+0xd) [0x56848945] ../src/vm_dump.c:785
	    ruby(rb_vm_bugreport) ../src/vm_dump.c:1101
	    ruby(rb_assert_failure+0x7a) [0x56671857] ../src/error.c:878
	    ruby(vm_search_cc+0x0) [0x56666e47] ../src/vm_method.c:1366
	    ruby(rb_vm_search_method_slowpath) ../src/vm_insnhelper.c:2090
	    ruby(callable_method_entry+0x5) [0x568232d3] ../src/vm_method.c:1406
	    ruby(rb_callable_method_entry) ../src/vm_method.c:1413
	    ruby(gccct_method_search_slowpath) ../src/vm_eval.c:427
	    ruby(gccct_method_search+0x20f) [0x568237ef] ../src/vm_eval.c:476
	    ruby(opt_equality_by_mid_slowpath+0x2c) [0x5682388c] ../src/vm_insnhelper.c:2338
	    ruby(rb_equal+0x37) [0x566fe577] ../src/object.c:133
	    ruby(rb_big_eq+0x34) [0x56876ee4] ../src/bignum.c:5554
	    ruby(rb_int_equal+0x14) [0x566f3ed4] ../src/numeric.c:4640
	    ruby(rb_int_equal) ../src/numeric.c:4634
	    ruby(vm_call0_cfunc_with_frame+0x6d) [0x568303c2] ../src/vm_eval.c:148
	    ruby(vm_call0_cfunc) ../src/vm_eval.c:162
	    ruby(vm_call0_body) ../src/vm_eval.c:208
	    ruby(rb_funcallv_scope+0xd1) [0x56833971] ../src/vm_eval.c:85
	    ruby(RB_TEST+0x0) [0x567e8488] ../src/time.c:78
	    ruby(eq) ../src/time.c:78
	    ruby(small_vtm_sub) ../src/time.c:1523
	    ruby(timelocalw+0x23b) [0x567f3e9b] ../src/time.c:1593
	    ruby(time_s_alloc+0x0) [0x567f536b] ../src/time.c:3698
	    ruby(time_new_timew) ../src/time.c:2694
	    ruby(time_s_mktime) ../src/time.c:3698
	---
	 test/ruby/test_time.rb |  7 ++-----
	 time.c                 | 57 ++++++++++++++++++++++++--------------------------
	 timev.h                |  7 +++++--
	 3 files changed, 34 insertions(+), 37 deletions(-)
2023-07-17 09:45:57 +09:00

58 lines
1.8 KiB
C

#ifndef RUBY_TIMEV_H
#define RUBY_TIMEV_H
#include "ruby/ruby.h"
struct vtm {
VALUE year; /* 2000 for example. Integer. */
VALUE subsecx; /* 0 <= subsecx < TIME_SCALE. possibly Rational. */
VALUE utc_offset; /* -3600 as -01:00 for example. possibly Rational. */
VALUE zone; /* "JST", "EST", "EDT", etc. as String */
unsigned int yday:9; /* 1..366 */
unsigned int mon:4; /* 1..12 */
unsigned int mday:5; /* 1..31 */
unsigned int hour:5; /* 0..23 */
unsigned int min:6; /* 0..59 */
unsigned int sec:6; /* 0..60 */
unsigned int wday:3; /* 0:Sunday, 1:Monday, ..., 6:Saturday 7:init */
unsigned int isdst:2; /* 0:StandardTime 1:DayLightSavingTime 3:init */
/* Flags for struct time_object */
unsigned int tzmode:3; /* 0:localtime 1:utc 2:fixoff 3:uninitialized */
unsigned int tm_got:1;
};
#define TIME_SCALE 1000000000
#ifndef TYPEOF_TIMEVAL_TV_SEC
# define TYPEOF_TIMEVAL_TV_SEC time_t
#endif
#ifndef TYPEOF_TIMEVAL_TV_USEC
# if INT_MAX >= 1000000
# define TYPEOF_TIMEVAL_TV_USEC int
# else
# define TYPEOF_TIMEVAL_TV_USEC long
# endif
#endif
#if SIZEOF_TIME_T == SIZEOF_LONG
typedef unsigned long unsigned_time_t;
#elif SIZEOF_TIME_T == SIZEOF_INT
typedef unsigned int unsigned_time_t;
#elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
typedef unsigned LONG_LONG unsigned_time_t;
#else
# error cannot find integer type which size is same as time_t.
#endif
/* strftime.c */
#ifdef RUBY_ENCODING_H
VALUE rb_strftime_timespec(const char *format, size_t format_len, rb_encoding *enc,
VALUE time, const struct vtm *vtm, struct timespec *ts, int gmt);
VALUE rb_strftime(const char *format, size_t format_len, rb_encoding *enc,
VALUE time, const struct vtm *vtm, VALUE timev, int gmt);
#endif
/* time.c */
VALUE rb_time_zone_abbreviation(VALUE zone, VALUE time);
#endif