diff --git a/ChangeLog b/ChangeLog index 996b9669c88c01..44b5d351c3e2bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Fri Sep 26 12:52:36 2014 Nobuyoshi Nakada + + * ext/stringio/stringio.c (strio_write): ASCII-8BIT StringIO + should be writable any encoding strings, without conversion. + [ruby-core:65240] [Bug #10285] + +Wed Sep 24 02:30:55 2014 Nobuyoshi Nakada + + * parse.y (parse_ident): just after a label, new expression should + start, cannot be a modifier. [ruby-core:65211] [Bug #10279] + Fri Mar 7 12:06:19 2014 Martin Bosslet * test/openssl/test_ssl.rb: Reuse TLS default options from @@ -11,6 +22,1058 @@ Thu Mar 6 10:33:31 2014 Martin Bosslet Reported by Jeff Hodges. [ruby-core:59829] [Bug #9424] +Fri Sep 19 00:58:34 2014 CHIKANAGA Tomoyuki + + * version.h (RUBY_VERSION): bump RUBY_VERSION to 2.1.3. + +Mon Sep 15 23:12:47 2014 Nobuyoshi Nakada + + * signal.c (check_stack_overflow): drop the last tag too close to + the fault page, to get rid of stack overflow deadlock. + [Bug #9971] + +Mon Sep 15 22:34:39 2014 Natalie Weizenbaum + + * ext/pathname/lib/pathname.rb (SAME_PATHS): + Pathname#relative_path_from uses String#casecmp to compare strings + on case-insensitive filesystem platforms (e.g., Windows). This can + return nil for strings with different encodings, and the code + previously assumed that it always returned a Fixnum. [Fix GH-713] + +Mon Sep 15 22:31:33 2014 Sho Hashimoto + + * ext/fiddle/lib/fiddle/import.rb (Fiddle::Importer#sizeof): fix typo, + SIZEOF_LONG_LON. [Fix GH-714] + +Mon Sep 15 11:08:23 2014 Shota Fukumori + + * lib/mkmf.rb (configuration): Make CXXFLAGS customizable. + Patch by Kohei Suzuki (eagletmt). [Fixes GH-492] + +Mon Sep 15 01:06:35 2014 Nobuyoshi Nakada + + * lib/mkmf.rb (MakeMakefile#pkg_config): append --cflags to also + $CXXFLAGS, as they are often used by C++ compiler. + [ruby-core:54532] [Bug #8315] + +Mon Sep 15 00:02:20 2014 Nobuyoshi Nakada + + * lib/csv.rb (CSV#<<): honor explicitly given encoding. based on + the patch by DAISUKE TANIWAKI at + [ruby-core:62113]. [Bug #9766] + +Wed Sep 10 23:36:38 2014 Koichi Sasada + + * test/ruby/test_object.rb: extend timeout. + +Wed Sep 10 23:36:38 2014 Nobuyoshi Nakada + + * object.c (rb_obj_copy_ivar): allocate no memory for empty + instance variables. [ruby-core:64700] [Bug #10191] + +Wed Sep 10 23:36:38 2014 Nobuyoshi Nakada + + * object.c (rb_obj_copy_ivar): extract function to copy instance + variables only for T_OBJECT from init_copy. + +Wed Sep 10 23:14:42 2014 NARUSE, Yui + + merge r46831 partially. extracted commits are as follows. [Bug #9344] + https://github.com/k-takata/Onigmo/commit/bdfc1997aa15b6baddaf9a482c6610b32504bd86 + + * regcomp.c: Merge Onigmo 5.14.1 25a8a69fc05ae3b56a09. + this includes Support for Unicode 7.0 [Bug #9092]. + +Wed Sep 10 22:58:25 2014 Nobuyoshi Nakada + + * common.mk (Doxyfile): revert r43888, not to require preinstalled + ruby. [ruby-core:64488] [Bug #10161] + +Wed Sep 10 03:29:48 2014 Nobuyoshi Nakada + + * io.c (io_close): ignore only "closed stream" IOError and + NoMethodError, do not swallow other exceptions at the end of + block. [ruby-core:64463] [Bug #10153] + +Wed Sep 10 03:17:13 2014 Nobuyoshi Nakada + + * enc/trans/euckr-tbl.rb (EUCKR_TO_UCS_TBL): add missing euro and + registered signs. [ruby-core:64452] [Bug #10149] + +Wed Sep 10 03:01:31 2014 Eric Wong + + * time.c (time_timespec): fix tv_nsec overflow + [Bug #10144] + +Wed Sep 10 02:51:38 2014 Koichi Sasada + + * iseq.c (rb_iseq_clone): Should not insert write barrier from + non-RVALUE data (to non-RVALUE data, of course). + + Ruby 2.1 also has a same problem. + +Wed Sep 10 02:33:08 2014 Koichi Sasada + + * parse.y (setup_fake_str): fake strings should not set class by + RBASIC_SET_CLASS() because it insert write barriers to fake + (non-RVALUE) structure. + + It can cause unexpected behaviour. + +Fri Sep 5 17:01:38 2014 Zachary Scott + + * lib/rdoc/generator/template/darkfish/js/jquery.js: Backport + rdoc/rdoc@74f60fcb04fee1778fe2694d1a0ea6513f8e67b7 + +Sat Sep 6 00:57:07 2014 Eric Wong + + * ext/zlib/zlib.c (gzfile_reset): preserve ZSTREAM_FLAG_GZFILE + [Bug #10101] + + * test/zlib/test_zlib.rb (test_rewind): test each_byte + +Sat Sep 6 00:47:32 2014 Nobuyoshi Nakada + + * configure.in (rb_cv_broken_backtrace): exit with failure + normally, no needs to abort. [ruby-core:63678] [Bug #10008] + +Sat Sep 6 00:05:02 2014 Nobuyoshi Nakada + + * include/ruby/win32.h, win32/win32.c (rb_w32_inet_pton): add a + wrapper function for inet_pton minimum supported client is + Vista, as well as inet_ntop. + +Sat Sep 6 00:05:02 2014 Kazuhiro NISHIYAMA + + * ext/socket/raddrinfo.c (rb_getaddrinfo): second argument of + MEMZERO is type. Coverity Scan found this bug. + +Sat Sep 6 00:05:02 2014 Tanaka Akira + + * ext/socket/raddrinfo.c (numeric_getaddrinfo): Use xcalloc. + Suggested by Eric Wong. + https://bugs.ruby-lang.org/issues/9525#note-14 + +Sat Sep 6 00:05:02 2014 Tanaka Akira + + * ext/socket: Bypass getaddrinfo() if node and serv are numeric. + Reporeted by Naotoshi Seo. [ruby-core:60801] [Bug #9525] + + * ext/socket/extconf.rb: Detect struct sockaddr_in6.sin6_len. + + * ext/socket/sockport.h (SET_SIN6_LEN): New macro. + (INIT_SOCKADDR_IN6): Ditto. + + * ext/socket/rubysocket.h (struct rb_addrinfo): Add + allocated_by_malloc field. + + * ext/socket/raddrinfo.c (numeric_getaddrinfo): New function. + (rb_getaddrinfo): Call numeric_getaddrinfo at first. + (rb_freeaddrinfo): Free struct addrinfo properly when it is + allocated by numeric_getaddrinfo. + +Sat Sep 6 00:05:02 2014 Tanaka Akira + + * ext/socket: Wrap struct addrinfo by struct rb_addrinfo. + +Thu Sep 4 00:31:23 2014 Nobuyoshi Nakada + + * ext/thread/thread.c (get_array): check instance variables are + initialized properly. [ruby-core:63826][Bug #10062] + +Thu Sep 4 00:29:10 2014 Nobuyoshi Nakada + + * io.c (rb_io_initialize): [DOC] fix rdoc of append mode. it does + not move the pointer at open. [ruby-core:63747] [Bug #10039] + +Thu Sep 4 00:23:15 2014 Nobuyoshi Nakada + + * sprintf.c (GETASTER): should not use the numbered argument to be + formatted, raise ArgumentError instead. + [ruby-dev:48330] [Bug #9982] + +Thu Sep 4 00:21:05 2014 SHIBATA Hiroshi + + * test/openssl/test_pkey_rsa.rb (OpenSSL#test_sign_verify_memory_leak): + added timeout into testcase for low performance environment. + [Bug #9984][ruby-core:63367] + +Tue Sep 2 02:21:58 2014 Nobuyoshi Nakada + + * hash.c (env_aset, env_has_key, env_assoc, env_has_value), + (env_rassoc, env_key): prohibit tainted strings if $SAFE is + non-zero. [Bug #9976] + +Tue Sep 2 02:08:12 2014 Nobuyoshi Nakada + + * signal.c (rb_f_kill): directly enqueue an ignored signal to self, + except for SIGSEGV and SIGBUS. [ruby-dev:48203] [Bug #9820] + +Sun Aug 31 01:13:21 2014 Koichi Sasada + + * gc.c: change full GC timing to keep lower memory usage. + + Extend heap only at + (1) after major GC + or + (2) after several (two times, at current) minor GC + + Details in https://bugs.ruby-lang.org/issues/9607#note-9 + [Bug #9607] + +Sun Aug 31 01:07:05 2014 Masaki Suketa + + * ext/win32ole/win32ole.c (ole_create_dcom): use the converted + result if the argument can be converted to a string, to get rid + of invalid access. Thanks to nobu. [ruby-dev:48467] [Bug #10127] + +Sun Aug 31 00:54:47 2014 Nobuyoshi Nakada + + * process.c (open): use UTF-8 version function to support + non-ascii path properly. [ruby-core:63185] [Bug #9946] + +Tue Aug 26 00:08:40 2014 Nobuyoshi Nakada + + * configure.in (RUBY_SETJMP_TYPE): check for setjmp type after + CCDLFLAGS is appended to CFLAGS, since __builtin_setjmp can be + affected. [ruby-core:62469] [Bug #9818] + +Tue Aug 26 00:07:20 2014 Nobuyoshi Nakada + + * configure.in: get rid of __builtin_setjmp/__builtin_longjmp on + x64-mingw, which causes SEGV with callcc. + [ruby-core:61887] [Bug #9710] + +Tue Aug 26 00:06:05 2014 Nobuyoshi Nakada + + * configure.in (ac_cv_func___builtin_setjmp): should not skip + flags restoration in RUBY_WERROR_FLAG by `break`. + [ruby-dev:48086] [Bug #9698] + +Tue Aug 26 00:02:51 2014 Nobuyoshi Nakada + + * configure.in (ac_cv_func___builtin_setjmp): __builtin_longjmp() + in Apple LLVM 5.1 (LLVM 3.4svn) uses `void**`, not `jmp_buf`. + [Bug #9692] + +Tue Aug 26 00:02:51 2014 Nobuyoshi Nakada + + * configure.in (ac_cv_func___builtin_setjmp): gcc 4.9 disallows a + variable as the second argument of __builtin_longjmp(). + [ruby-core:61800] [Bug #9692] + +Mon Aug 25 00:36:56 2014 Nobuyoshi Nakada + + * parse.y (parser_yylex): fix invalid char in eval, should raise + an syntax error too, as well as directly coded. + [ruby-core:64243] [Bug #10117] + +Mon Aug 25 00:26:12 2014 Nobuyoshi Nakada + + * parse.y (parser_yyerror): preserve source code encoding in + syntax error messages. [ruby-core:64228] [Bug #10114] + +Sat Aug 23 02:39:20 2014 Nobuyoshi Nakada + + * vm_insnhelper.c (vm_call_method): unusable super class should cause + method missing when BasicObject is refined but not been using. + [ruby-core:64166] [Bug #10106] + +Sat Aug 23 02:22:02 2014 Nobuyoshi Nakada + + * string.c (rb_str_count): fix wrong single-byte optimization. + 7bit ascii can be a trailing byte in Shift_JIS. + [ruby-dev:48442] [Bug #10078] + +Thu Aug 21 01:44:46 2014 Tanaka Akira + + * gc.c (mark_current_machine_context): Call SET_STACK_END. + This reverts a hunk of r40703 by ko1. + This fixes [ruby-dev:48098] [Bug #9717]. + +Thu Aug 21 01:41:09 2014 Tanaka Akira + + * lib/time.rb (Time.parse): [DOC] Fix an example in the documentation + to use EST. + Reported by Marcus Stollsteimer. + [ruby-core:60778] [Bug #9521] and [ruby-core:61718] [Bug #9682] + +Thu Aug 21 01:41:09 2014 Zachary Scott + + * lib/time.rb: [DOC] Fix timezone in example of Time.parse [Bug #9521] + Based on patch by @stomar + +Tue Aug 19 23:31:48 2014 CHIKANAGA Tomoyuki + + merge r46831 partially. extracted commits are as follows. + https://github.com/k-takata/Onigmo/commit/b9fba1dc63ccb42a86e934011b468e6022fabb74 + https://github.com/k-takata/Onigmo/commit/c1fc76b9bd463948ffc5058bc352bf93732f0314 + https://github.com/k-takata/Onigmo/commit/a0efc0a200f7108ca3d5ac3039c8f952e0051619 + https://github.com/k-takata/Onigmo/commit/c7cda4ed5676167b0d01bb5555724f6164fbdb13 + [Bug #8716] + + * include/ruby/oniguruma.h (ONIG_MAX_CAPTURE_GROUP_NUM, + ONIGERR_TOO_MANY_CAPTURE_GROUPS): add cheking the number of capture + groups. + + * regerror.c (onig_error_code_to_format): ditto. + + * regparse.c (scan_env_add_mem_entry): ditto. + + * regexec.c (onig_region_copy, match_at): fix: segmation fault occurs + when many groups are used. + +Mon Aug 18 23:38:21 2014 Nobuyoshi Nakada + + * encoding.c (enc_find): [DOC] never accepted a symbol. + [ruby-dev:48308] [Bug #9966] + +Mon Aug 18 23:22:03 2014 Nobuyoshi Nakada + + * string.c (rb_str_resize): update capa only when buffer get + reallocated. + http://d.hatena.ne.jp/nagachika/20140613/ruby_trunk_changes_46413_46420#r46413 + +Mon Aug 18 23:22:03 2014 Nobuyoshi Nakada + + * string.c (rb_str_resize): should consider the capacity instead + of the old length, as pointed out by nagachika. + +Mon Aug 18 23:22:03 2014 Nobuyoshi Nakada + + * file.c (expand_path): shrink expanded path which no longer needs + rooms to append. [ruby-core:63114] [Bug #9934] + +Mon Aug 11 23:55:32 2014 Mark Lorenz + + * lib/erb.rb (result): [DOC] no longer accepts a Proc, as + Kernel.eval does not. [fix GH-619] + +Mon Aug 11 23:38:20 2014 Tanaka Akira + + * io.c (rb_io_autoclose_p): Don't raise on frozen IO. + +Mon Aug 11 23:38:20 2014 Nobuyoshi Nakada + + * io.c (rb_io_fileno, rb_io_inspect): non-modification does not + error on frozen IO. [ruby-dev:48241] [Bug #9865] + +Mon Aug 11 22:34:47 2014 Nobuyoshi Nakada + + * configure.in (posix_fadvise): disable use of posix_fadvise + itself on 32-bit AIX. [ruby-core:62968] [Bug #9914] + +Mon Aug 11 22:34:47 2014 + + * io.c (rb_io_advise): AIX currently does not support a 32-bit call to + posix_fadvise() if _LARGE_FILES is defined. Patch by Rei Odaira. + [ruby-core:62968] [Bug #9914] + +Mon Aug 11 22:14:28 2014 Nobuyoshi Nakada + + * vm_insnhelper.c (vm_callee_setup_keyword_arg): adjust VM stack + pointer to get rid of overwriting splat arguments by arguments + for `to_hash` conversion. [ruby-core:63593] [Bug #10016] + +Fri Aug 8 23:36:01 2014 Nobuyoshi Nakada + + * ext/stringio/stringio.c (strio_write): use rb_str_append to + reuse coderange bits other than ASCII-8BIT, and keep + taintedness. [ruby-dev:48118] [Bug #9769] + +Mon Aug 4 01:29:57 2014 Nobuyoshi Nakada + + * hash.c (env_shift): fix memory leak on Windows, free environment + strings block always. [ruby-dev:48332] [Bug #9983] + +Mon Aug 4 01:26:46 2014 Nobuyoshi Nakada + + * hash.c (env_select): fix memory leak and crash on Windows, make + keys array first instead of iterating on environ directly. + [ruby-dev:48325] [Bug #9978] + +Mon Aug 4 01:24:09 2014 Nobuyoshi Nakada + + * hash.c (ruby_setenv): fix memory leak on Windows, free + environment strings block after check for the size. + [ruby-dev:48323] [Bug #9977] + +Mon Aug 4 01:11:07 2014 Nobuyoshi Nakada + + * re.c (match_aref, rb_reg_regsub): consider encoding of captured + names, encoding-incompatible should not match. + [ruby-dev:48278] [Bug #9903] + +Mon Aug 4 00:52:42 2014 Koichi Sasada + + * vm_eval.c (rb_catch_protect): fix same problem of [Bug #9961]. + + * vm_eval.c (rb_iterate): ditto. + +Mon Aug 4 00:52:42 2014 Koichi Sasada + + * vm.c (rb_vm_rewind_cfp): add new function to rewind specified cfp + with invoking RUBY_EVENT_C_RETURN. + [Bug #9961] + + * vm_core.h: ditto. + + * eval.c (rb_protect): use it. + + * eval.c (rb_rescue2): ditto. + + * vm_eval.c (rb_iterate): ditto. + + * test/ruby/test_settracefunc.rb: add a test. + + * vm_core.h (rb_vm_rewind_cfp): add the prototype declaration. + +Sun Aug 3 00:06:10 2014 Charlie Somerville + + * node.c (dump_node): handle nd_value == (NODE *)-1 to mean this + keyword argument is required + +Thu Jul 31 01:56:11 2014 Koichi Sasada + + * compile.c (rb_iseq_compile_node): put start label of block after + trace (b_call). + [Bug #9964] + + * test/ruby/test_settracefunc.rb: add a test. + + added assert_consistent_call_return() method check call/return + consistency. + +Thu Jul 31 01:22:43 2014 Koichi Sasada + + * vm.c (invoke_block_from_c): move call/return event timing for + bmethod. It can invoke inconsistent call event if this call raises + argument error. + [Bug #9959] + + * vm_insnhelper.c (vm_call_bmethod_body): ditto. + + * test/ruby/test_settracefunc.rb: add a test. + +Thu Jul 31 01:12:55 2014 Koichi Sasada + + * vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or + rescue clause. + + * vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure. + + * test/ruby/test_settracefunc.rb: should not invoke b_return at rescue + clause. + [Bug #9957] + + * vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE. + + * vm_dump.c (vm_stack_dump_each): ditto. + +Thu Jul 31 00:44:34 2014 Koichi Sasada + + * vm_trace.c: clear and restore recursive checking thread local data + to avoid unexpected throw from TracePoint. + [Bug #9940] + + * test/ruby/test_settracefunc.rb: add a test. + + * thread.c: added + * rb_threadptr_reset_recursive_data(rb_thread_t *th); + * rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old); + + * vm_core.h: ditto. + +Wed Jul 23 23:49:59 2014 Hiroshi Shirosaki + + * lib/test/unit/parallel.rb: fix test-all parallel failure if a test + is skipped after raise. + DL::TestFunc#test_sinf is skipped after raise on mingw ruby. + But it causes Marshal.load failure due to undefined class/module + DL::DLError when doing test-all parallel and test-all doesn't + complete. We create new MiniTest::Skip object to avoid Marshal.load + failure. + [ruby-core:62133] [Bug #9767] + + * test/testunit/test_parallel.rb (TestParallel): add a test. + + * test/testunit/tests_for_parallel/ptest_forth.rb: ditto. + +Wed Jul 23 23:11:28 2014 SHIBATA Hiroshi + + * test/socket/test_socket.rb: unix socket is required by test case. + +Wed Jul 23 23:11:28 2014 SHIBATA Hiroshi + + * test/socket/test_addrinfo.rb: remove unused variables. + * test/socket/test_nonblock.rb: ditto. + * test/socket/test_socket.rb: ditto. + * test/socket/test_unix.rb: ditto. + * test/testunit/test_parallel.rb: ditto. + * test/webrick/test_filehandler.rb: ditto. + * test/xmlrpc/test_features.rb: ditto. + * test/zlib/test_zlib.rb: ditto. + +Wed Jul 23 23:05:19 2014 Tanaka Akira + + * ext/pathname/lib/pathname.rb (cleanpath_aggressive): make all + separators File::SEPARATOR from File::ALT_SEPARATOR. + Reported by Daniel Rikowski. + Fixed by Nobuyoshi Nakada. [Bug #9618] + + * ext/pathname/lib/pathname.rb (cleanpath_conservative): ditto. + +Wed Jul 23 22:51:34 2014 Naohisa Goto + + * lib/fileutils.rb (rmdir): rescue Errno::EEXIST in addition to + ENOTEMPTY (and ENOENT), because SUSv3 describes that "If the + directory is not an empty directory, rmdir() shall fail and set + errno to [EEXIST] or [ENOTEMPTY]" and Solaris uses EEXIST. + [Bug #9571] [ruby-dev:48017] + +Wed Jul 23 22:43:50 2014 Tanaka Akira + + * lib/resolv.rb (bind_random_port): Rescue EPERM for FreeBSD which + security.mac.portacl.port_high is changed. + See mac_portacl(4) for details. + Reported by Jakub Szafranski. [ruby-core:60917] [Bug #9544] + +Wed Jul 23 22:24:26 2014 CHIKANAGA Tomoyuki + + * test/openssl/test_x509cert.rb: split assertions into algorithms. + CentOS 7 seems finish MD5 support + http://chkbuild005.hsbt.org/chkbuild/ruby-trunk/log/20140722T140010Z.fail.html.gz + + * test/openssl/test_x509req.rb: ditto. + +Sat Jul 19 01:44:34 2014 Nobuyoshi Nakada + + * re.c (match_aref): should not ignore name after NUL byte. + [ruby-dev:48275] [Bug #9902] + +Sun Jul 13 23:28:41 2014 SHIBATA Hiroshi + + * test/test_timeout.rb (test_timeout): inverted test condition. + [Bug #8523] + +Sun Jul 13 23:18:11 2014 Nobuyoshi Nakada + + * ext/digest/digest.c (rb_digest_instance_equal): no need to call + `to_s` twice. [Bug #9913] + +Sun Jul 13 23:18:11 2014 Benoit Daloze + + * ext/digest/digest.c (rb_digest_instance_equal): + fix #== for non-string arguments. [ruby-core:62967] [Bug #9913] + + * test/digest/test_digest.rb: add test for above. + +Sun Jul 13 23:10:03 2014 Nobuyoshi Nakada + + * array.c (yield_indexed_values): extract from permute0(), + rpermute0(), and rcombinate0(). + +Sun Jul 13 23:02:36 2014 Nobuyoshi Nakada + + * array.c (rb_ary_permutation): `p` is the array of size `r`, as + commented at permute0(). since `n >= r` here, buffer overflow + never happened, just reduce unnecessary allocation though. + +Sun Jul 13 22:52:43 2014 Nobuyoshi Nakada + + * pack.c (encodes): fix buffer overrun by tail_lf. Thanks to + Mamoru Tasaka and Tomas Hoger. [ruby-core:63604] [Bug #10019] + +Sun Jul 13 22:44:05 2014 Nobuyoshi Nakada + + * ext/thread/thread.c (undumpable): ConditionVariable and Queue + are not dumpable. [ruby-core:61677] [Bug #9674] + +Fri Jul 11 23:07:09 2014 Marc-Andre Lafortune + + * lib/matrix.rb: Fix sign for cross_product [#9499] + +Sun Jul 6 23:16:30 2014 Masaya Tarui + + * st.c (st_foreach_check): change start point of search at check + from top to current. [ruby-dev:48047] [Bug #9646] + +Sun Jul 6 22:56:03 2014 Zachary Scott + + * lib/gserver.rb: [DOC] Fixed typo in example by @stomar [Bug #9543] + +Fri Jul 4 00:46:03 2014 Zachary Scott + + * enumerator.c: [DOC] Fix example to show Enumerator#peek behavior + Patch by Erik Hollembeak [Bug #9814] + +Fri Jul 4 00:44:43 2014 Zachary Scott + + * enum.c: [DOC] Use #find in example to clarify alias by @rachellogie + Patch submitted via documenting-ruby/ruby#34 + +Fri Jul 4 00:42:57 2014 SHIBATA Hiroshi + + * man/ruby.1: remove deadlink. [ruby-core:62145][Bug #9773] + +Fri Jul 4 00:25:16 2014 Nobuyoshi Nakada + + * struct.c (not_a_member): extract name error and use same error + messages. based on the patch by Marcus Stollsteimer at [ruby-core:61721]. [Bug #9684] + +Thu Jul 3 01:19:50 2014 CHIKANAGA Tomoyuki + + * numeric.c (num_step_scan_args): table argument of rb_get_kwargs() is + array of IDs, not Symbols. [ruby-dev:48353] [Bug #9811] + +Thu Jul 3 01:19:50 2014 Nobuyoshi Nakada + + * numeric.c (num_step_scan_args): check keyword arguments and fail + if they conflict with positional arguments. + [ruby-dev:48177] [Bug #9811] + +Tue Jul 1 03:05:22 2014 Nobuyoshi Nakada + + * io.c (read_all): truncate the buffer before appending read data, + instead of truncating before reading. + [ruby-core:55951] [Bug #8625] + +Tue Jul 1 03:05:22 2014 Nobuyoshi Nakada + + * io.c (io_setstrbuf, io_read): should not shorten the given buffer until + read succeeds. [ruby-core:55951] [Bug #8625] + +Mon Jun 30 03:15:59 2014 Nobuyoshi Nakada + + * vm.c (core_hash_merge_kwd): should return the result hash, which + may be converted from and differ from the given argument. + [ruby-core:62921] [Bug #9898] + +Mon Jun 30 03:07:22 2014 Shugo Maeda + + * lib/net/ftp.rb (gets, readline): read lines without LF properly. + [ruby-core:63205] [Bug #9949] + + * test/net/ftp/test_buffered_socket.rb: related test. + +Mon Jun 30 02:59:08 2014 Shugo Maeda + + * lib/net/imap.rb (body_type_1part): Gmail IMAP reports a body + type as "MIXED" followed immediately by params + [ruby-core:62864] [Bug #9885] + Patch by @rayners (David Raynes). [Fixes GH-622] + https://github.com/ruby/ruby/pull/622 + +Mon Jun 30 02:46:44 2014 Rei Odaira + + * signal.c (ruby_signal): should return either `old.sa_sigaction` + or `old.sa_handler`, depending on whether `SA_SIGINFO` is set in + `old.sa_flags`, because they may not be a union. + [ruby-core:62836] [Bug #9878] + +Mon Jun 30 02:36:08 2014 Eric Wong + + * process.c (proc_getgroups, proc_setgroups): use ALLOCV_N + [Bug #9856] + +Mon Jun 30 02:28:10 2014 Nobuyoshi Nakada + + * io.c (io_setstrbuf): always check if the buffer is modifiable. + [ruby-core:62643] [Bug #9847] + +Mon Jun 30 02:25:00 2014 Tanaka Akira + + * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLServer#accept): + Consider Socket#accept as well as TCPServer#accept. + Reported by Sam Stelfox. [ruby-core:62064] [Bug #9750] + +Mon Jun 30 02:18:47 2014 Eric Wong + + * complex.c (parse_comp): replace ALLOCA_N with ALLOCV_N/ALLOCV_END + [Bug #9608] + * rational.c (read_digits): ditto + +Mon Jun 30 02:10:34 2014 Nobuyoshi Nakada + + * vsnprintf.c (BSD_vfprintf): fix string width when precision is + given. as the result of `memchr` is NULL or its offset from the + start cannot exceed the size, the comparison was always false. + [ruby-core:62737] [Bug #9861] + +Mon Jun 30 01:46:19 2014 Nobuyoshi Nakada + + * ext/fiddle/extconf.rb: supply 0 to fill RUBY_LIBFFI_MODVERSION + with 3-digit. libffi 3.1 returns just 2-digit. + [ruby-core:62920] [Bug #9897] + +Mon Jun 30 00:57:05 2014 Koichi Sasada + + * vm.c (rb_vm_pop_cfunc_frame): added. It cares c_return event. + The patch base by drkaes (Stefan Kaes). + [Bug #9321] + + * variable.c (rb_mod_const_missing): use rb_vm_pop_cfunc_frame() + instead of rb_frame_pop(). + + * vm_eval.c (raise_method_missing): ditto. + + * vm_eval.c (rb_iterate): ditto. + + * internal.h (rb_vm_pop_cfunc_frame): add decl. + + * test/ruby/test_settracefunc.rb: add tests. + provided by drkaes (Stefan Kaes). + + * vm.c, eval.c, include/ruby/intern.h (rb_frame_pop): + move definition of rb_frame_pop() and deprecate it. + It doesn't care about `return' events. + +Sun Jun 29 01:34:06 2014 Tanaka Akira + + * lib/webrick/utils.rb (create_listeners): Close socket objects. + +Sat Jun 28 16:35:51 2014 Nobuyoshi Nakada + + * string.c (rb_str_substr): need to reset code range for shared + string too, not only copied string. + [ruby-core:62842] [Bug #9882] + +Sat Jun 28 14:37:17 2014 Nobuyoshi Nakada + + * parse.y (local_tbl_gen): remove local variables duplicated with + arguments. + [ruby-core:60501] [Bug #9486] + +Tue Jun 24 00:21:58 2014 Koichi Sasada + + * eval.c (rb_using_refinement): add write-barriers for + cref->nd_refinements. + +Tue Jun 24 00:14:20 2014 Tanaka Akira + + * lib/net/ftp.rb (transfercmd): Close TCP server socket even if an + exception occur. + +Tue Jun 24 00:06:41 2014 Hiroshi Shirosaki + + * thread_win32.c (rb_w32_stack_overflow_handler): use Structured + Exception Handling by AddVectoredExceptionHandler() for machine + stack overflow on mingw. + This would be equivalent to the handling using __try and __except + on mswin introduced by r43748. + +Mon Jun 23 23:56:54 2014 Eric Wong + + * signal.c (signal_exec): ignore immediate cmd for SIG_IGN + * signal.c (trap_handler): set cmd to true for SIG_IGN + * signal.c (trap): handle nil and true values for oldcmd + [Bug #9835] + +Mon Jun 23 02:46:14 2014 Nobuyoshi Nakada + + * class.c (rb_mod_init_copy): always clear instance variable, + constant and method tables first, regardless the source tables. + [ruby-dev:48182] [Bug #9813] + +Mon Jun 23 02:36:04 2014 Nobuyoshi Nakada + + * thread.c (thread_start_func_2): stop if forked in a sub-thread, + the thread has become the main thread. + [ruby-core:62070] [Bug #9751] + +Mon Jun 23 01:53:18 2014 Josh Goebel + + * net/protocol.rb (using_each_crlf_line): fix SMTP dot-stuffing + for messages not ending with a new-line. + [ruby-core:61441] [Bug #9627] [fix GH-616] + +Fri Jun 20 00:40:06 2014 Nobuyoshi Nakada + + * thread_pthread.c (ruby_init_stack, ruby_stack_overflowed_p): + place get_stack above others to get stack boundary information. + [ruby-core:60113] [Bug #9454] + +Fri Jun 20 00:40:06 2014 NARUSE, Yui + + * thread_pthread.c: rlimit is only available on Linux. + At least r44712 breaks FreeBSD. + [ruby-core:60113] [Bug #9454] + +Fri Jun 20 00:40:06 2014 Nobuyoshi Nakada + + * thread_pthread.c: get current main thread stack size, which may + be expanded than allocated size at initialization, by rlimit(). + [ruby-core:60113] [Bug #9454] + +Fri Jun 20 00:20:02 2014 Hiroshi Shirosaki + + * configure.in: enable SSE2 on mingw. target='i386-pc-mingw32'. + [ruby-core:62095] [Bug #8358] + +Tue Jun 17 00:45:44 2014 Nobuyoshi Nakada + + * compile.c (compile_array_): make copy a first hash not to modify + the argument itself. keyword splat should be non-destructive. + [ruby-core:62161] [Bug #9776] + +Tue Jun 17 00:37:15 2014 Bugra Barin + + * dln.c (dln_load): use wchar version to load a library in + non-ascii path on Windows. based on the patch by Bugra Barin + in [ruby-core:61845]. [Bug #9699] + +Tue Jun 17 00:26:59 2014 Nobuyoshi Nakada + + * process.c (obj2uid, obj2gid): now getpwnam_r() and getgrnam_r() + may need larger buffers than sysconf values, so retry with + expanding the buffer when ERANGE is returned. + [ruby-core:61325] [Bug #9600] + +Wed Jun 11 22:58:30 2014 Eric Wong + + * gc.c (ruby_gc_set_params): simplify condition + +Wed Jun 11 22:58:30 2014 Eric Wong + + * gc.c (ruby_gc_set_params): fix building without RGenGC + +Wed Jun 11 02:43:32 2014 Kazuki Tsujimoto + + * test/objspace/test_objspace.rb (TestObjSpace#test_dump_uninitialized_file): + remove dependency on json library. + +Wed Jun 11 02:43:32 2014 Scott Francis + + * ext/objspace/objspace_dump.c: Check fptr before trying to dump RFILE + object fd. [GH-562] + + * test/objspace/test_objspace.rb: add test + +Wed Jun 11 02:27:55 2014 Akinori MUSHA + + * configure.in: Fix a build problem with clang and --with-opt-dir. + If ruby is configured with --with-opt-dir=dir when using clang + as compiler, a warning `clang: warning: argument unused during + compilation: '-I dir'` is emitted almost every time clang + compiles a file. Unfortunately, RUBY_CHECK_PRINTF_PREFIX takes + any output from the compiler as fatal error, and the check thus + fails due to the warning. This is an attempt to fix the problem + by adding a flag -Qunused-arguments to CFLAGS locally in the + function to suppress the warning. [ruby-dev:48062] [Bug #9658] + [Fixes GH-571] https://github.com/ruby/ruby/pull/571 + +Wed Jun 11 02:18:34 2014 Marc-Andre Lafortune + + * numeric.c: Fix Numeric#step with 0 unit [Bug #9575] + +Wed Jun 11 00:36:05 2014 CHIKANAGA Tomoyuki + + * test/ruby/test_string (test_LSHIFT_neary_long_max): extend timeout. + this test fails on some CI environment by timeout. + +Sat Jun 7 01:17:16 2014 Tanaka Akira + + * signal.c (check_stack_overflow): Don't use ucontext_t if ucontext.h + is not available. + Fixes build on Android (x86). + +Tue Jun 3 00:38:33 2014 Eric Wong + + * class.c (rb_class_subclass_add): use xmalloc + * class.c (rb_module_add_to_subclasses_list): ditto + * class.c (rb_class_remove_from_super_subclasses): use xfree + * class.c (rb_class_remove_from_module_subclasses): ditto + [Bug #9616] + +Mon Jun 2 02:19:30 2014 NAKAMURA Usaku + + * win32/win32.c (rb_w32_accept, open_ifs_socket, socketpair_internal): + reset inherit flag of socket to avoid unintentional inheritance of + socket. note that the return value of SetHandleInformation() is not + verified intentionally because old Windows may return an error. + [Bug #9688] [ruby-core:61754] + +Mon Jun 2 02:12:10 2014 Eric Wong + + * time.c (time_mload): freeze and preserve marshal-loaded time zone + * test/ruby/test_time.rb: add test for GC on loaded object + [Bug #9652] + +Mon Jun 2 01:57:59 2014 Nobuyoshi Nakada + + * vm_insnhelper.c (vm_callee_setup_arg): turn a macro into an + inline function. + +Mon Jun 2 01:46:43 2014 Eric Wong + + * variable.c (rb_const_set): delete existing entry on redefinition + [Bug #9645] + * test/ruby/test_const.rb (test_redefinition): test for leak + +Fri May 30 00:13:19 2014 Nobuyoshi Nakada + + * eval.c (setup_exception): preserve errinfo across calling #to_s + method on the exception. [ruby-core:61091] [Bug #9568] + +Thu May 29 20:57:59 2014 Nobuyoshi Nakada + + * numeric.c (ruby_num_interval_step_size): check signs and get rid + of implementation dependent behavior of negative division. + [ruby-core:61106] [Bug #9570] + +Wed May 28 23:47:22 2014 Nobuyoshi Nakada + + * configure.in (rb_cv_func___builtin_unreachable): try with an + external variable not only by a warning, which might not be + shown due to the optimization. [ruby-core:61647] [Bug #9665] + +Wed May 28 23:40:57 2014 Nobuyoshi Nakada + + * ext/openssl/ossl_asn1.c (ossl_asn1_initialize): SYMID on a value + other than Symbol is an undefined behavior. fix up r31699. + [ruby-core:62142] [Bug #9771] + +Wed May 28 23:37:32 2014 Nobuyoshi Nakada + + * ext/stringio/stringio.c (strio_putc): fix for non-ascii + encoding, like as IO#putc. [ruby-dev:48114] [Bug #9765] + +Wed May 28 01:05:06 2014 Nobuyoshi Nakada + + * lib/fileutils.rb (FileUtils#copy_entry): update rdoc about + preserve option and permissions, following r31123. + [ruby-core:62065] [Bug #9748] + +Wed May 28 00:57:06 2014 Nobuyoshi Nakada + + * proc.c (umethod_bind): use the ancestor iclass instead of new + iclass to get rid of infinite recursion, if the defined module + is already included. [ruby-core:62014] [Bug #9721] + +Wed May 28 00:57:06 2014 Nobuyoshi Nakada + + * proc.c (rb_method_call_with_block, umethod_bind): call with + IClass including the module for a module instance method. + [ruby-core:61936] [Bug #9721] + + * vm_insnhelper.c (vm_search_super_method): allow bound + UnboundMethod case. + +Wed May 28 00:38:37 2014 Nobuyoshi Nakada + + * array.c (ary_reject): may be turned into a shared array during + the given block. [ruby-dev:48101] [Bug #9727] + +Wed May 28 00:29:02 2014 Nobuyoshi Nakada + + * string.c (str_buf_cat): should round up the capacity by 4KiB, + but not number of rooms. [ruby-core:61886] [Bug #9709] + +Wed May 28 00:23:11 2014 NARUSE, Yui + + * lib/xmlrpc/client.rb (do_rpc): don't check body length. + If HTTP content-encoding is used, the length may be different. + [Bug #8182] [ruby-core:53811] + +Wed May 28 00:18:29 2014 Tadayoshi Funaba + + * ext/date/date_core.c (d_lite_cmp): should compare with #<. + +Fri May 23 00:04:13 2014 Tanaka Akira + + * ext/socket/socket.c (sock_s_getnameinfo): Save errno for EAI_SYSTEM. + Reported by Saravana kumar. [ruby-core:61820] [Bug #9697] + Fixed by Heesob Park. [ruby-core:61868] + +Fri May 23 00:04:13 2014 Tanaka Akira + + * ext/socket: Wrap struct addrinfo by struct rb_addrinfo. + +Fri May 23 00:04:13 2014 Tanaka Akira + + * ext/socket/ipsocket.c (ip_s_getaddress): Don't access freed memory. + +Mon May 19 00:47:00 2014 Koichi Sasada + + * test/ruby/test_array.rb: remove useless `assert'. + +Mon May 19 00:47:00 2014 Koichi Sasada + + * array.c (rb_ary_modify): remember shared array owner if a shared + array owner is promoted and a shared array is not promoted. + + Now, shared array is WB-unprotected so that shared arrays are not + promoted. All objects referred from shared array should be marked + correctly. + + [ruby-core:61919] [ruby-trunk - Bug #9718] + + * test/ruby/test_array.rb: add a test for above. + +Mon May 19 00:26:53 2014 Nobuyoshi Nakada + + * parse.y (parser_yylex): only a newline after label should be + significant. [ruby-core:61658] [Bug #9669] + +Mon May 19 00:26:53 2014 Nobuyoshi Nakada + + * parse.y (lex_state_e, parser_params, f_arglist, parser_yylex): + separate EXPR_LABELARG from EXPR_BEG and let newline significant, + so that required keyword argument can place at the end of + argument list without parentheses. [ruby-core:61658] [Bug #9669] + +Fri May 16 00:27:02 2014 James Edward Gray II + + * lib/csv.rb: Fixed a broken regular expression that was causing + CSV to miss escaping some special meaning characters when used + in parsing. + Reported by David Unric + [ruby-core:54986] [Bug #8405] + +Fri May 16 00:14:25 2014 Kohei Suzuki + + * vm_method.c (rb_method_entry_get_without_cache): me->klass is 0 + for a method aliased in a module. [ruby-core:61636] [Bug #9663] + +Fri May 16 00:14:25 2014 Nobuyoshi Nakada + + * vm_method.c (rb_method_entry_get_without_cache): get rid of + infinite recursion at aliases in a subclass and a superclass. + return actually defined class for other than singleton class. + [ruby-core:60431] [Bug #9475] + +Mon May 12 22:53:08 2014 Nobuyoshi Nakada + + * parse.y (primary): flush cmdarg flags inside left-paren in a + command argument, to allow parenthesed do-block as an argument + without arguments parentheses. [ruby-core:61950] [Bug #9726] + +Mon May 12 22:22:43 2014 Koichi Sasada + + * vm.c (invoke_block_from_c): add VM_FRAME_FLAG_BMETHOD to record + it is bmethod frame. + + * vm.c (vm_exec): invoke RUBY_EVENT_RETURN event if rollbacked frame + is VM_FRAME_FLAG_BMETHOD. + [Bug #9759] + + * test/ruby/test_settracefunc.rb: add a test for TracePoint/set_trace_func. + + * vm_core.h: rename rb_thread_t::passed_me to + rb_thread_t::passed_bmethod_me to clarify the usage. + + * vm_insnhelper.c (vm_call_bmethod_body): use renamed member. + +Mon May 12 22:11:47 2014 Shota Fukumori + + * vm_eval.c (eval_string_with_cref): Unify to use NIL_P. + +Mon May 12 22:11:47 2014 Shota Fukumori + + * vm_eval.c (eval_string_with_cref): Use file path even if scope is + given. Related to [ruby-core:56099] [Bug #8662] and r42103. + Thu May 8 01:13:10 2014 NARUSE, Yui * configure.in: correct pthread_setname_np's prototype on NetBSD. diff --git a/README.EXT b/README.EXT index b1a816c271e0ac..6f7340cedaafd5 100644 --- a/README.EXT +++ b/README.EXT @@ -650,7 +650,7 @@ Here's the example of an initializing function. { /* define DBM class */ cDBM = rb_define_class("DBM", rb_cObject); - /* DBM includes Enumerate module */ + /* DBM includes Enumerable module */ rb_include_module(cDBM, rb_mEnumerable); /* DBM has class method open(): arguments are received as C array */ diff --git a/README.EXT.ja b/README.EXT.ja index b4b59008e090db..5ccc9306d10d59 100644 --- a/README.EXT.ja +++ b/README.EXT.ja @@ -726,7 +726,7 @@ Rubyは拡張ライブラリをロードする時に「Init_ライブラリ名 { /* DBMクラスを定義する */ cDBM = rb_define_class("DBM", rb_cObject); - /* DBMはEnumerateモジュールをインクルードする */ + /* DBMはEnumerableモジュールをインクルードする */ rb_include_module(cDBM, rb_mEnumerable); /* DBMクラスのクラスメソッドopen(): 引数はCの配列で受ける */ diff --git a/array.c b/array.c index ff77a3ed949842..79f7d3b5373b4e 100644 --- a/array.c +++ b/array.c @@ -343,6 +343,11 @@ rb_ary_modify(VALUE ary) ARY_SET_CAPA(ary, len); ARY_SET_PTR(ary, ptr); } + + /* TODO: age2 promotion, OBJ_PROMOTED() checks not infant. */ + if (OBJ_PROMOTED(ary) && !OBJ_PROMOTED(shared)) { + rb_gc_writebarrier_remember_promoted(ary); + } } } @@ -898,19 +903,6 @@ rb_ary_push(VALUE ary, VALUE item) return ary; } -static VALUE -rb_ary_push_1(VALUE ary, VALUE item) -{ - long idx = RARRAY_LEN(ary); - - if (idx >= ARY_CAPA(ary)) { - ary_double_capa(ary, idx); - } - RARRAY_ASET(ary, idx, item); - ARY_SET_LEN(ary, idx + 1); - return ary; -} - VALUE rb_ary_cat(VALUE ary, const VALUE *ptr, long len) { @@ -1593,6 +1585,7 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl) MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_CONST_PTR(rpl), VALUE, rlen); } } + RB_GC_GUARD(rpl); } void @@ -3077,7 +3070,7 @@ ary_reject(VALUE orig, VALUE result) for (i = 0; i < RARRAY_LEN(orig); i++) { VALUE v = RARRAY_AREF(orig, i); if (!RTEST(rb_yield(v))) { - rb_ary_push_1(result, v); + rb_ary_push(result, v); } } return result; @@ -4690,6 +4683,25 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) #define tmpary(n) rb_ary_tmp_new(n) #define tmpary_discard(a) (ary_discard(a), RBASIC_SET_CLASS_RAW(a, rb_cArray)) +/* + * Build a ruby array of the corresponding values and yield it to the + * associated block. + * Return the class of +values+ for reentry check. + */ +static int +yield_indexed_values(const VALUE values, const long r, const long *const p) +{ + const VALUE result = rb_ary_new2(r); + VALUE *const result_array = RARRAY_PTR(result); + const VALUE *const values_array = RARRAY_CONST_PTR(values); + long i; + + for (i = 0; i < r; i++) result_array[i] = values_array[p[i]]; + ARY_SET_LEN(result, r); + rb_yield(result); + return !RBASIC(values)->klass; +} + /* * Recursively compute permutations of +r+ elements of the set * [0..n-1]. @@ -4707,7 +4719,7 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) static void permute0(long n, long r, long *p, long index, char *used, VALUE values) { - long i,j; + long i; for (i = 0; i < n; i++) { if (used[i] == 0) { p[index] = i; @@ -4718,17 +4730,7 @@ permute0(long n, long r, long *p, long index, char *used, VALUE values) used[i] = 0; /* index unused */ } else { - /* We have a complete permutation of array indexes */ - /* Build a ruby array of the corresponding values */ - /* And yield it to the associated block */ - VALUE result = rb_ary_new2(r); - VALUE *result_array = RARRAY_PTR(result); - const VALUE *values_array = RARRAY_PTR(values); - - for (j = 0; j < r; j++) result_array[j] = values_array[p[j]]; - ARY_SET_LEN(result, r); - rb_yield(result); - if (RBASIC(values)->klass) { + if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "permute reentered"); } } @@ -4826,7 +4828,7 @@ rb_ary_permutation(int argc, VALUE *argv, VALUE ary) } } else { /* this is the general case */ - volatile VALUE t0 = tmpbuf(n,sizeof(long)); + volatile VALUE t0 = tmpbuf(r,sizeof(long)); long *p = (long*)RSTRING_PTR(t0); volatile VALUE t1 = tmpbuf(n,sizeof(char)); char *used = (char*)RSTRING_PTR(t1); @@ -4897,21 +4899,19 @@ rb_ary_combination(VALUE ary, VALUE num) } } else { - volatile VALUE t0 = tmpbuf(n+1, sizeof(long)); - long *stack = (long*)RSTRING_PTR(t0); - volatile VALUE cc = tmpary(n); - VALUE *chosen = RARRAY_PTR(cc); + VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ + volatile VALUE t0; + long *stack = ALLOCV_N(long, t0, n+1); long lev = 0; - MEMZERO(stack, long, n); + RBASIC_CLEAR_CLASS(ary0); + MEMZERO(stack+1, long, n); stack[0] = -1; for (;;) { - chosen[lev] = RARRAY_AREF(ary, stack[lev+1]); for (lev++; lev < n; lev++) { - chosen[lev] = RARRAY_AREF(ary, stack[lev+1] = stack[lev]+1); + stack[lev+1] = stack[lev]+1; } - rb_yield(rb_ary_new4(n, chosen)); - if (RBASIC(t0)->klass) { + if (!yield_indexed_values(ary0, n, stack+1)) { rb_raise(rb_eRuntimeError, "combination reentered"); } do { @@ -4920,8 +4920,8 @@ rb_ary_combination(VALUE ary, VALUE num) } while (stack[lev+1]+n == len+lev+1); } done: - tmpbuf_discard(t0); - tmpary_discard(cc); + ALLOCV_END(t0); + RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; } @@ -4942,24 +4942,14 @@ rb_ary_combination(VALUE ary, VALUE num) static void rpermute0(long n, long r, long *p, long index, VALUE values) { - long i, j; + long i; for (i = 0; i < n; i++) { p[index] = i; if (index < r-1) { /* if not done yet */ rpermute0(n, r, p, index+1, values); /* recurse */ } else { - /* We have a complete permutation of array indexes */ - /* Build a ruby array of the corresponding values */ - /* And yield it to the associated block */ - VALUE result = rb_ary_new2(r); - VALUE *result_array = RARRAY_PTR(result); - const VALUE *values_array = RARRAY_PTR(values); - - for (j = 0; j < r; j++) result_array[j] = values_array[p[j]]; - ARY_SET_LEN(result, r); - rb_yield(result); - if (RBASIC(values)->klass) { + if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "repeated permute reentered"); } } @@ -5040,7 +5030,6 @@ rb_ary_repeated_permutation(VALUE ary, VALUE num) static void rcombinate0(long n, long r, long *p, long index, long rest, VALUE values) { - long j; if (rest > 0) { for (; index < n; ++index) { p[r-rest] = index; @@ -5048,14 +5037,7 @@ rcombinate0(long n, long r, long *p, long index, long rest, VALUE values) } } else { - VALUE result = rb_ary_new2(r); - VALUE *result_array = RARRAY_PTR(result); - const VALUE *values_array = RARRAY_PTR(values); - - for (j = 0; j < r; ++j) result_array[j] = values_array[p[j]]; - ARY_SET_LEN(result, r); - rb_yield(result); - if (RBASIC(values)->klass) { + if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "repeated combination reentered"); } } diff --git a/bignum.c b/bignum.c index 6c2cda3937692c..b499c0b9730214 100644 --- a/bignum.c +++ b/bignum.c @@ -218,7 +218,7 @@ end */ -#ifdef HAVE_UINT16_T +#if SIZEOF_BDIGIT_DBL == 2 static const int maxpow16_exp[35] = { 15, 10, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -234,8 +234,7 @@ static const uint16_t maxpow16_num[35] = { U16(0x00006978), U16(0x0000745f), U16(0x00008000), U16(0x00008c61), U16(0x00009988), U16(0x0000a77b), U16(0x0000b640), }; -#endif -#ifdef HAVE_UINT32_T +#elif SIZEOF_BDIGIT_DBL == 4 static const int maxpow32_exp[35] = { 31, 20, 15, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, @@ -251,8 +250,7 @@ static const uint32_t maxpow32_num[35] = { U32(0x2b73a840), U32(0x34e63b41), U32(0x40000000), U32(0x4cfa3cc1), U32(0x5c13d840), U32(0x6d91b519), U32(0x81bf1000), }; -#endif -#ifdef HAVE_UINT64_T +#elif SIZEOF_BDIGIT_DBL == 8 && defined HAVE_UINT64_T static const int maxpow64_exp[35] = { 63, 40, 31, 27, 24, 22, 21, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, @@ -278,8 +276,7 @@ static const uint64_t maxpow64_num[35] = { U64(0x211e44f7,0xd02c1000), U64(0x2ee56725,0xf06e5c71), U64(0x41c21cb8,0xe1000000), }; -#endif -#ifdef HAVE_UINT128_T +#elif SIZEOF_BDIGIT_DBL == 16 && defined HAVE_UINT128_T static const int maxpow128_exp[35] = { 127, 80, 63, 55, 49, 45, 42, 40, 38, 37, 35, 34, 33, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 27, 26, 26, 26, 26, 25, 25, 25, 25, 24, diff --git a/class.c b/class.c index 0c18b43eb3eea0..23f36a73e98af9 100644 --- a/class.c +++ b/class.c @@ -42,7 +42,7 @@ rb_class_subclass_add(VALUE super, VALUE klass) rb_subclass_entry_t *entry, *head; if (super && super != Qundef) { - entry = malloc(sizeof(*entry)); + entry = xmalloc(sizeof(*entry)); entry->klass = klass; entry->next = NULL; @@ -62,7 +62,7 @@ rb_module_add_to_subclasses_list(VALUE module, VALUE iclass) { rb_subclass_entry_t *entry, *head; - entry = malloc(sizeof(*entry)); + entry = xmalloc(sizeof(*entry)); entry->klass = iclass; entry->next = NULL; @@ -88,7 +88,7 @@ rb_class_remove_from_super_subclasses(VALUE klass) if (entry->next) { RCLASS_EXT(entry->next->klass)->parent_subclasses = RCLASS_EXT(klass)->parent_subclasses; } - free(entry); + xfree(entry); } RCLASS_EXT(klass)->parent_subclasses = NULL; @@ -107,7 +107,7 @@ rb_class_remove_from_module_subclasses(VALUE klass) RCLASS_EXT(entry->next->klass)->module_subclasses = RCLASS_EXT(klass)->module_subclasses; } - free(entry); + xfree(entry); } RCLASS_EXT(klass)->module_subclasses = NULL; @@ -329,12 +329,21 @@ rb_mod_init_copy(VALUE clone, VALUE orig) } RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig)); RCLASS_EXT(clone)->allocator = RCLASS_EXT(orig)->allocator; + if (RCLASS_IV_TBL(clone)) { + st_free_table(RCLASS_IV_TBL(clone)); + RCLASS_IV_TBL(clone) = 0; + } + if (RCLASS_CONST_TBL(clone)) { + rb_free_const_table(RCLASS_CONST_TBL(clone)); + RCLASS_CONST_TBL(clone) = 0; + } + if (RCLASS_M_TBL_WRAPPER(clone)) { + rb_free_m_tbl_wrapper(RCLASS_M_TBL_WRAPPER(clone)); + RCLASS_M_TBL_WRAPPER(clone) = 0; + } if (RCLASS_IV_TBL(orig)) { st_data_t id; - if (RCLASS_IV_TBL(clone)) { - st_free_table(RCLASS_IV_TBL(clone)); - } RCLASS_IV_TBL(clone) = rb_st_copy(clone, RCLASS_IV_TBL(orig)); CONST_ID(id, "__tmp_classpath__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); @@ -345,18 +354,13 @@ rb_mod_init_copy(VALUE clone, VALUE orig) } if (RCLASS_CONST_TBL(orig)) { struct clone_const_arg arg; - if (RCLASS_CONST_TBL(clone)) { - rb_free_const_table(RCLASS_CONST_TBL(clone)); - } + RCLASS_CONST_TBL(clone) = st_init_numtable(); arg.klass = clone; arg.tbl = RCLASS_CONST_TBL(clone); st_foreach(RCLASS_CONST_TBL(orig), clone_const_i, (st_data_t)&arg); } if (RCLASS_M_TBL(orig)) { - if (RCLASS_M_TBL_WRAPPER(clone)) { - rb_free_m_tbl_wrapper(RCLASS_M_TBL_WRAPPER(clone)); - } RCLASS_M_TBL_INIT(clone); st_foreach(RCLASS_M_TBL(orig), clone_method_i, (st_data_t)clone); } diff --git a/common.mk b/common.mk index f9935960261f6b..41fb072704e82c 100644 --- a/common.mk +++ b/common.mk @@ -204,7 +204,7 @@ $(CAPIOUT)/.timestamp: Doxyfile $(PREP) Doxyfile: $(srcdir)/template/Doxyfile.tmpl $(PREP) $(srcdir)/tool/generic_erb.rb $(RBCONFIG) $(ECHO) generating $@ $(Q) $(MINIRUBY) $(srcdir)/tool/generic_erb.rb -o $@ $(srcdir)/template/Doxyfile.tmpl \ - --srcdir="$(srcdir)" --miniruby="$(BASERUBY)" + --srcdir="$(srcdir)" --miniruby="$(MINIRUBY)" program: showflags $(PROGRAM) wprogram: showflags $(WPROGRAM) diff --git a/compile.c b/compile.c index 936728984291e7..ccd04bc4c6f4da 100644 --- a/compile.c +++ b/compile.c @@ -478,8 +478,8 @@ rb_iseq_compile_node(VALUE self, NODE *node) LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0); LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0); - ADD_LABEL(ret, start); ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_B_CALL); + ADD_LABEL(ret, start); COMPILE(ret, "block body", node->nd_body); ADD_LABEL(ret, end); ADD_TRACE(ret, nd_line(node), RUBY_EVENT_B_RETURN); @@ -2479,6 +2479,7 @@ compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, if (i > 0 || !first) ADD_INSN(ret, line, swap); COMPILE(ret, "keyword splat", kw); ADD_SEND(ret, line, ID2SYM(id_core_hash_merge_kwd), nhash); + if (nhash == INT2FIX(1)) ADD_SEND(ret, line, ID2SYM(rb_intern("dup")), INT2FIX(0)); } first = 0; break; diff --git a/complex.c b/complex.c index 3e9d63117afc1e..e1d5ff9f2a97a0 100644 --- a/complex.c +++ b/complex.c @@ -18,10 +18,10 @@ VALUE rb_cComplex; -static ID id_abs, id_abs2, id_arg, id_cmp, id_conj, id_convert, - id_denominator, id_divmod, id_eqeq_p, id_expt, id_fdiv, id_floor, - id_idiv, id_imag, id_inspect, id_negate, id_numerator, id_quo, - id_real, id_real_p, id_to_f, id_to_i, id_to_r, id_to_s, +static ID id_abs, id_arg, id_convert, + id_denominator, id_eqeq_p, id_expt, id_fdiv, + id_inspect, id_negate, id_numerator, id_quo, + id_real_p, id_to_f, id_to_i, id_to_r, id_to_s, id_i_real, id_i_imag; #define f_boolcast(x) ((x) ? Qtrue : Qfalse) @@ -75,20 +75,6 @@ f_add(VALUE x, VALUE y) return rb_funcall(x, '+', 1, y); } -inline static VALUE -f_cmp(VALUE x, VALUE y) -{ - if (FIXNUM_P(x) && FIXNUM_P(y)) { - long c = FIX2LONG(x) - FIX2LONG(y); - if (c > 0) - c = 1; - else if (c < 0) - c = -1; - return INT2FIX(c); - } - return rb_funcall(x, id_cmp, 1, y); -} - inline static VALUE f_div(VALUE x, VALUE y) { @@ -105,16 +91,6 @@ f_gt_p(VALUE x, VALUE y) return rb_funcall(x, '>', 1, y); } -inline static VALUE -f_lt_p(VALUE x, VALUE y) -{ - if (FIXNUM_P(x) && FIXNUM_P(y)) - return f_boolcast(FIX2LONG(x) < FIX2LONG(y)); - return rb_funcall(x, '<', 1, y); -} - -binop(mod, '%') - inline static VALUE f_mul(VALUE x, VALUE y) { @@ -152,16 +128,11 @@ f_sub(VALUE x, VALUE y) } fun1(abs) -fun1(abs2) fun1(arg) -fun1(conj) fun1(denominator) -fun1(floor) -fun1(imag) fun1(inspect) fun1(negate) fun1(numerator) -fun1(real) fun1(real_p) inline static VALUE @@ -182,8 +153,6 @@ f_to_f(VALUE x) fun1(to_r) fun1(to_s) -fun2(divmod) - inline static VALUE f_eqeq_p(VALUE x, VALUE y) { @@ -194,7 +163,6 @@ f_eqeq_p(VALUE x, VALUE y) fun2(expt) fun2(fdiv) -fun2(idiv) fun2(quo) inline static VALUE @@ -257,12 +225,6 @@ k_numeric_p(VALUE x) return f_kind_of_p(x, rb_cNumeric); } -inline static VALUE -k_integer_p(VALUE x) -{ - return f_kind_of_p(x, rb_cInteger); -} - inline static VALUE k_fixnum_p(VALUE x) { @@ -456,13 +418,6 @@ nucomp_s_new(int argc, VALUE *argv, VALUE klass) return nucomp_s_canonicalize_internal(klass, real, imag); } -inline static VALUE -f_complex_new1(VALUE klass, VALUE x) -{ - assert(!k_complex_p(x)); - return nucomp_s_canonicalize_internal(klass, x, ZERO); -} - inline static VALUE f_complex_new2(VALUE klass, VALUE x, VALUE y) { @@ -537,7 +492,6 @@ m_log_bang(VALUE x) imp1(sin) imp1(sinh) -imp1(sqrt) static VALUE m_cos(VALUE x) @@ -570,6 +524,8 @@ m_sin(VALUE x) } #if 0 +imp1(sqrt) + static VALUE m_sqrt(VALUE x) { @@ -1774,19 +1730,26 @@ parse_comp(const char *s, int strict, VALUE *num) { char *buf, *b; + VALUE tmp; + int ret = 1; - buf = ALLOCA_N(char, strlen(s) + 1); + buf = ALLOCV_N(char, tmp, strlen(s) + 1); b = buf; skip_ws(&s); - if (!read_comp(&s, strict, num, &b)) - return 0; - skip_ws(&s); + if (!read_comp(&s, strict, num, &b)) { + ret = 0; + } + else { + skip_ws(&s); - if (strict) - if (*s != '\0') - return 0; - return 1; + if (strict) + if (*s != '\0') + ret = 0; + } + ALLOCV_END(tmp); + + return ret; } static VALUE @@ -2091,24 +2054,16 @@ Init_Complex(void) assert(fprintf(stderr, "assert() is now active\n")); id_abs = rb_intern("abs"); - id_abs2 = rb_intern("abs2"); id_arg = rb_intern("arg"); - id_cmp = rb_intern("<=>"); - id_conj = rb_intern("conj"); id_convert = rb_intern("convert"); id_denominator = rb_intern("denominator"); - id_divmod = rb_intern("divmod"); id_eqeq_p = rb_intern("=="); id_expt = rb_intern("**"); id_fdiv = rb_intern("fdiv"); - id_floor = rb_intern("floor"); - id_idiv = rb_intern("div"); - id_imag = rb_intern("imag"); id_inspect = rb_intern("inspect"); id_negate = rb_intern("-@"); id_numerator = rb_intern("numerator"); id_quo = rb_intern("quo"); - id_real = rb_intern("real"); id_real_p = rb_intern("real?"); id_to_f = rb_intern("to_f"); id_to_i = rb_intern("to_i"); diff --git a/configure.in b/configure.in index ddc4216d9107df..fc01f3b42526b0 100644 --- a/configure.in +++ b/configure.in @@ -770,6 +770,8 @@ if test "$GCC:${warnflags+set}:no" = yes::no; then rb_cv_warnflags="$warnflags" warnflags= fi +RUBY_TRY_CFLAGS(-Qunused-arguments, [RUBY_APPEND_OPTIONS(rb_cv_wsuppress_flags, -Qunused-arguments)]) + if test "$GCC" = yes; then # -D_FORTIFY_SOURCE # When defined _FORTIFY_SOURCE, glibc enables some additional sanity @@ -860,7 +862,7 @@ if test "$GCC" = yes; then [*-darwin*], [ # doesn't seem necessary on Mac OS X ], - [[i[4-6]86*]], [ + [[i[4-6]86*|i386*mingw*]], [ RUBY_TRY_CFLAGS(-msse2 -mfpmath=sse, [ RUBY_APPEND_OPTION(XCFLAGS, -msse2 -mfpmath=sse) ]) @@ -1045,6 +1047,7 @@ main() ac_cv_func_clock_gettime=yes ac_cv_func_clock_getres=yes ac_cv_func_malloc_usable_size=no + { test "$target_cpu" = x64 && ac_cv_func___builtin_setjmp=no; } AC_CHECK_TYPE([NET_LUID], [], [], [@%:@include @%:@include ]) @@ -1153,7 +1156,18 @@ mv confdefs.h largefile.h mv confdefs1.h confdefs.h cat largefile.h >> confdefs.h -AS_CASE(["$target_os"],[mingw*], [ac_cv_type_off_t=yes;ac_cv_sizeof_off_t=8]) +AS_CASE(["$target_os"], + [mingw*], [ac_cv_type_off_t=yes;ac_cv_sizeof_off_t=8], + [aix*], [ + AS_CASE(["$target_cpu:$ac_cv_sys_large_files"], + [ppc64:*|powerpc64:*], [], + [*:no|*:unknown], [], + [ + # AIX currently does not support a 32-bit call to posix_fadvise() + # if _LARGE_FILES is defined. + ac_cv_posix_fadvise=no + ]) + ]) AC_C_BIGENDIAN AC_C_CONST @@ -1269,7 +1283,8 @@ RUBY_CHECK_SIZEOF(clock_t, [], [], [@%:@include ]) AC_DEFUN([RUBY_CHECK_PRINTF_PREFIX], [ AC_CACHE_CHECK([for printf prefix for $1], [rb_cv_pri_prefix_]AS_TR_SH($1),[ [rb_cv_pri_prefix_]AS_TR_SH($1)=[NONE] - RUBY_WERROR_FLAG(for pri in $2; do + RUBY_WERROR_FLAG(RUBY_APPEND_OPTIONS(CFLAGS, $rb_cv_wsuppress_flags) + for pri in $2; do AC_TRY_COMPILE( [@%:@include @%:@include @@ -1548,8 +1563,8 @@ if test "$GCC" = yes; then AC_CACHE_CHECK(for __builtin_unreachable, rb_cv_func___builtin_unreachable, [RUBY_WERROR_FLAG( - [AC_TRY_LINK([@%:@include ], - [exit(0); __builtin_unreachable();], + [AC_TRY_LINK([volatile int zero;], + [if (zero) __builtin_unreachable();], [rb_cv_func___builtin_unreachable=yes], [rb_cv_func___builtin_unreachable=no]) ]) @@ -2008,17 +2023,35 @@ AC_CACHE_CHECK(for sigsetjmp as a macro or function, ac_cv_func_sigsetjmp, ac_cv_func_sigsetjmp=yes, ac_cv_func_sigsetjmp=no)]) +AC_DEFUN(RUBY_CHECK_BUILTIN_SETJMP, [ +if test x"${ac_cv_func___builtin_setjmp}" = xyes; then + unset ac_cv_func___builtin_setjmp +fi AC_CACHE_CHECK(for __builtin_setjmp, ac_cv_func___builtin_setjmp, -[AC_TRY_LINK([@%:@include - jmp_buf jb; void t(v) int v; {__builtin_longjmp(jb, v);}], - [__builtin_setjmp(jb);], - [ac_cv_func___builtin_setjmp=yes], - [ac_cv_func___builtin_setjmp=no]) + [ + ac_cv_func___builtin_setjmp=no + for cast in "" "(void **)"; do + RUBY_WERROR_FLAG( + [AC_TRY_LINK([@%:@include + @%:@include + jmp_buf jb; + void t(void) {__builtin_longjmp($cast jb, 1);} + int jump(void) {(void)(__builtin_setjmp($cast jb) ? 1 : 0); return 0;}], + [ + void (*volatile f)(void) = t; + if (!jump()) printf("%d\n", f != 0); + ], + [ac_cv_func___builtin_setjmp="yes with cast ($cast)"]) + ]) + test "$ac_cv_func___builtin_setjmp" = no || break + done]) ]) # we don't use _setjmp if _longjmp doesn't exist. test x$ac_cv_func__longjmp = xno && ac_cv_func__setjmp=no +AC_DEFUN(RUBY_SETJMP_TYPE, [ +RUBY_CHECK_BUILTIN_SETJMP AC_MSG_CHECKING(for setjmp type) setjmp_suffix= AC_ARG_WITH(setjmp-type, @@ -2032,11 +2065,13 @@ AC_ARG_WITH(setjmp-type, [setjmpex], [ setjmp_prefix= setjmp_suffix=ex], [''], [ unset setjmp_prefix], [ AC_MSG_ERROR(invalid setjmp type: $withval)])], [unset setjmp_prefix]) +setjmp_cast= if test ${setjmp_prefix+set}; then if test "${setjmp_prefix}" && eval test '$ac_cv_func_'${setjmp_prefix}setjmp${setjmp_suffix} = no; then AC_MSG_ERROR(${setjmp_prefix}setjmp${setjmp_suffix} is not available) fi -elif test "$ac_cv_func___builtin_setjmp" = yes; then +elif { AS_CASE("$ac_cv_func___builtin_setjmp", [yes*], [true], [false]); }; then + setjmp_cast=`expr "$ac_cv_func___builtin_setjmp" : "yes with cast (\(.*\))"` setjmp_prefix=__builtin_ setjmp_suffix= elif test "$ac_cv_header_setjmpex_h:$ac_cv_func__setjmpex" = yes:yes; then @@ -2057,10 +2092,11 @@ if test x$setjmp_prefix = xsig; then else unset setjmp_sigmask fi -AC_MSG_RESULT(${setjmp_prefix}setjmp${setjmp_suffix}) -AC_DEFINE_UNQUOTED([RUBY_SETJMP(env)], [${setjmp_prefix}setjmp${setjmp_suffix}(env${setjmp_sigmask+,0})]) -AC_DEFINE_UNQUOTED([RUBY_LONGJMP(env,val)], [${setjmp_prefix}longjmp(env,val)]) +AC_MSG_RESULT(${setjmp_prefix}setjmp${setjmp_suffix}${setjmp_cast:+($setjmp_cast)}) +AC_DEFINE_UNQUOTED([RUBY_SETJMP(env)], [${setjmp_prefix}setjmp${setjmp_suffix}($setjmp_cast(env)${setjmp_sigmask+,0})]) +AC_DEFINE_UNQUOTED([RUBY_LONGJMP(env,val)], [${setjmp_prefix}longjmp($setjmp_cast(env),val)]) AC_DEFINE_UNQUOTED(RUBY_JMP_BUF, ${setjmp_sigmask+${setjmp_prefix}}jmp_buf) +]) # End of setjmp check. AC_ARG_ENABLE(setreuid, @@ -2850,24 +2886,25 @@ void sigsegv(int signum, siginfo_t *info, void *ctx){ if (n > 0) { /*fprintf(stdout, "backtrace:%d\n",n);*/ } else { - abort(); + _exit(EXIT_FAILURE); } - _exit(0); + _exit(EXIT_SUCCESS); } int -main() +main(void) { + volatile int *a = NULL; stack_t ss; ss.ss_sp = malloc(SIGSTKSZ); if (ss.ss_sp == NULL) { fprintf(stderr, "cannot allocate memory for sigaltstack\n"); - abort(); + return EXIT_FAILURE; } ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; if (sigaltstack(&ss, NULL) == -1) { fprintf(stderr, "sigaltstack failed\n"); - abort(); + return EXIT_FAILURE; } struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); @@ -2876,9 +2913,8 @@ main() sa.sa_flags |= SA_SIGINFO; sa.sa_flags |= SA_ONSTACK; sigaction(SIGSEGV, &sa, NULL); - int *a = NULL; a[0] = 1; - return 0; + return EXIT_SUCCESS; } ], rb_cv_broken_backtrace=no, @@ -3338,6 +3374,7 @@ AC_SUBST(DTRACE_OBJ) AC_SUBST(DTRACE_GLOMMED_OBJ) AC_SUBST(LIBRUBY_A_OBJS) +RUBY_SETJMP_TYPE } { # build section diff --git a/cont.c b/cont.c index fa9e91ee64ac57..3b05f995d4180a 100644 --- a/cont.c +++ b/cont.c @@ -97,16 +97,18 @@ typedef struct rb_context_struct { size_t vm_stack_slen; /* length of stack (head of th->stack) */ size_t vm_stack_clen; /* length of control frames (tail of th->stack) */ #endif - VALUE *machine_stack; - VALUE *machine_stack_src; + struct { + VALUE *stack; + VALUE *stack_src; + size_t stack_size; #ifdef __ia64 - VALUE *machine_register_stack; - VALUE *machine_register_stack_src; - int machine_register_stack_size; + VALUE *register_stack; + VALUE *register_stack_src; + int register_stack_size; #endif + } machine; rb_thread_t saved_thread; rb_jmpbuf_t jmpbuf; - size_t machine_stack_size; rb_ensure_entry_t *ensure_array; rb_ensure_list_t *ensure_list; } rb_context_t; @@ -188,11 +190,11 @@ cont_mark(void *ptr) #endif } - if (cont->machine_stack) { + if (cont->machine.stack) { if (cont->type == CONTINUATION_CONTEXT) { /* cont */ - rb_gc_mark_locations(cont->machine_stack, - cont->machine_stack + cont->machine_stack_size); + rb_gc_mark_locations(cont->machine.stack, + cont->machine.stack + cont->machine.stack_size); } else { /* fiber */ @@ -200,15 +202,15 @@ cont_mark(void *ptr) rb_fiber_t *fib = (rb_fiber_t*)cont; GetThreadPtr(cont->saved_thread.self, th); if ((th->fiber != cont->self) && fib->status == RUNNING) { - rb_gc_mark_locations(cont->machine_stack, - cont->machine_stack + cont->machine_stack_size); + rb_gc_mark_locations(cont->machine.stack, + cont->machine.stack + cont->machine.stack_size); } } } #ifdef __ia64 - if (cont->machine_register_stack) { - rb_gc_mark_locations(cont->machine_register_stack, - cont->machine_register_stack + cont->machine_register_stack_size); + if (cont->machine.register_stack) { + rb_gc_mark_locations(cont->machine.register_stack, + cont->machine.register_stack + cont->machine.register_stack_size); } #endif } @@ -226,7 +228,7 @@ cont_free(void *ptr) if (cont->type == CONTINUATION_CONTEXT) { /* cont */ ruby_xfree(cont->ensure_array); - RUBY_FREE_UNLESS_NULL(cont->machine_stack); + RUBY_FREE_UNLESS_NULL(cont->machine.stack); } else { /* fiber */ @@ -257,10 +259,10 @@ cont_free(void *ptr) } #else /* not FIBER_USE_NATIVE */ ruby_xfree(cont->ensure_array); - RUBY_FREE_UNLESS_NULL(cont->machine_stack); + RUBY_FREE_UNLESS_NULL(cont->machine.stack); #endif #ifdef __ia64 - RUBY_FREE_UNLESS_NULL(cont->machine_register_stack); + RUBY_FREE_UNLESS_NULL(cont->machine.register_stack); #endif RUBY_FREE_UNLESS_NULL(cont->vm_stack); @@ -286,12 +288,12 @@ cont_memsize(const void *ptr) size += n * sizeof(*cont->vm_stack); } - if (cont->machine_stack) { - size += cont->machine_stack_size * sizeof(*cont->machine_stack); + if (cont->machine.stack) { + size += cont->machine.stack_size * sizeof(*cont->machine.stack); } #ifdef __ia64 - if (cont->machine_register_stack) { - size += cont->machine_register_stack_size * sizeof(*cont->machine_register_stack); + if (cont->machine.register_stack) { + size += cont->machine.register_stack_size * sizeof(*cont->machine.register_stack); } #endif } @@ -380,42 +382,42 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) { size_t size; - SET_MACHINE_STACK_END(&th->machine_stack_end); + SET_MACHINE_STACK_END(&th->machine.stack_end); #ifdef __ia64 - th->machine_register_stack_end = rb_ia64_bsp(); + th->machine.register_stack_end = rb_ia64_bsp(); #endif - if (th->machine_stack_start > th->machine_stack_end) { - size = cont->machine_stack_size = th->machine_stack_start - th->machine_stack_end; - cont->machine_stack_src = th->machine_stack_end; + if (th->machine.stack_start > th->machine.stack_end) { + size = cont->machine.stack_size = th->machine.stack_start - th->machine.stack_end; + cont->machine.stack_src = th->machine.stack_end; } else { - size = cont->machine_stack_size = th->machine_stack_end - th->machine_stack_start; - cont->machine_stack_src = th->machine_stack_start; + size = cont->machine.stack_size = th->machine.stack_end - th->machine.stack_start; + cont->machine.stack_src = th->machine.stack_start; } - if (cont->machine_stack) { - REALLOC_N(cont->machine_stack, VALUE, size); + if (cont->machine.stack) { + REALLOC_N(cont->machine.stack, VALUE, size); } else { - cont->machine_stack = ALLOC_N(VALUE, size); + cont->machine.stack = ALLOC_N(VALUE, size); } FLUSH_REGISTER_WINDOWS; - MEMCPY(cont->machine_stack, cont->machine_stack_src, VALUE, size); + MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size); #ifdef __ia64 rb_ia64_flushrs(); - size = cont->machine_register_stack_size = th->machine_register_stack_end - th->machine_register_stack_start; - cont->machine_register_stack_src = th->machine_register_stack_start; - if (cont->machine_register_stack) { - REALLOC_N(cont->machine_register_stack, VALUE, size); + size = cont->machine.register_stack_size = th->machine.register_stack_end - th->machine.register_stack_start; + cont->machine.register_stack_src = th->machine.register_stack_start; + if (cont->machine.register_stack) { + REALLOC_N(cont->machine.register_stack, VALUE, size); } else { - cont->machine_register_stack = ALLOC_N(VALUE, size); + cont->machine.register_stack = ALLOC_N(VALUE, size); } - MEMCPY(cont->machine_register_stack, cont->machine_register_stack_src, VALUE, size); + MEMCPY(cont->machine.register_stack, cont->machine.register_stack_src, VALUE, size); #endif } @@ -430,13 +432,13 @@ cont_save_thread(rb_context_t *cont, rb_thread_t *th) { /* save thread context */ cont->saved_thread = *th; - /* saved_thread->machine_stack_(start|end) should be NULL */ + /* saved_thread->machine.stack_(start|end) should be NULL */ /* because it may happen GC afterward */ - cont->saved_thread.machine_stack_start = 0; - cont->saved_thread.machine_stack_end = 0; + cont->saved_thread.machine.stack_start = 0; + cont->saved_thread.machine.stack_end = 0; #ifdef __ia64 - cont->saved_thread.machine_register_stack_start = 0; - cont->saved_thread.machine_register_stack_end = 0; + cont->saved_thread.machine.register_stack_start = 0; + cont->saved_thread.machine.register_stack_end = 0; #endif } @@ -579,7 +581,7 @@ fiber_set_stack_location(void) VALUE *ptr; SET_MACHINE_STACK_END(&ptr); - th->machine_stack_start = (void*)(((VALUE)ptr & RB_PAGE_MASK) + STACK_UPPER((void *)&ptr, 0, RB_PAGE_SIZE)); + th->machine.stack_start = (void*)(((VALUE)ptr & RB_PAGE_MASK) + STACK_UPPER((void *)&ptr, 0, RB_PAGE_SIZE)); } static VOID CALLBACK @@ -654,7 +656,7 @@ fiber_initialize_machine_stack_context(rb_fiber_t *fib, size_t size) rb_raise(rb_eFiberError, "can't create fiber"); } } - sth->machine_stack_maxsize = size; + sth->machine.stack_maxsize = size; #else /* not WIN32 */ ucontext_t *context = &fib->context; char *ptr; @@ -666,11 +668,11 @@ fiber_initialize_machine_stack_context(rb_fiber_t *fib, size_t size) context->uc_stack.ss_sp = ptr; context->uc_stack.ss_size = size; makecontext(context, rb_fiber_start, 0); - sth->machine_stack_start = (VALUE*)(ptr + STACK_DIR_UPPER(0, size)); - sth->machine_stack_maxsize = size - RB_PAGE_SIZE; + sth->machine.stack_start = (VALUE*)(ptr + STACK_DIR_UPPER(0, size)); + sth->machine.stack_maxsize = size - RB_PAGE_SIZE; #endif #ifdef __ia64 - sth->machine_register_stack_maxsize = sth->machine_stack_maxsize; + sth->machine.register_stack_maxsize = sth->machine.stack_maxsize; #endif } @@ -687,29 +689,29 @@ fiber_setcontext(rb_fiber_t *newfib, rb_fiber_t *oldfib) /* restore thread context */ cont_restore_thread(&newfib->cont); - th->machine_stack_maxsize = sth->machine_stack_maxsize; - if (sth->machine_stack_end && (newfib != oldfib)) { - rb_bug("fiber_setcontext: sth->machine_stack_end has non zero value"); + th->machine.stack_maxsize = sth->machine.stack_maxsize; + if (sth->machine.stack_end && (newfib != oldfib)) { + rb_bug("fiber_setcontext: sth->machine.stack_end has non zero value"); } /* save oldfib's machine stack */ if (oldfib->status != TERMINATED) { STACK_GROW_DIR_DETECTION; - SET_MACHINE_STACK_END(&th->machine_stack_end); + SET_MACHINE_STACK_END(&th->machine.stack_end); if (STACK_DIR_UPPER(0, 1)) { - oldfib->cont.machine_stack_size = th->machine_stack_start - th->machine_stack_end; - oldfib->cont.machine_stack = th->machine_stack_end; + oldfib->cont.machine.stack_size = th->machine.stack_start - th->machine.stack_end; + oldfib->cont.machine.stack = th->machine.stack_end; } else { - oldfib->cont.machine_stack_size = th->machine_stack_end - th->machine_stack_start; - oldfib->cont.machine_stack = th->machine_stack_start; + oldfib->cont.machine.stack_size = th->machine.stack_end - th->machine.stack_start; + oldfib->cont.machine.stack = th->machine.stack_start; } } /* exchange machine_stack_start between oldfib and newfib */ - oldfib->cont.saved_thread.machine_stack_start = th->machine_stack_start; - th->machine_stack_start = sth->machine_stack_start; - /* oldfib->machine_stack_end should be NULL */ - oldfib->cont.saved_thread.machine_stack_end = 0; + oldfib->cont.saved_thread.machine.stack_start = th->machine.stack_start; + th->machine.stack_start = sth->machine.stack_start; + /* oldfib->machine.stack_end should be NULL */ + oldfib->cont.saved_thread.machine.stack_end = 0; #ifndef _WIN32 if (!newfib->context.uc_stack.ss_sp && th->root_fiber != newfib->cont.self) { rb_bug("non_root_fiber->context.uc_stac.ss_sp should not be NULL"); @@ -742,16 +744,16 @@ cont_restore_1(rb_context_t *cont) ((_JUMP_BUFFER*)(&buf))->Frame; } #endif - if (cont->machine_stack_src) { + if (cont->machine.stack_src) { FLUSH_REGISTER_WINDOWS; - MEMCPY(cont->machine_stack_src, cont->machine_stack, - VALUE, cont->machine_stack_size); + MEMCPY(cont->machine.stack_src, cont->machine.stack, + VALUE, cont->machine.stack_size); } #ifdef __ia64 - if (cont->machine_register_stack_src) { - MEMCPY(cont->machine_register_stack_src, cont->machine_register_stack, - VALUE, cont->machine_register_stack_size); + if (cont->machine.register_stack_src) { + MEMCPY(cont->machine.register_stack_src, cont->machine.register_stack, + VALUE, cont->machine.register_stack_size); } #endif @@ -786,7 +788,7 @@ register_stack_extend(rb_context_t *cont, VALUE *vp, VALUE *curr_bsp) E(k) = E(l) = E(m) = E(n) = E(o) = E(p) = E(q) = E(r) = E(s) = E(t) = 0; } - if (curr_bsp < cont->machine_register_stack_src+cont->machine_register_stack_size) { + if (curr_bsp < cont->machine.register_stack_src+cont->machine.register_stack_size) { register_stack_extend(cont, vp, (VALUE*)rb_ia64_bsp()); } cont_restore_0(cont, vp); @@ -798,7 +800,7 @@ register_stack_extend(rb_context_t *cont, VALUE *vp, VALUE *curr_bsp) static void cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame) { - if (cont->machine_stack_src) { + if (cont->machine.stack_src) { #ifdef HAVE_ALLOCA #define STACK_PAD_SIZE 1 #else @@ -811,7 +813,7 @@ cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame) /* Stack grows downward */ #endif #if STACK_GROW_DIRECTION <= 0 - volatile VALUE *const end = cont->machine_stack_src; + volatile VALUE *const end = cont->machine.stack_src; if (&space[0] > end) { # ifdef HAVE_ALLOCA volatile VALUE *sp = ALLOCA_N(VALUE, &space[0] - end); @@ -827,7 +829,7 @@ cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame) /* Stack grows upward */ #endif #if STACK_GROW_DIRECTION >= 0 - volatile VALUE *const end = cont->machine_stack_src + cont->machine_stack_size; + volatile VALUE *const end = cont->machine.stack_src + cont->machine.stack_size; if (&space[STACK_PAD_SIZE] < end) { # ifdef HAVE_ALLOCA volatile VALUE *sp = ALLOCA_N(VALUE, end - &space[STACK_PAD_SIZE]); @@ -1258,8 +1260,8 @@ rb_fiber_terminate(rb_fiber_t *fib) terminated_machine_stack.ptr = fib->context.uc_stack.ss_sp; terminated_machine_stack.size = fib->context.uc_stack.ss_size / sizeof(VALUE); fib->context.uc_stack.ss_sp = NULL; - fib->cont.machine_stack = NULL; - fib->cont.machine_stack_size = 0; + fib->cont.machine.stack = NULL; + fib->cont.machine.stack_size = 0; #endif rb_fiber_transfer(return_fiber(), 1, &value); } @@ -1369,7 +1371,7 @@ fiber_store(rb_fiber_t *next_fib) machine_stack_cache_index++; } else { - if (terminated_machine_stack.ptr != fib->cont.machine_stack) { + if (terminated_machine_stack.ptr != fib->cont.machine.stack) { munmap((void*)terminated_machine_stack.ptr, terminated_machine_stack.size * sizeof(VALUE)); } else { @@ -1659,7 +1661,7 @@ Init_Cont(void) #else /* not WIN32 */ pagesize = sysconf(_SC_PAGESIZE); #endif - SET_MACHINE_STACK_END(&th->machine_stack_end); + SET_MACHINE_STACK_END(&th->machine.stack_end); #endif rb_cFiber = rb_define_class("Fiber", rb_cObject); diff --git a/dln.c b/dln.c index e6b20d54e3e8ef..85ebe27caee3e7 100644 --- a/dln.c +++ b/dln.c @@ -1255,20 +1255,25 @@ dln_load(const char *file) #if defined _WIN32 && !defined __CYGWIN__ HINSTANCE handle; - char winfile[MAXPATHLEN]; + WCHAR *winfile; char message[1024]; void (*init_fct)(); char *buf; - if (strlen(file) >= MAXPATHLEN) dln_loaderror("filename too long"); - /* Load the file as an object one */ init_funcname(&buf, file); - strlcpy(winfile, file, sizeof(winfile)); + /* Convert the file path to wide char */ + winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL); + if (!winfile) { + dln_memerror(); + } /* Load file */ - if ((handle = LoadLibrary(winfile)) == NULL) { + handle = LoadLibraryW(winfile); + free(winfile); + + if (!handle) { error = dln_strerror(); goto failed; } diff --git a/enc/trans/euckr-tbl.rb b/enc/trans/euckr-tbl.rb index 773cd90122039a..4ce8521a8a9240 100644 --- a/enc/trans/euckr-tbl.rb +++ b/enc/trans/euckr-tbl.rb @@ -162,6 +162,8 @@ ["A2E3",0x33C2], ["A2E4",0x33D8], ["A2E5",0x2121], + ["A2E6",0x20AC], + ["A2E7",0x00AE], ["A3A1",0xFF01], ["A3A2",0xFF02], ["A3A3",0xFF03], diff --git a/enc/trans/single_byte.trans b/enc/trans/single_byte.trans index afbee1b257aa95..dec247dfb9d19e 100644 --- a/enc/trans/single_byte.trans +++ b/enc/trans/single_byte.trans @@ -91,8 +91,8 @@ extern int rb_encoding_compat; TRANS_INIT(single_byte) { if (rb_encoding_compat) { - ((struct rb_transcoder *)&rb_from_ASCII_8BIT)->conv_tree_start = from_UTF_8_COMPAT_to_ASCII_8BIT; - ((struct rb_transcoder *) &rb_to_ASCII_8BIT)->conv_tree_start = from_UTF_8_COMPAT_to_ASCII_8BIT; + rb_from_ASCII_8BIT.conv_tree_start = from_UTF_8_COMPAT_to_ASCII_8BIT; + rb_to_ASCII_8BIT.conv_tree_start = from_UTF_8_COMPAT_to_ASCII_8BIT; } <%= transcode_register_code %> } diff --git a/enc/utf_16be.c b/enc/utf_16be.c index 8b25d473a7dae8..3af8359caf019c 100644 --- a/enc/utf_16be.c +++ b/enc/utf_16be.c @@ -33,6 +33,7 @@ #define UTF16_IS_SURROGATE_SECOND(c) (((c) & 0xfc) == 0xdc) #define UTF16_IS_SURROGATE(c) (((c) & 0xf8) == 0xd8) +#if 0 static const int EncLen_UTF16[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -51,6 +52,7 @@ static const int EncLen_UTF16[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; +#endif static int utf16be_mbc_enc_len(const UChar* p, const OnigUChar* e ARG_UNUSED, diff --git a/enc/utf_16le.c b/enc/utf_16le.c index 8feb7ad7690cc1..453c771cc53973 100644 --- a/enc/utf_16le.c +++ b/enc/utf_16le.c @@ -33,6 +33,7 @@ #define UTF16_IS_SURROGATE_SECOND(c) (((c) & 0xfc) == 0xdc) #define UTF16_IS_SURROGATE(c) (((c) & 0xf8) == 0xd8) +#if 0 static const int EncLen_UTF16[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -51,6 +52,7 @@ static const int EncLen_UTF16[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; +#endif static int utf16le_mbc_enc_len(const UChar* p, const OnigUChar* e, diff --git a/encoding.c b/encoding.c index 9bdf7df6ea009a..16f8c4ee7a679a 100644 --- a/encoding.c +++ b/encoding.c @@ -1155,13 +1155,11 @@ enc_list(VALUE klass) /* * call-seq: * Encoding.find(string) -> enc - * Encoding.find(symbol) -> enc * * Search the encoding with specified name. - * name should be a string or symbol. + * name should be a string. * * Encoding.find("US-ASCII") #=> # - * Encoding.find(:Shift_JIS) #=> # * * Names which this method accept are encoding names and aliases * including following special aliases diff --git a/enum.c b/enum.c index e37ff16c5d3882..9d1d36d0dd9293 100644 --- a/enum.c +++ b/enum.c @@ -203,8 +203,8 @@ find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop)) * * If no block is given, an enumerator is returned instead. * - * (1..10).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> nil - * (1..100).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> 35 + * (1..10).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> nil + * (1..100).find { |i| i % 5 == 0 and i % 7 == 0 } #=> 35 * */ diff --git a/enumerator.c b/enumerator.c index 2e80580dea4e1e..c452b1776a1b57 100644 --- a/enumerator.c +++ b/enumerator.c @@ -838,7 +838,7 @@ enumerator_peek_values_m(VALUE obj) * p e.peek #=> 2 * p e.next #=> 2 * p e.next #=> 3 - * p e.next #raises StopIteration + * p e.peek #raises StopIteration * */ diff --git a/error.c b/error.c index b9d8d52809d7c6..d533a3bf4b1ef1 100644 --- a/error.c +++ b/error.c @@ -43,12 +43,17 @@ VALUE rb_eEINPROGRESS; extern const char ruby_description[]; -#define REPORTBUG_MSG \ +static const char REPORTBUG_MSG[] = "[NOTE]\n" \ "You may have encountered a bug in the Ruby interpreter" \ " or extension libraries.\n" \ "Bug reports are welcome.\n" \ + "" +#if defined __APPLE__ + "Don't forget to include the above Crash Report log file.\n" +#endif "For details: http://www.ruby-lang.org/bugreport.html\n\n" \ + ; static const char * rb_strerrno(int err) diff --git a/eval.c b/eval.c index 841b3671e3b794..7f002270a55d3f 100644 --- a/eval.c +++ b/eval.c @@ -507,9 +507,12 @@ setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg) !rb_obj_is_kind_of(e, rb_eSystemExit)) { int status; + mesg = e; PUSH_TAG(); if ((status = EXEC_TAG()) == 0) { - RB_GC_GUARD(e) = rb_obj_as_string(e); + th->errinfo = Qnil; + e = rb_obj_as_string(mesg); + th->errinfo = mesg; if (file && line) { warn_printf("Exception `%s' at %s:%d - %"PRIsVALUE"\n", rb_obj_classname(th->errinfo), file, line, e); @@ -760,7 +763,7 @@ rb_rescue2(VALUE (* b_proc) (ANYARGS), VALUE data1, } } else { - th->cfp = cfp; /* restore */ + rb_vm_rewind_cfp(th, cfp); if (state == TAG_RAISE) { int handle = FALSE; @@ -819,7 +822,7 @@ rb_protect(VALUE (* proc) (VALUE), VALUE data, int * state) SAVE_ROOT_JMPBUF(th, result = (*proc) (data)); } else { - th->cfp = cfp; + rb_vm_rewind_cfp(th, cfp); } MEMCPY(&(th)->root_jmpbuf, &org_jmpbuf, rb_jmpbuf_t, 1); th->protect_tag = protect_tag.prev; @@ -975,13 +978,6 @@ prev_frame_func(void) return frame_func_id(prev_cfp); } -void -rb_frame_pop(void) -{ - rb_thread_t *th = GET_THREAD(); - th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); -} - /* * call-seq: * append_features(mod) -> mod @@ -1095,11 +1091,11 @@ rb_using_refinement(NODE *cref, VALUE klass, VALUE module) Check_Type(klass, T_CLASS); Check_Type(module, T_MODULE); if (NIL_P(cref->nd_refinements)) { - cref->nd_refinements = hidden_identity_hash_new(); + RB_OBJ_WRITE(cref, &cref->nd_refinements, hidden_identity_hash_new()); } else { if (cref->flags & NODE_FL_CREF_OMOD_SHARED) { - cref->nd_refinements = rb_hash_dup(cref->nd_refinements); + RB_OBJ_WRITE(cref, &cref->nd_refinements, rb_hash_dup(cref->nd_refinements)); cref->flags &= ~NODE_FL_CREF_OMOD_SHARED; } if (!NIL_P(c = rb_hash_lookup(cref->nd_refinements, klass))) { diff --git a/eval_intern.h b/eval_intern.h index a0ecb5086bd692..2e00efde032654 100644 --- a/eval_intern.h +++ b/eval_intern.h @@ -95,6 +95,15 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval EXCEPTION_CONTINUE_SEARCH) { \ /* never reaches here */ \ } +#elif defined(__MINGW32__) +LONG WINAPI rb_w32_stack_overflow_handler(struct _EXCEPTION_POINTERS *); +#define SAVE_ROOT_JMPBUF_BEFORE_STMT \ + do { \ + PVOID _handler = AddVectoredExceptionHandler(1, rb_w32_stack_overflow_handler); + +#define SAVE_ROOT_JMPBUF_AFTER_STMT \ + RemoveVectoredExceptionHandler(_handler); \ + } while (0); #else #define SAVE_ROOT_JMPBUF_BEFORE_STMT #define SAVE_ROOT_JMPBUF_AFTER_STMT @@ -145,7 +154,8 @@ NORETURN(static inline void rb_threadptr_tag_jump(rb_thread_t *, int)); static inline void rb_threadptr_tag_jump(rb_thread_t *th, int st) { - ruby_longjmp(th->tag->buf, (th->state = st)); + th->state = st; + ruby_longjmp(th->tag->buf, 1); } /* diff --git a/ext/-test-/printf/printf.c b/ext/-test-/printf/printf.c index fd60b0f5932f46..1ebe80411bd38e 100644 --- a/ext/-test-/printf/printf.c +++ b/ext/-test-/printf/printf.c @@ -42,18 +42,23 @@ utoa(char *p, char *e, unsigned int x) static VALUE printf_test_call(int argc, VALUE *argv, VALUE self) { - VALUE opt, type, num; + VALUE opt, type, num, result; char format[sizeof(int) * 6 + 8], *p = format, cnv; int n; + const char *s; rb_scan_args(argc, argv, "2:", &type, &num, &opt); Check_Type(type, T_STRING); if (RSTRING_LEN(type) != 1) rb_raise(rb_eArgError, "wrong length(%ld)", RSTRING_LEN(type)); switch (cnv = RSTRING_PTR(type)[0]) { - case 'd': case 'x': case 'o': case 'X': break; + case 'd': case 'x': case 'o': case 'X': + n = NUM2INT(num); + break; + case 's': + s = StringValueCStr(num); + break; default: rb_raise(rb_eArgError, "wrong conversion(%c)", cnv); } - n = NUM2INT(num); *p++ = '%'; if (!NIL_P(opt)) { VALUE v; @@ -84,8 +89,13 @@ printf_test_call(int argc, VALUE *argv, VALUE self) } *p++ = cnv; *p++ = '\0'; - return rb_assoc_new(rb_enc_sprintf(rb_usascii_encoding(), format, n), - rb_usascii_str_new_cstr(format)); + if (cnv == 's') { + result = rb_enc_sprintf(rb_usascii_encoding(), format, s); + } + else { + result = rb_enc_sprintf(rb_usascii_encoding(), format, n); + } + return rb_assoc_new(result, rb_usascii_str_new_cstr(format)); } void diff --git a/ext/-test-/struct/extconf.rb b/ext/-test-/struct/extconf.rb new file mode 100644 index 00000000000000..0e4f9551f2a49b --- /dev/null +++ b/ext/-test-/struct/extconf.rb @@ -0,0 +1,7 @@ +$INCFLAGS << " -I$(topdir) -I$(top_srcdir)" +$srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")] +inits = $srcs.map {|s| File.basename(s, ".*")} +inits.delete("init") +inits.map! {|s|"X(#{s})"} +$defs << "-DTEST_INIT_FUNCS(X)=\"#{inits.join(' ')}\"" +create_makefile("-test-/struct") diff --git a/ext/-test-/struct/init.c b/ext/-test-/struct/init.c new file mode 100644 index 00000000000000..459a939e79c165 --- /dev/null +++ b/ext/-test-/struct/init.c @@ -0,0 +1,11 @@ +#include "ruby.h" + +#define init(n) {void Init_##n(VALUE klass); Init_##n(klass);} + +void +Init_struct(void) +{ + VALUE mBug = rb_define_module("Bug"); + VALUE klass = rb_define_class_under(mBug, "Struct", rb_cStruct); + TEST_INIT_FUNCS(init); +} diff --git a/ext/-test-/struct/member.c b/ext/-test-/struct/member.c new file mode 100644 index 00000000000000..1d404039b49d95 --- /dev/null +++ b/ext/-test-/struct/member.c @@ -0,0 +1,18 @@ +#include "ruby.h" + +static VALUE +bug_struct_get(VALUE obj, VALUE name) +{ + ID id = rb_check_id(&name); + + if (!id) { + rb_name_error_str(name, "`%"PRIsVALUE"' is not a struct member", name); + } + return rb_struct_getmember(obj, id); +} + +void +Init_member(VALUE klass) +{ + rb_define_method(klass, "get", bug_struct_get, 1); +} diff --git a/ext/-test-/win32/dln/empty/empty.c b/ext/-test-/win32/dln/empty/empty.c new file mode 100644 index 00000000000000..c4f94f164423b0 --- /dev/null +++ b/ext/-test-/win32/dln/empty/empty.c @@ -0,0 +1,4 @@ +void +Init_empty(void) +{ +} diff --git a/ext/-test-/win32/dln/empty/extconf.rb b/ext/-test-/win32/dln/empty/extconf.rb new file mode 100644 index 00000000000000..a4efed90c9a3ea --- /dev/null +++ b/ext/-test-/win32/dln/empty/extconf.rb @@ -0,0 +1,3 @@ +if $mingw or $mswin + create_makefile("-test-/win32/dln/empty") +end diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 176c76ef0cbdde..1685d15e615bc7 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -1723,23 +1723,6 @@ m_real_year(union DateData *x) return ry; } - -#ifdef USE_PACK -inline static int -m_pc(union DateData *x) -{ - if (simple_dat_p(x)) { - get_s_civil(x); - return x->s.pc; - } - else { - get_c_civil(x); - get_c_time(x); - return x->c.pc; - } -} -#endif - inline static int m_mon(union DateData *x) { @@ -1979,12 +1962,6 @@ k_date_p(VALUE x) return f_kind_of_p(x, cDate); } -inline static VALUE -k_datetime_p(VALUE x) -{ - return f_kind_of_p(x, cDateTime); -} - inline static VALUE k_numeric_p(VALUE x) { @@ -6306,7 +6283,7 @@ d_lite_cmp(VALUE self, VALUE other) return INT2FIX(1); } } - else if (a_nth < b_nth) { + else if (f_lt_p(a_nth, b_nth)) { return INT2FIX(-1); } else { diff --git a/ext/digest/digest.c b/ext/digest/digest.c index 527d0ed1feb9de..f1592f4725c059 100644 --- a/ext/digest/digest.c +++ b/ext/digest/digest.c @@ -372,7 +372,8 @@ rb_digest_instance_equal(VALUE self, VALUE other) str2 = rb_digest_instance_digest(0, 0, other); } else { str1 = rb_digest_instance_to_s(self); - str2 = other; + str2 = rb_check_string_type(other); + if (NIL_P(str2)) return Qfalse; } /* never blindly assume that subclass methods return strings */ diff --git a/ext/dl/cptr.c b/ext/dl/cptr.c index d34309379bbf58..7a82c7c3e06a3c 100644 --- a/ext/dl/cptr.c +++ b/ext/dl/cptr.c @@ -389,7 +389,6 @@ static VALUE rb_dlptr_inspect(VALUE self) { struct ptr_data *data; - char str[1024]; TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>", diff --git a/ext/dl/extconf.rb b/ext/dl/extconf.rb index 4ef46f85fb1415..53e73c3a8b9e43 100644 --- a/ext/dl/extconf.rb +++ b/ext/dl/extconf.rb @@ -1,7 +1,12 @@ require 'mkmf' if RbConfig::CONFIG['GCC'] == 'yes' - (have_macro("__clang__") ? $LDFLAGS : $CFLAGS) << " -fno-defer-pop" + flag = " -fno-defer-pop" + if have_macro("__clang__") + $LDFLAGS << flag if try_ldflags(flag) + else + $CFLAGS << flag + end $CFLAGS << " -fno-omit-frame-pointer" end diff --git a/ext/fiddle/extconf.rb b/ext/fiddle/extconf.rb index 2190aa907fdab1..466d77e6dd1cec 100644 --- a/ext/fiddle/extconf.rb +++ b/ext/fiddle/extconf.rb @@ -7,7 +7,8 @@ pkg_config("libffi") if ver = pkg_config("libffi", "modversion") ver = ver.gsub(/-rc\d+/, '') # If ver contains rc version, just ignored. - $defs.push(%{-DRUBY_LIBFFI_MODVERSION=#{ '%d%03d%03d' % ver.split('.') }}) + ver = (ver.split('.') + [0,0])[0,3] + $defs.push(%{-DRUBY_LIBFFI_MODVERSION=#{ '%d%03d%03d' % ver }}) end unless have_header('ffi.h') diff --git a/ext/fiddle/lib/fiddle/import.rb b/ext/fiddle/lib/fiddle/import.rb index 8b948e8f2358a0..ec5ee94dcf0807 100644 --- a/ext/fiddle/lib/fiddle/import.rb +++ b/ext/fiddle/lib/fiddle/import.rb @@ -112,7 +112,7 @@ def sizeof(ty) when TYPE_LONG return SIZEOF_LONG when TYPE_LONG_LONG - return SIZEOF_LONG_LON + return SIZEOF_LONG_LONG when TYPE_FLOAT return SIZEOF_FLOAT when TYPE_DOUBLE diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index df89f2c58b4cae..29335541d4fdae 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -89,11 +89,11 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions, #line 92 "parser.c" -static const int JSON_object_start = 1; -static const int JSON_object_first_final = 27; -static const int JSON_object_error = 0; +enum {JSON_object_start = 1}; +enum {JSON_object_first_final = 27}; +enum {JSON_object_error = 0}; -static const int JSON_object_en_main = 1; +enum {JSON_object_en_main = 1}; #line 151 "parser.rl" @@ -467,11 +467,11 @@ case 26: #line 470 "parser.c" -static const int JSON_value_start = 1; -static const int JSON_value_first_final = 21; -static const int JSON_value_error = 0; +enum {JSON_value_start = 1}; +enum {JSON_value_first_final = 21}; +enum {JSON_value_error = 0}; -static const int JSON_value_en_main = 1; +enum {JSON_value_en_main = 1}; #line 271 "parser.rl" @@ -776,11 +776,11 @@ case 20: #line 779 "parser.c" -static const int JSON_integer_start = 1; -static const int JSON_integer_first_final = 3; -static const int JSON_integer_error = 0; +enum {JSON_integer_start = 1}; +enum {JSON_integer_first_final = 3}; +enum {JSON_integer_error = 0}; -static const int JSON_integer_en_main = 1; +enum {JSON_integer_en_main = 1}; #line 295 "parser.rl" @@ -875,11 +875,11 @@ case 5: #line 878 "parser.c" -static const int JSON_float_start = 1; -static const int JSON_float_first_final = 8; -static const int JSON_float_error = 0; +enum {JSON_float_start = 1}; +enum {JSON_float_first_final = 8}; +enum {JSON_float_error = 0}; -static const int JSON_float_en_main = 1; +enum {JSON_float_en_main = 1}; #line 329 "parser.rl" @@ -1041,11 +1041,11 @@ case 7: #line 1044 "parser.c" -static const int JSON_array_start = 1; -static const int JSON_array_first_final = 17; -static const int JSON_array_error = 0; +enum {JSON_array_start = 1}; +enum {JSON_array_first_final = 17}; +enum {JSON_array_error = 0}; -static const int JSON_array_en_main = 1; +enum {JSON_array_en_main = 1}; #line 381 "parser.rl" @@ -1373,11 +1373,11 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd) #line 1376 "parser.c" -static const int JSON_string_start = 1; -static const int JSON_string_first_final = 8; -static const int JSON_string_error = 0; +enum {JSON_string_start = 1}; +enum {JSON_string_first_final = 8}; +enum {JSON_string_error = 0}; -static const int JSON_string_en_main = 1; +enum {JSON_string_en_main = 1}; #line 494 "parser.rl" @@ -1730,11 +1730,11 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) #line 1733 "parser.c" -static const int JSON_start = 1; -static const int JSON_first_final = 10; -static const int JSON_error = 0; +enum {JSON_start = 1}; +enum {JSON_first_final = 10}; +enum {JSON_error = 0}; -static const int JSON_en_main = 1; +enum {JSON_en_main = 1}; #line 740 "parser.rl" @@ -1904,11 +1904,11 @@ case 9: #line 1907 "parser.c" -static const int JSON_quirks_mode_start = 1; -static const int JSON_quirks_mode_first_final = 10; -static const int JSON_quirks_mode_error = 0; +enum {JSON_quirks_mode_start = 1}; +enum {JSON_quirks_mode_first_final = 10}; +enum {JSON_quirks_mode_error = 0}; -static const int JSON_quirks_mode_en_main = 1; +enum {JSON_quirks_mode_en_main = 1}; #line 778 "parser.rl" diff --git a/ext/json/parser/prereq.mk b/ext/json/parser/prereq.mk index 440ef4017ed3d7..be7bcb43190e01 100644 --- a/ext/json/parser/prereq.mk +++ b/ext/json/parser/prereq.mk @@ -4,6 +4,7 @@ RAGEL = ragel .rl.c: $(RAGEL) -G2 $< - $(BASERUBY) -pli -e '$$_.sub!(/[ \t]+$$/, "")' $@ + $(BASERUBY) -pli -e '$$_.sub!(/[ \t]+$$/, "")' \ + -e '$$_.sub!(/^static const int (JSON_.*=.*);$$/, "enum {\\1};")' $@ parser.c: diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c index 9a694d33aa1cf2..e3ce7e727d6123 100644 --- a/ext/objspace/objspace_dump.c +++ b/ext/objspace/objspace_dump.c @@ -232,7 +232,8 @@ dump_object(VALUE obj, struct dump_config *dc) case T_FILE: fptr = RFILE(obj)->fptr; - dump_append(dc, ", \"fd\":%d", fptr->fd); + if (fptr) + dump_append(dc, ", \"fd\":%d", fptr->fd); break; case T_ZOMBIE: diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index 0600080adc9d0f..bb5db9b5d39fe5 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -225,7 +225,10 @@ def shutdown(how=Socket::SHUT_RDWR) # Works similar to TCPServer#accept. def accept - sock = @svr.accept + # Socket#accept returns [socket, addrinfo]. + # TCPServer#accept returns a socket. + # The following comma strips addrinfo. + sock, = @svr.accept begin ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx) ssl.sync_close = true diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 50f1db7cf790c6..5104987c465723 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -1082,6 +1082,11 @@ Init_openssl() */ rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT)); + /* + * Version of OpenSSL the ruby OpenSSL extension is running with + */ + rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION))); + /* * Version number of OpenSSL the ruby OpenSSL extension was built with * (base 16) diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index c2344affa69145..efdfbfc8aa232b 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -1150,7 +1150,7 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) } if(!SYMBOL_P(tag_class)) ossl_raise(eASN1Error, "invalid tag class"); - if(SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31) + if(!NIL_P(tagging) && SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31) ossl_raise(eASN1Error, "tag number for Universal too large"); } else{ diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb index 46fa72b7849062..8bce81ea1046bf 100644 --- a/ext/pathname/lib/pathname.rb +++ b/ext/pathname/lib/pathname.rb @@ -22,7 +22,8 @@ class Pathname end SAME_PATHS = if File::FNM_SYSCASE.nonzero? - proc {|a, b| a.casecmp(b).zero?} + # Avoid #zero? here because #casecmp can return nil. + proc {|a, b| a.casecmp(b) == 0} else proc {|a, b| a == b} end @@ -113,6 +114,7 @@ def cleanpath_aggressive # :nodoc: end end end + pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR if /#{SEPARATOR_PAT}/o =~ File.basename(pre) names.shift while names[0] == '..' end @@ -161,6 +163,7 @@ def cleanpath_conservative # :nodoc: pre, base = r names.unshift base if base != '.' end + pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR if /#{SEPARATOR_PAT}/o =~ File.basename(pre) names.shift while names[0] == '..' end diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb index f3be5862f0089f..6c61324e383890 100644 --- a/ext/socket/extconf.rb +++ b/ext/socket/extconf.rb @@ -332,6 +332,7 @@ def test_recvmsg_with_msg_peek_creates_fds(headers) have_struct_member("struct sockaddr", "sa_len", headers) # 4.4BSD have_struct_member("struct sockaddr_in", "sin_len", headers) # 4.4BSD +have_struct_member("struct sockaddr_in6", "sin6_len", headers) # 4.4BSD if have_type("struct sockaddr_un", headers) # POSIX have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c index 7b198bd154727c..ef5ce763ec3f46 100644 --- a/ext/socket/ipsocket.c +++ b/ext/socket/ipsocket.c @@ -15,7 +15,7 @@ struct inetsock_arg VALUE sock; struct { VALUE host, serv; - struct addrinfo *res; + struct rb_addrinfo *res; } remote, local; int type; int fd; @@ -25,11 +25,11 @@ static VALUE inetsock_cleanup(struct inetsock_arg *arg) { if (arg->remote.res) { - freeaddrinfo(arg->remote.res); + rb_freeaddrinfo(arg->remote.res); arg->remote.res = 0; } if (arg->local.res) { - freeaddrinfo(arg->local.res); + rb_freeaddrinfo(arg->local.res); arg->local.res = 0; } if (arg->fd >= 0) { @@ -57,14 +57,14 @@ init_inetsock_internal(struct inetsock_arg *arg) } arg->fd = fd = -1; - for (res = arg->remote.res; res; res = res->ai_next) { + for (res = arg->remote.res->ai; res; res = res->ai_next) { #if !defined(INET6) && defined(AF_INET6) if (res->ai_family == AF_INET6) continue; #endif lres = NULL; if (arg->local.res) { - for (lres = arg->local.res; lres; lres = lres->ai_next) { + for (lres = arg->local.res->ai; lres; lres = lres->ai_next) { if (lres->ai_family == res->ai_family) break; } @@ -73,7 +73,7 @@ init_inetsock_internal(struct inetsock_arg *arg) continue; /* Use a different family local address if no choice, this * will cause EAFNOSUPPORT. */ - lres = arg->local.res; + lres = arg->local.res->ai; } } status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol); @@ -304,13 +304,14 @@ static VALUE ip_s_getaddress(VALUE obj, VALUE host) { union_sockaddr addr; - struct addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0); + struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0); + socklen_t len = res->ai->ai_addrlen; /* just take the first one */ - memcpy(&addr, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); + memcpy(&addr, res->ai->ai_addr, len); + rb_freeaddrinfo(res); - return rsock_make_ipaddr(&addr.addr, res->ai_addrlen); + return rsock_make_ipaddr(&addr.addr, len); } void diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c index 109fcccae84767..3deadd1aeae539 100644 --- a/ext/socket/raddrinfo.c +++ b/ext/socket/raddrinfo.c @@ -171,24 +171,140 @@ nogvl_getaddrinfo(void *arg) } #endif +static int +numeric_getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ +#ifdef HAVE_INET_PTON +# if defined __MINGW64__ +# define inet_pton(f,s,d) rb_w32_inet_pton(f,s,d) +# endif + + if (node && (!service || strspn(service, "0123456789") == strlen(service))) { + static const struct { + int socktype; + int protocol; + } list[] = { + { SOCK_STREAM, IPPROTO_TCP }, + { SOCK_DGRAM, IPPROTO_UDP }, + { SOCK_RAW, 0 } + }; + struct addrinfo *ai = NULL; + int port = service ? (unsigned short)atoi(service): 0; + int hint_family = hints ? hints->ai_family : PF_UNSPEC; + int hint_socktype = hints ? hints->ai_socktype : 0; + int hint_protocol = hints ? hints->ai_protocol : 0; + char ipv4addr[4]; +#ifdef AF_INET6 + char ipv6addr[16]; + if ((hint_family == PF_UNSPEC || hint_family == PF_INET6) && + strspn(node, "0123456789abcdefABCDEF.:") == strlen(node) && + inet_pton(AF_INET6, node, ipv6addr)) { + int i; + for (i = numberof(list)-1; 0 <= i; i--) { + if ((hint_socktype == 0 || hint_socktype == list[i].socktype) && + (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) { + struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo)); + struct sockaddr_in6 *sa = xmalloc(sizeof(struct sockaddr_in6)); + INIT_SOCKADDR_IN6(sa, sizeof(struct sockaddr_in6)); + memcpy(&sa->sin6_addr, ipv6addr, sizeof(ipv6addr)); + sa->sin6_port = htons(port); + ai0->ai_family = PF_INET6; + ai0->ai_socktype = list[i].socktype; + ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol; + ai0->ai_addrlen = sizeof(struct sockaddr_in6); + ai0->ai_addr = (struct sockaddr *)sa; + ai0->ai_canonname = NULL; + ai0->ai_next = ai; + ai = ai0; + } + } + } + else +#endif + if ((hint_family == PF_UNSPEC || hint_family == PF_INET) && + strspn(node, "0123456789.") == strlen(node) && + inet_pton(AF_INET, node, ipv4addr)) { + int i; + for (i = numberof(list)-1; 0 <= i; i--) { + if ((hint_socktype == 0 || hint_socktype == list[i].socktype) && + (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) { + struct addrinfo *ai0 = xcalloc(1, sizeof(struct addrinfo)); + struct sockaddr_in *sa = xmalloc(sizeof(struct sockaddr_in)); + INIT_SOCKADDR_IN(sa, sizeof(struct sockaddr_in)); + memcpy(&sa->sin_addr, ipv4addr, sizeof(ipv4addr)); + sa->sin_port = htons(port); + ai0->ai_family = PF_INET; + ai0->ai_socktype = list[i].socktype; + ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol; + ai0->ai_addrlen = sizeof(struct sockaddr_in); + ai0->ai_addr = (struct sockaddr *)sa; + ai0->ai_canonname = NULL; + ai0->ai_next = ai; + ai = ai0; + } + } + } + if (ai) { + *res = ai; + return 0; + } + } +#endif + return EAI_FAIL; +} + int rb_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, - struct addrinfo **res) + struct rb_addrinfo **res) { + struct addrinfo *ai; + int ret; + int allocated_by_malloc = 0; + + ret = numeric_getaddrinfo(node, service, hints, &ai); + if (ret == 0) + allocated_by_malloc = 1; + else { #ifdef GETADDRINFO_EMU - return getaddrinfo(node, service, hints, res); + ret = getaddrinfo(node, service, hints, &ai); #else - struct getaddrinfo_arg arg; - int ret; - MEMZERO(&arg, sizeof arg, 1); - arg.node = node; - arg.service = service; - arg.hints = hints; - arg.res = res; - ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0); - return ret; + struct getaddrinfo_arg arg; + MEMZERO(&arg, struct getaddrinfo_arg, 1); + arg.node = node; + arg.service = service; + arg.hints = hints; + arg.res = &ai; + ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0); #endif + } + + if (ret == 0) { + *res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo)); + (*res)->allocated_by_malloc = allocated_by_malloc; + (*res)->ai = ai; + } + return ret; +} + +void +rb_freeaddrinfo(struct rb_addrinfo *ai) +{ + if (!ai->allocated_by_malloc) + freeaddrinfo(ai->ai); + else { + struct addrinfo *ai1, *ai2; + ai1 = ai->ai; + while (ai1) { + ai2 = ai1->ai_next; + xfree(ai1->ai_addr); + xfree(ai1); + ai1 = ai2; + } + } + xfree(ai); } #ifndef GETADDRINFO_EMU @@ -345,10 +461,10 @@ port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr) } } -struct addrinfo* +struct rb_addrinfo* rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack) { - struct addrinfo* res = NULL; + struct rb_addrinfo* res = NULL; char *hostp, *portp; int error; char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; @@ -373,7 +489,7 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h return res; } -struct addrinfo* +struct rb_addrinfo* rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags) { struct addrinfo hints; @@ -474,7 +590,7 @@ rsock_unix_sockaddr_len(VALUE path) struct hostent_arg { VALUE host; - struct addrinfo* addr; + struct rb_addrinfo* addr; VALUE (*ipaddr)(struct sockaddr*, socklen_t); }; @@ -482,7 +598,7 @@ static VALUE make_hostent_internal(struct hostent_arg *arg) { VALUE host = arg->host; - struct addrinfo* addr = arg->addr; + struct addrinfo* addr = arg->addr->ai; VALUE (*ipaddr)(struct sockaddr*, socklen_t) = arg->ipaddr; struct addrinfo *ai; @@ -522,14 +638,15 @@ make_hostent_internal(struct hostent_arg *arg) } VALUE -rsock_freeaddrinfo(struct addrinfo *addr) +rsock_freeaddrinfo(VALUE arg) { - freeaddrinfo(addr); + struct rb_addrinfo *addr = (struct rb_addrinfo *)arg; + rb_freeaddrinfo(addr); return Qnil; } VALUE -rsock_make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t)) +rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t)) { struct hostent_arg arg; @@ -639,12 +756,13 @@ rsock_addrinfo_new(struct sockaddr *addr, socklen_t len, return a; } -static struct addrinfo * +static struct rb_addrinfo * call_getaddrinfo(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags, int socktype_hack) { - struct addrinfo hints, *res; + struct addrinfo hints; + struct rb_addrinfo *res; MEMZERO(&hints, struct addrinfo, 1); hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family); @@ -672,21 +790,21 @@ init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE protocol, VALUE flags, VALUE inspectnode, VALUE inspectservice) { - struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1); + struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 1); VALUE canonname; - VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res); + VALUE inspectname = rb_str_equal(node, inspectnode) ? Qnil : make_inspectname(inspectnode, inspectservice, res->ai); canonname = Qnil; - if (res->ai_canonname) { - canonname = rb_tainted_str_new_cstr(res->ai_canonname); + if (res->ai->ai_canonname) { + canonname = rb_tainted_str_new_cstr(res->ai->ai_canonname); OBJ_FREEZE(canonname); } - init_addrinfo(rai, res->ai_addr, res->ai_addrlen, + init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen, NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol), canonname, inspectname); - freeaddrinfo(res); + rb_freeaddrinfo(res); } static VALUE @@ -742,21 +860,22 @@ addrinfo_firstonly_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE canonname; VALUE inspectname; - struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0); + struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0); - inspectname = make_inspectname(node, service, res); + inspectname = make_inspectname(node, service, res->ai); canonname = Qnil; - if (res->ai_canonname) { - canonname = rb_tainted_str_new_cstr(res->ai_canonname); + if (res->ai->ai_canonname) { + canonname = rb_tainted_str_new_cstr(res->ai->ai_canonname); OBJ_FREEZE(canonname); } - ret = rsock_addrinfo_new(res->ai_addr, res->ai_addrlen, - res->ai_family, res->ai_socktype, res->ai_protocol, + ret = rsock_addrinfo_new(res->ai->ai_addr, res->ai->ai_addrlen, + res->ai->ai_family, res->ai->ai_socktype, + res->ai->ai_protocol, canonname, inspectname); - freeaddrinfo(res); + rb_freeaddrinfo(res); return ret; } @@ -767,12 +886,12 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE struct addrinfo *r; VALUE inspectname; - struct addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0); + struct rb_addrinfo *res = call_getaddrinfo(node, service, family, socktype, protocol, flags, 0); - inspectname = make_inspectname(node, service, res); + inspectname = make_inspectname(node, service, res->ai); ret = rb_ary_new(); - for (r = res; r; r = r->ai_next) { + for (r = res->ai; r; r = r->ai_next) { VALUE addr; VALUE canonname = Qnil; @@ -788,7 +907,7 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE rb_ary_push(ret, addr); } - freeaddrinfo(res); + rb_freeaddrinfo(res); return ret; } @@ -1513,7 +1632,7 @@ addrinfo_mload(VALUE self, VALUE ary) default: { VALUE pair = rb_convert_type(v, T_ARRAY, "Array", "to_ary"); - struct addrinfo *res; + struct rb_addrinfo *res; int flags = AI_NUMERICHOST; #ifdef AI_NUMERICSERV flags |= AI_NUMERICSERV; @@ -1522,8 +1641,8 @@ addrinfo_mload(VALUE self, VALUE ary) INT2NUM(pfamily), INT2NUM(socktype), INT2NUM(protocol), INT2NUM(flags), 1); - len = res->ai_addrlen; - memcpy(&ss, res->ai_addr, res->ai_addrlen); + len = res->ai->ai_addrlen; + memcpy(&ss, res->ai->ai_addr, res->ai->ai_addrlen); break; } } diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index c74fb326ec16c4..a4893d9698bd39 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -278,10 +278,16 @@ int rsock_shutdown_how_arg(VALUE how); int rsock_getfamily(int sockfd); -int rb_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); +struct rb_addrinfo { + struct addrinfo *ai; + int allocated_by_malloc; +}; +int rb_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct rb_addrinfo **res); +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); -struct addrinfo *rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags); -struct addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack); +struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags); +struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack); 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); @@ -290,7 +296,7 @@ VALUE rsock_addrinfo_inspect_sockaddr(VALUE rai); VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen); VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup); -VALUE rsock_make_hostent(VALUE host, struct addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t)); +VALUE rsock_make_hostent(VALUE host, struct rb_addrinfo *addr, VALUE (*ipaddr)(struct sockaddr *, socklen_t)); VALUE rsock_inspect_sockaddr(struct sockaddr *addr, socklen_t socklen, VALUE ret); socklen_t rsock_sockaddr_len(struct sockaddr *addr); VALUE rsock_sockaddr_obj(struct sockaddr *addr, socklen_t len); diff --git a/ext/socket/socket.c b/ext/socket/socket.c index ca256b6733a109..8bfccbd5598a65 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -23,8 +23,10 @@ rsock_syserr_fail_host_port(int err, const char *mesg, VALUE host, VALUE port) { VALUE message; - message = rb_sprintf("%s for %+"PRIsVALUE" port % "PRIsVALUE"", - mesg, host, port); + port = rb_String(port); + + message = rb_sprintf("%s for \"%s\" port %s", + mesg, StringValueCStr(host), StringValueCStr(port)); rb_syserr_fail_str(err, message); } @@ -41,7 +43,15 @@ rsock_syserr_fail_path(int err, const char *mesg, VALUE path) VALUE message; if (RB_TYPE_P(path, T_STRING)) { - message = rb_sprintf("%s for % "PRIsVALUE"", mesg, path); + if (memchr(RSTRING_PTR(path), '\0', RSTRING_LEN(path))) { + path = rb_str_inspect(path); + message = rb_sprintf("%s for %s", mesg, + StringValueCStr(path)); + } + else { + message = rb_sprintf("%s for \"%s\"", mesg, + StringValueCStr(path)); + } rb_syserr_fail_str(err, message); } else { @@ -77,7 +87,7 @@ rsock_syserr_fail_raddrinfo(int err, const char *mesg, VALUE rai) VALUE str, message; str = rsock_addrinfo_inspect_sockaddr(rai); - message = rb_sprintf("%s for %"PRIsVALUE"", mesg, str); + message = rb_sprintf("%s for %s", mesg, StringValueCStr(str)); rb_syserr_fail_str(err, message); } @@ -1029,7 +1039,7 @@ sock_gethostname(VALUE obj) #endif static VALUE -make_addrinfo(struct addrinfo *res0, int norevlookup) +make_addrinfo(struct rb_addrinfo *res0, int norevlookup) { VALUE base, ary; struct addrinfo *res; @@ -1038,7 +1048,7 @@ make_addrinfo(struct addrinfo *res0, int norevlookup) rb_raise(rb_eSocket, "host not found"); } base = rb_ary_new(); - for (res = res0; res; res = res->ai_next) { + for (res = res0->ai; res; res = res->ai_next) { ary = rsock_ipaddr(res->ai_addr, res->ai_addrlen, norevlookup); if (res->ai_canonname) { RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname); @@ -1261,7 +1271,8 @@ static VALUE sock_s_getaddrinfo(int argc, VALUE *argv) { VALUE host, port, family, socktype, protocol, flags, ret, revlookup; - struct addrinfo hints, *res; + struct addrinfo hints; + struct rb_addrinfo *res; int norevlookup; rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup); @@ -1284,7 +1295,7 @@ sock_s_getaddrinfo(int argc, VALUE *argv) res = rsock_getaddrinfo(host, port, &hints, 0); ret = make_addrinfo(res, norevlookup); - freeaddrinfo(res); + rb_freeaddrinfo(res); return ret; } @@ -1317,8 +1328,9 @@ sock_s_getnameinfo(int argc, VALUE *argv) char *hptr, *pptr; char hbuf[1024], pbuf[1024]; int fl; - struct addrinfo hints, *res = NULL, *r; - int error; + struct rb_addrinfo *res = NULL; + struct addrinfo hints, *r; + int error, saved_errno; union_sockaddr ss; struct sockaddr *sap; socklen_t salen; @@ -1402,8 +1414,8 @@ sock_s_getnameinfo(int argc, VALUE *argv) hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af); error = rb_getaddrinfo(hptr, pptr, &hints, &res); if (error) goto error_exit_addr; - sap = res->ai_addr; - salen = res->ai_addrlen; + sap = res->ai->ai_addr; + salen = res->ai->ai_addrlen; } else { rb_raise(rb_eTypeError, "expecting String or Array"); @@ -1414,7 +1426,7 @@ sock_s_getnameinfo(int argc, VALUE *argv) pbuf, sizeof(pbuf), fl); if (error) goto error_exit_name; if (res) { - for (r = res->ai_next; r; r = r->ai_next) { + for (r = res->ai->ai_next; r; r = r->ai_next) { char hbuf2[1024], pbuf2[1024]; sap = r->ai_addr; @@ -1423,20 +1435,24 @@ sock_s_getnameinfo(int argc, VALUE *argv) pbuf2, sizeof(pbuf2), fl); if (error) goto error_exit_name; if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) { - freeaddrinfo(res); + rb_freeaddrinfo(res); rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename"); } } - freeaddrinfo(res); + rb_freeaddrinfo(res); } return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf)); error_exit_addr: - if (res) freeaddrinfo(res); + saved_errno = errno; + if (res) rb_freeaddrinfo(res); + errno = saved_errno; rsock_raise_socket_error("getaddrinfo", error); error_exit_name: - if (res) freeaddrinfo(res); + saved_errno = errno; + if (res) rb_freeaddrinfo(res); + errno = saved_errno; rsock_raise_socket_error("getnameinfo", error); UNREACHABLE; @@ -1459,10 +1475,10 @@ sock_s_getnameinfo(int argc, VALUE *argv) static VALUE sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host) { - struct addrinfo *res = rsock_addrinfo(host, port, 0, 0); - VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen); + struct rb_addrinfo *res = rsock_addrinfo(host, port, 0, 0); + VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen); - freeaddrinfo(res); + rb_freeaddrinfo(res); OBJ_INFECT(addr, port); OBJ_INFECT(addr, host); diff --git a/ext/socket/sockport.h b/ext/socket/sockport.h index a3c698e8a4b24f..2b58958ae7b5a3 100644 --- a/ext/socket/sockport.h +++ b/ext/socket/sockport.h @@ -29,6 +29,12 @@ # define SET_SIN_LEN(sa, len) SET_SA_LEN((struct sockaddr *)(sa), (len)) #endif +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN +# define SET_SIN6_LEN(sa, len) (void)((sa)->sin6_len = (len)) +#else +# define SET_SIN6_LEN(sa, len) SET_SA_LEN((struct sockaddr *)(sa), (len)) +#endif + #define INIT_SOCKADDR(addr, family, len) \ do { \ struct sockaddr *init_sockaddr_ptr = (addr); \ @@ -47,6 +53,15 @@ SET_SIN_LEN(init_sockaddr_ptr, init_sockaddr_len); \ } while (0) +#define INIT_SOCKADDR_IN6(addr, len) \ + do { \ + struct sockaddr_in6 *init_sockaddr_ptr = (addr); \ + socklen_t init_sockaddr_len = (len); \ + memset(init_sockaddr_ptr, 0, init_sockaddr_len); \ + init_sockaddr_ptr->sin6_family = AF_INET6; \ + SET_SIN6_LEN(init_sockaddr_ptr, init_sockaddr_len); \ + } while (0) + /* for strict-aliasing rule */ #ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c index a89c453239085c..761b11a2981c48 100644 --- a/ext/socket/udpsocket.c +++ b/ext/socket/udpsocket.c @@ -44,7 +44,7 @@ udp_init(int argc, VALUE *argv, VALUE sock) struct udp_arg { - struct addrinfo *res; + struct rb_addrinfo *res; int fd; }; @@ -54,7 +54,7 @@ udp_connect_internal(struct udp_arg *arg) int fd = arg->fd; struct addrinfo *res; - for (res = arg->res; res; res = res->ai_next) { + for (res = arg->res->ai; res; res = res->ai_next) { if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) { return Qtrue; } @@ -62,8 +62,6 @@ udp_connect_internal(struct udp_arg *arg) return Qfalse; } -VALUE rsock_freeaddrinfo(struct addrinfo *addr); - /* * call-seq: * udpsocket.connect(host, port) => 0 @@ -113,19 +111,20 @@ static VALUE udp_bind(VALUE sock, VALUE host, VALUE port) { rb_io_t *fptr; - struct addrinfo *res0, *res; + struct rb_addrinfo *res0; + struct addrinfo *res; rb_secure(3); res0 = rsock_addrinfo(host, port, SOCK_DGRAM, 0); GetOpenFile(sock, fptr); - for (res = res0; res; res = res->ai_next) { + for (res = res0->ai; res; res = res->ai_next) { if (bind(fptr->fd, res->ai_addr, res->ai_addrlen) < 0) { continue; } - freeaddrinfo(res0); + rb_freeaddrinfo(res0); return INT2FIX(0); } - freeaddrinfo(res0); + rb_freeaddrinfo(res0); rsock_sys_fail_host_port("bind(2)", host, port); @@ -160,7 +159,8 @@ udp_send(int argc, VALUE *argv, VALUE sock) VALUE flags, host, port; rb_io_t *fptr; int n; - struct addrinfo *res0, *res; + struct rb_addrinfo *res0; + struct addrinfo *res; struct rsock_send_arg arg; if (argc == 2 || argc == 3) { @@ -173,21 +173,21 @@ udp_send(int argc, VALUE *argv, VALUE sock) GetOpenFile(sock, fptr); arg.fd = fptr->fd; arg.flags = NUM2INT(flags); - for (res = res0; res; res = res->ai_next) { + for (res = res0->ai; res; res = res->ai_next) { retry: arg.to = res->ai_addr; arg.tolen = res->ai_addrlen; rb_thread_fd_writable(arg.fd); n = (int)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg); if (n >= 0) { - freeaddrinfo(res0); + rb_freeaddrinfo(res0); return INT2FIX(n); } if (rb_io_wait_writable(fptr->fd)) { goto retry; } } - freeaddrinfo(res0); + rb_freeaddrinfo(res0); rsock_sys_fail_host_port("sendto(2)", host, port); return INT2FIX(n); } diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c index 3fef619de62213..55563c3a69e009 100644 --- a/ext/stringio/stringio.c +++ b/ext/stringio/stringio.c @@ -1169,13 +1169,13 @@ strio_write(VALUE self, VALUE str) struct StringIO *ptr = writable(self); long len, olen; rb_encoding *enc, *enc2; + rb_encoding *const ascii8bit = rb_ascii8bit_encoding(); - RB_GC_GUARD(str); if (!RB_TYPE_P(str, T_STRING)) str = rb_obj_as_string(str); enc = rb_enc_get(ptr->string); enc2 = rb_enc_get(str); - if (enc != enc2 && enc != rb_ascii8bit_encoding()) { + if (enc != enc2 && enc != ascii8bit) { str = rb_str_conv_enc(str, enc2, enc); } len = RSTRING_LEN(str); @@ -1186,7 +1186,13 @@ strio_write(VALUE self, VALUE str) ptr->pos = olen; } if (ptr->pos == olen) { - rb_enc_str_buf_cat(ptr->string, RSTRING_PTR(str), len, enc); + if (enc == ascii8bit || enc2 == ascii8bit) { + rb_enc_str_buf_cat(ptr->string, RSTRING_PTR(str), len, enc); + OBJ_INFECT(ptr->string, str); + } + else { + rb_str_buf_append(ptr->string, str); + } } else { strio_extend(ptr, ptr->pos, len); @@ -1194,6 +1200,7 @@ strio_write(VALUE self, VALUE str) OBJ_INFECT(ptr->string, str); } OBJ_INFECT(ptr->string, self); + RB_GC_GUARD(str); ptr->pos += len; return LONG2NUM(len); } @@ -1233,17 +1240,17 @@ static VALUE strio_putc(VALUE self, VALUE ch) { struct StringIO *ptr = writable(self); - int c = NUM2CHR(ch); - long olen; + VALUE str; check_modifiable(ptr); - olen = RSTRING_LEN(ptr->string); - if (ptr->flags & FMODE_APPEND) { - ptr->pos = olen; + if (RB_TYPE_P(ch, T_STRING)) { + str = rb_str_substr(ch, 0, 1); } - strio_extend(ptr, ptr->pos, 1); - RSTRING_PTR(ptr->string)[ptr->pos++] = c; - OBJ_INFECT(ptr->string, self); + else { + char c = NUM2CHR(ch); + str = rb_str_new(&c, 1); + } + strio_write(self, str); return ch; } diff --git a/ext/thread/thread.c b/ext/thread/thread.c index c409b36da2c0ba..c3d81dc58d8a8b 100644 --- a/ext/thread/thread.c +++ b/ext/thread/thread.c @@ -11,14 +11,24 @@ enum { SZQUEUE_MAX = 3 }; -#define GET_CONDVAR_WAITERS(cv) RSTRUCT_GET((cv), CONDVAR_WAITERS) +#define GET_CONDVAR_WAITERS(cv) get_array((cv), CONDVAR_WAITERS) -#define GET_QUEUE_QUE(q) RSTRUCT_GET((q), QUEUE_QUE) -#define GET_QUEUE_WAITERS(q) RSTRUCT_GET((q), QUEUE_WAITERS) -#define GET_SZQUEUE_WAITERS(q) RSTRUCT_GET((q), SZQUEUE_WAITERS) +#define GET_QUEUE_QUE(q) get_array((q), QUEUE_QUE) +#define GET_QUEUE_WAITERS(q) get_array((q), QUEUE_WAITERS) +#define GET_SZQUEUE_WAITERS(q) get_array((q), SZQUEUE_WAITERS) #define GET_SZQUEUE_MAX(q) RSTRUCT_GET((q), SZQUEUE_MAX) #define GET_SZQUEUE_ULONGMAX(q) NUM2ULONG(GET_SZQUEUE_MAX(q)) +static VALUE +get_array(VALUE obj, int idx) +{ + VALUE ary = RSTRUCT_GET(obj, idx); + if (!RB_TYPE_P(ary, T_ARRAY)) { + rb_raise(rb_eTypeError, "%+"PRIsVALUE" not initialized", obj); + } + return ary; +} + static VALUE ary_buf_new(void) { @@ -534,6 +544,13 @@ rb_szqueue_num_waiting(VALUE self) #define UNDER_THREAD 1 #endif +static VALUE +undumpable(VALUE obj) +{ + rb_raise(rb_eTypeError, "can't dump %"PRIsVALUE, rb_obj_class(obj)); + UNREACHABLE; +} + void Init_thread(void) { @@ -572,11 +589,13 @@ Init_thread(void) id_sleep = rb_intern("sleep"); rb_define_method(rb_cConditionVariable, "initialize", rb_condvar_initialize, 0); + rb_define_method(rb_cConditionVariable, "marshal_dump", undumpable, 0); rb_define_method(rb_cConditionVariable, "wait", rb_condvar_wait, -1); rb_define_method(rb_cConditionVariable, "signal", rb_condvar_signal, 0); rb_define_method(rb_cConditionVariable, "broadcast", rb_condvar_broadcast, 0); rb_define_method(rb_cQueue, "initialize", rb_queue_initialize, 0); + rb_define_method(rb_cQueue, "marshal_dump", undumpable, 0); rb_define_method(rb_cQueue, "push", rb_queue_push, 1); rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1); rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0); diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index 072638a10b5920..57da91c67ab75d 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -361,7 +361,7 @@ static VALUE typelib_file_from_typelib(VALUE ole); static VALUE typelib_file(VALUE ole); static void ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self); static HRESULT clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid); -static VALUE ole_create_dcom(int argc, VALUE *argv, VALUE self); +static VALUE ole_create_dcom(VALUE self, VALUE ole, VALUE host, VALUE others); static VALUE ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self); static VALUE fole_s_connect(int argc, VALUE *argv, VALUE self); static VALUE fole_s_const_load(int argc, VALUE *argv, VALUE self); @@ -2636,9 +2636,8 @@ clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid) } static VALUE -ole_create_dcom(int argc, VALUE *argv, VALUE self) +ole_create_dcom(VALUE self, VALUE ole, VALUE host, VALUE others) { - VALUE ole, host, others; HRESULT hr; CLSID clsid; OLECHAR *pbuf; @@ -2656,7 +2655,6 @@ ole_create_dcom(int argc, VALUE *argv, VALUE self) GetProcAddress(gole32, "CoCreateInstanceEx"); if (!gCoCreateInstanceEx) rb_raise(rb_eRuntimeError, "CoCreateInstanceEx is not supported in this environment"); - rb_scan_args(argc, argv, "2*", &ole, &host, &others); pbuf = ole_vstr2wc(ole); hr = CLSIDFromProgID(pbuf, &clsid); @@ -3270,7 +3268,7 @@ fole_initialize(int argc, VALUE *argv, VALUE self) rb_raise(rb_eSecurityError, "Insecure Object Creation - %s", StringValuePtr(svr_name)); } - return ole_create_dcom(argc, argv, self); + return ole_create_dcom(self, svr_name, host, others); } /* get CLSID from OLE server name */ diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index ffdd9a0b7d51d2..4d8fde68c9d9f0 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -2288,6 +2288,7 @@ static void gzfile_reset(struct gzfile *gz) { zstream_reset(&gz->z); + gz->z.flags |= ZSTREAM_FLAG_GZFILE; gz->crc = crc32(0, Z_NULL, 0); gz->lineno = 0; gz->ungetc = 0; diff --git a/gc.c b/gc.c index 4c00d96d2e6626..7fa70c2c7a7832 100644 --- a/gc.c +++ b/gc.c @@ -1196,30 +1196,26 @@ heap_add_pages(rb_objspace_t *objspace, rb_heap_t *heap, size_t add) heap_pages_increment = 0; } -static size_t -heap_extend_pages(rb_objspace_t *objspace) +static void +heap_set_increment(rb_objspace_t *objspace, size_t minimum_limit) { size_t used = heap_pages_used - heap_tomb->page_length; size_t next_used_limit = (size_t)(used * gc_params.growth_factor); - if (gc_params.growth_max_slots > 0) { size_t max_used_limit = (size_t)(used + gc_params.growth_max_slots/HEAP_OBJ_LIMIT); if (next_used_limit > max_used_limit) next_used_limit = max_used_limit; } + if (next_used_limit == heap_pages_used) next_used_limit++; - return next_used_limit - used; + if (next_used_limit < minimum_limit) { + next_used_limit = minimum_limit; } -static void -heap_set_increment(rb_objspace_t *objspace, size_t additional_pages) -{ - size_t used = heap_eden->page_length; - size_t next_used_limit = used + additional_pages; - - if (next_used_limit == heap_pages_used) next_used_limit++; - heap_pages_increment = next_used_limit - used; heap_pages_expand_sorted(objspace); + + if (0) fprintf(stderr, "heap_set_increment: heap_pages_length: %d, heap_pages_used: %d, heap_pages_increment: %d, next_used_limit: %d\n", + (int)heap_pages_length, (int)heap_pages_used, (int)heap_pages_increment, (int)next_used_limit); } static int @@ -2862,7 +2858,7 @@ gc_heap_prepare_minimum_pages(rb_objspace_t *objspace, rb_heap_t *heap) { if (!heap->free_pages) { /* there is no free after page_sweep() */ - heap_set_increment(objspace, 1); + heap_set_increment(objspace, 0); if (!heap_increment(objspace, heap)) { /* can't allocate additional free objects */ during_gc = 0; rb_memerror(); @@ -3001,13 +2997,18 @@ gc_after_sweep(rb_objspace_t *objspace) (int)heap->total_slots, (int)heap_pages_swept_slots, (int)heap_pages_min_free_slots); if (heap_pages_swept_slots < heap_pages_min_free_slots) { +#if USE_RGENGC if (objspace->rgengc.during_minor_gc && objspace->profile.count - objspace->rgengc.last_major_gc > 2 /* magic number */) { objspace->rgengc.need_major_gc = GPR_FLAG_MAJOR_BY_NOFREE; } else { - heap_set_increment(objspace, heap_extend_pages(objspace)); + heap_set_increment(objspace, (heap_pages_min_free_slots - heap_pages_swept_slots) / HEAP_OBJ_LIMIT); heap_increment(objspace, heap); } +#else + heap_set_increment(objspace, (heap_pages_min_free_slots - heap_pages_swept_slots) / HEAP_OBJ_LIMIT); + heap_increment(objspace, heap); +#endif } gc_prof_set_heap_info(objspace); @@ -3255,14 +3256,14 @@ init_mark_stack(mark_stack_t *stack) /* Marking */ #ifdef __ia64 -#define SET_STACK_END (SET_MACHINE_STACK_END(&th->machine_stack_end), th->machine_register_stack_end = rb_ia64_bsp()) +#define SET_STACK_END (SET_MACHINE_STACK_END(&th->machine.stack_end), th->machine.register_stack_end = rb_ia64_bsp()) #else -#define SET_STACK_END SET_MACHINE_STACK_END(&th->machine_stack_end) +#define SET_STACK_END SET_MACHINE_STACK_END(&th->machine.stack_end) #endif -#define STACK_START (th->machine_stack_start) -#define STACK_END (th->machine_stack_end) -#define STACK_LEVEL_MAX (th->machine_stack_maxsize/sizeof(VALUE)) +#define STACK_START (th->machine.stack_start) +#define STACK_END (th->machine.stack_end) +#define STACK_LEVEL_MAX (th->machine.stack_maxsize/sizeof(VALUE)) #if STACK_GROW_DIRECTION < 0 # define STACK_LENGTH (size_t)(STACK_START - STACK_END) @@ -3304,8 +3305,8 @@ stack_check(int water_mark) ret = STACK_LENGTH > STACK_LEVEL_MAX - water_mark; #ifdef __ia64 if (!ret) { - ret = (VALUE*)rb_ia64_bsp() - th->machine_register_stack_start > - th->machine_register_stack_maxsize/sizeof(VALUE) - water_mark; + ret = (VALUE*)rb_ia64_bsp() - th->machine.register_stack_start > + th->machine.register_stack_maxsize/sizeof(VALUE) - water_mark; } #endif return ret; @@ -3523,13 +3524,17 @@ mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th) /* This assumes that all registers are saved into the jmp_buf (and stack) */ rb_setjmp(save_regs_gc_mark.j); + /* SET_STACK_END must be called in this function because + * the stack frame of this function may contain + * callee save registers and they should be marked. */ + SET_STACK_END; GET_STACK_BOUNDS(stack_start, stack_end, 1); mark_locations_array(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v)); rb_gc_mark_locations(stack_start, stack_end); #ifdef __ia64 - rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end); + rb_gc_mark_locations(th->machine.register_stack_start, th->machine.register_stack_end); #endif #if defined(__mc68000__) mark_locations_array(objspace, (VALUE*)((char*)STACK_END + 2), @@ -3546,7 +3551,7 @@ rb_gc_mark_machine_stack(rb_thread_t *th) GET_STACK_BOUNDS(stack_start, stack_end, 0); rb_gc_mark_locations(stack_start, stack_end); #ifdef __ia64 - rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end); + rb_gc_mark_locations(th->machine.register_stack_start, th->machine.register_stack_end); #endif } @@ -4190,7 +4195,6 @@ gc_marks_body(rb_objspace_t *objspace, int full_mark) } else { objspace->profile.major_gc_count++; - objspace->rgengc.last_major_gc = objspace->profile.count; rgengc_mark_and_rememberset_clear(objspace, heap_eden); } #endif @@ -4551,8 +4555,8 @@ gc_marks(rb_objspace_t *objspace, int full_mark) { /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */ const double r = gc_params.oldobject_limit_factor; - objspace->rgengc.remembered_shady_object_limit = objspace->rgengc.remembered_shady_object_count * r; - objspace->rgengc.old_object_limit = objspace->rgengc.old_object_count * r; + objspace->rgengc.remembered_shady_object_limit = (size_t)(objspace->rgengc.remembered_shady_object_count * r); + objspace->rgengc.old_object_limit = (size_t)(objspace->rgengc.old_object_count * r); } } else { /* minor GC */ @@ -5070,7 +5074,7 @@ heap_ready_to_gc(rb_objspace_t *objspace, rb_heap_t *heap) if (dont_gc || during_gc) { if (!heap->freelist && !heap->free_pages) { if (!heap_increment(objspace, heap)) { - heap_set_increment(objspace, 1); + heap_set_increment(objspace, 0); heap_increment(objspace, heap); } } @@ -5795,7 +5799,7 @@ ruby_gc_set_params(int safe_level) get_envparam_int("RUBY_GC_MALLOC_LIMIT_MAX", &gc_params.malloc_limit_max, 0); get_envparam_double("RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR", &gc_params.malloc_limit_growth_factor, 1.0); -#ifdef RGENGC_ESTIMATE_OLDMALLOC +#if RGENGC_ESTIMATE_OLDMALLOC if (get_envparam_int("RUBY_GC_OLDMALLOC_LIMIT", &gc_params.oldmalloc_limit_min, 0)) { rb_objspace_t *objspace = &rb_objspace; objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min; diff --git a/hash.c b/hash.c index 50f199fbc75be6..58f04a9663310c 100644 --- a/hash.c +++ b/hash.c @@ -2751,9 +2751,12 @@ ruby_setenv(const char *name, const char *value) int failed = 0; check_envname(name); if (value) { - const char* p = GetEnvironmentStringsA(); + char* p = GetEnvironmentStringsA(); + size_t n; if (!p) goto fail; /* never happen */ - if (strlen(name) + 2 + strlen(value) + getenvsize(p) >= getenvblocksize()) { + n = strlen(name) + 2 + strlen(value) + getenvsize(p); + FreeEnvironmentStringsA(p); + if (n >= getenvblocksize()) { goto fail; /* 2 for '=' & '\0' */ } buf = rb_sprintf("%s=%s", name, value); @@ -2873,8 +2876,8 @@ env_aset(VALUE obj, VALUE nm, VALUE val) env_delete(obj, nm); return Qnil; } - StringValue(nm); - StringValue(val); + SafeStringValue(nm); + SafeStringValue(val); name = RSTRING_PTR(nm); value = RSTRING_PTR(val); if (memchr(name, '\0', RSTRING_LEN(nm))) @@ -3136,23 +3139,21 @@ static VALUE env_select(VALUE ehash) { VALUE result; - char **env; + VALUE keys; + long i; RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size); result = rb_hash_new(); - env = GET_ENVIRON(environ); - while (*env) { - char *s = strchr(*env, '='); - if (s) { - VALUE k = env_str_new(*env, s-*env); - VALUE v = env_str_new2(s+1); - if (RTEST(rb_yield_values(2, k, v))) { - rb_hash_aset(result, k, v); + keys = env_keys(); + for (i = 0; i < RARRAY_LEN(keys); ++i) { + VALUE key = RARRAY_AREF(keys, i); + VALUE val = rb_f_getenv(Qnil, key); + if (!NIL_P(val)) { + if (RTEST(rb_yield_values(2, key, val))) { + rb_hash_aset(result, key, val); } } - env++; } - FREE_ENVIRON(environ); return result; } @@ -3371,7 +3372,8 @@ env_has_key(VALUE env, VALUE key) { char *s; - s = StringValuePtr(key); + SafeStringValue(key); + s = RSTRING_PTR(key); if (memchr(s, '\0', RSTRING_LEN(key))) rb_raise(rb_eArgError, "bad environment variable name"); if (getenv(s)) return Qtrue; @@ -3390,7 +3392,8 @@ env_assoc(VALUE env, VALUE key) { char *s, *e; - s = StringValuePtr(key); + SafeStringValue(key); + s = RSTRING_PTR(key); if (memchr(s, '\0', RSTRING_LEN(key))) rb_raise(rb_eArgError, "bad environment variable name"); e = getenv(s); @@ -3412,6 +3415,7 @@ env_has_value(VALUE dmy, VALUE obj) obj = rb_check_string_type(obj); if (NIL_P(obj)) return Qnil; + rb_check_safe_obj(obj); env = GET_ENVIRON(environ); while (*env) { char *s = strchr(*env, '='); @@ -3442,6 +3446,7 @@ env_rassoc(VALUE dmy, VALUE obj) obj = rb_check_string_type(obj); if (NIL_P(obj)) return Qnil; + rb_check_safe_obj(obj); env = GET_ENVIRON(environ); while (*env) { char *s = strchr(*env, '='); @@ -3472,7 +3477,7 @@ env_key(VALUE dmy, VALUE value) char **env; VALUE str; - StringValue(value); + SafeStringValue(value); env = GET_ENVIRON(environ); while (*env) { char *s = strchr(*env, '='); @@ -3556,6 +3561,7 @@ static VALUE env_shift(void) { char **env; + VALUE result = Qnil; env = GET_ENVIRON(environ); if (*env) { @@ -3564,11 +3570,11 @@ env_shift(void) VALUE key = env_str_new(*env, s-*env); VALUE val = env_str_new2(getenv(RSTRING_PTR(key))); env_delete(Qnil, key); - return rb_assoc_new(key, val); + result = rb_assoc_new(key, val); } } FREE_ENVIRON(environ); - return Qnil; + return result; } /* diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 6200e77a63f7f3..46af270bb3fcf7 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -939,11 +939,14 @@ VALUE rb_mod_remove_cvar(VALUE, VALUE); ID rb_frame_callee(void); VALUE rb_str_succ(VALUE); VALUE rb_time_succ(VALUE); -void rb_frame_pop(void); int rb_frame_method_id_and_class(ID *idp, VALUE *klassp); VALUE rb_make_backtrace(void); VALUE rb_make_exception(int, VALUE*); +/* deprecated */ +DEPRECATED(void rb_frame_pop(void)); + + RUBY_SYMBOL_EXPORT_END #if defined(__cplusplus) diff --git a/include/ruby/oniguruma.h b/include/ruby/oniguruma.h index 6a26ee4aaa6f18..d533a05b6674b5 100644 --- a/include/ruby/oniguruma.h +++ b/include/ruby/oniguruma.h @@ -338,6 +338,7 @@ int onigenc_str_bytelen_null P_((OnigEncoding enc, const OnigUChar* p)); /* config parameters */ #define ONIG_NREGION 10 #define ONIG_MAX_BACKREF_NUM 1000 +#define ONIG_MAX_CAPTURE_GROUP_NUM 32767 #define ONIG_MAX_REPEAT_NUM 100000 #define ONIG_MAX_MULTI_BYTE_RANGES_NUM 10000 /* constants */ @@ -582,6 +583,7 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax; #define ONIGERR_NEVER_ENDING_RECURSION -221 #define ONIGERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY -222 #define ONIGERR_INVALID_CHAR_PROPERTY_NAME -223 +#define ONIGERR_TOO_MANY_CAPTURE_GROUPS -224 #define ONIGERR_INVALID_CODE_POINT_VALUE -400 #define ONIGERR_INVALID_WIDE_CHAR_VALUE -400 #define ONIGERR_TOO_BIG_WIDE_CHAR_VALUE -401 diff --git a/include/ruby/win32.h b/include/ruby/win32.h index 070bab28f9c0c7..64fbdf2744da1e 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -309,6 +309,7 @@ extern char **rb_w32_get_environ(void); extern void rb_w32_free_environ(char **); extern int rb_w32_map_errno(DWORD); extern const char *WSAAPI rb_w32_inet_ntop(int,const void *,char *,size_t); +extern int WSAAPI rb_w32_inet_pton(int,const char *,void *); extern DWORD rb_w32_osver(void); extern int chown(const char *, int, int); @@ -652,6 +653,9 @@ extern char *rb_w32_strerror(int); #undef inet_ntop #define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l) +#undef inet_pton +#define inet_pton(f,s,d) rb_w32_inet_pton(f,s,d) + #undef accept #define accept(s, a, l) rb_w32_accept(s, a, l) @@ -772,6 +776,8 @@ int rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout); int rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait); int rb_w32_wrap_io_handle(HANDLE, int); int rb_w32_unwrap_io_handle(int); +WCHAR *rb_w32_mbstr_to_wstr(UINT, const char *, int, long *); +char *rb_w32_wstr_to_mbstr(UINT, const WCHAR *, int, long *); /* == ***CAUTION*** diff --git a/insns.def b/insns.def index 0247b19ecd72cb..96e7ce6a4239e7 100644 --- a/insns.def +++ b/insns.def @@ -1550,8 +1550,7 @@ opt_mod y = FIX2LONG(obj); if (x > 0 && y > 0) { val = LONG2FIX(x % y); - } - else { + } else { /* copied from numeric.c#fixdivmod */ long div, mod; @@ -2137,8 +2136,7 @@ opt_regexpmatch1 { if (BASIC_OP_UNREDEFINED_P(BOP_MATCH, REGEXP_REDEFINED_OP_FLAG)) { val = rb_reg_match(r, obj); - } - else { + } else { val = rb_funcall(r, idEqTilde, 1, obj); } } diff --git a/internal.h b/internal.h index 01bf81c4959b48..afa936ecbff0f4 100644 --- a/internal.h +++ b/internal.h @@ -613,7 +613,9 @@ rb_float_new_inline(double d) #define rb_float_new(d) rb_float_new_inline(d) /* object.c */ +void rb_obj_copy_ivar(VALUE dest, VALUE obj); VALUE rb_obj_equal(VALUE obj1, VALUE obj2); +VALUE rb_class_search_ancestor(VALUE klass, VALUE super); struct RBasicRaw { VALUE flags; @@ -783,6 +785,7 @@ void rb_vm_inc_const_missing_count(void); void rb_thread_mark(void *th); const void **rb_vm_get_insns_address_table(void); VALUE rb_sourcefilename(void); +void rb_vm_pop_cfunc_frame(void); /* vm_dump.c */ void rb_vm_bugreport(void); diff --git a/io.c b/io.c index 6e3fd85d2b1238..95229903ca3b4a 100644 --- a/io.c +++ b/io.c @@ -590,6 +590,8 @@ is_socket(int fd, VALUE path) } #endif +static const char closed_stream[] = "closed stream"; + void rb_eof_error(void) { @@ -616,7 +618,7 @@ rb_io_check_closed(rb_io_t *fptr) { rb_io_check_initialized(fptr); if (fptr->fd < 0) { - rb_raise(rb_eIOError, "closed stream"); + rb_raise(rb_eIOError, closed_stream); } } @@ -1075,7 +1077,7 @@ int rb_io_wait_readable(int f) { if (f < 0) { - rb_raise(rb_eIOError, "closed stream"); + rb_raise(rb_eIOError, closed_stream); } switch (errno) { case EINTR: @@ -1101,7 +1103,7 @@ int rb_io_wait_writable(int f) { if (f < 0) { - rb_raise(rb_eIOError, "closed stream"); + rb_raise(rb_eIOError, closed_stream); } switch (errno) { case EINTR: @@ -1914,10 +1916,10 @@ rb_io_fdatasync(VALUE io) static VALUE rb_io_fileno(VALUE io) { - rb_io_t *fptr; + rb_io_t *fptr = RFILE(io)->fptr; int fd; - GetOpenFile(io, fptr); + rb_io_check_closed(fptr); fd = fptr->fd; return INT2FIX(fd); } @@ -1969,7 +1971,7 @@ rb_io_inspect(VALUE obj) VALUE result; static const char closed[] = " (closed)"; - fptr = RFILE(rb_io_taint_check(obj))->fptr; + fptr = RFILE(obj)->fptr; if (!fptr) return rb_any_to_s(obj); result = rb_str_new_cstr("#<"); rb_str_append(result, rb_class_name(CLASS_OF(obj))); @@ -2290,10 +2292,7 @@ io_setstrbuf(VALUE *str, long len) VALUE s = StringValue(*str); long clen = RSTRING_LEN(s); if (clen >= len) { - if (clen != len) { - rb_str_modify(s); - rb_str_set_len(s, len); - } + rb_str_modify(s); return; } len -= clen; @@ -2320,23 +2319,27 @@ read_all(rb_io_t *fptr, long siz, VALUE str) int cr; if (NEED_READCONV(fptr)) { + int first = !NIL_P(str); SET_BINARY_MODE(fptr); io_setstrbuf(&str,0); make_readconv(fptr, 0); while (1) { VALUE v; if (fptr->cbuf.len) { + if (first) rb_str_set_len(str, first = 0); io_shift_cbuf(fptr, fptr->cbuf.len, &str); } v = fill_cbuf(fptr, 0); if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) { if (fptr->cbuf.len) { + if (first) rb_str_set_len(str, first = 0); io_shift_cbuf(fptr, fptr->cbuf.len, &str); } rb_exc_raise(v); } if (v == MORE_CHAR_FINISHED) { clear_readconv(fptr); + if (first) rb_str_set_len(str, first = 0); return io_enc_str(str, fptr); } } @@ -2807,7 +2810,10 @@ io_read(int argc, VALUE *argv, VALUE io) GetOpenFile(io, fptr); rb_io_check_byte_readable(fptr); - if (len == 0) return str; + if (len == 0) { + io_set_read_length(str, 0); + return str; + } READ_CHECK(fptr); #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32) @@ -4058,7 +4064,7 @@ finish_writeconv(rb_io_t *fptr, int noalloc) } if (rb_io_wait_writable(fptr->fd)) { if (fptr->fd < 0) - return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr("closed stream")); + return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream)); goto retry; } return noalloc ? Qtrue : INT2NUM(errno); @@ -4340,13 +4346,31 @@ rb_io_close_m(VALUE io) static VALUE io_call_close(VALUE io) { - return rb_funcall(io, rb_intern("close"), 0, 0); + rb_check_funcall(io, rb_intern("close"), 0, 0); + return io; +} + +static VALUE +ignore_closed_stream(VALUE io, VALUE exc) +{ + enum {mesg_len = sizeof(closed_stream)-1}; + VALUE mesg = rb_attr_get(exc, rb_intern("mesg")); + if (!RB_TYPE_P(mesg, T_STRING) || + RSTRING_LEN(mesg) != mesg_len || + memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) { + rb_exc_raise(exc); + } + return io; } static VALUE io_close(VALUE io) { - return rb_rescue(io_call_close, io, 0, 0); + VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0); + if (closed != Qundef && RTEST(closed)) return io; + rb_rescue2(io_call_close, io, ignore_closed_stream, io, + rb_eIOError, (VALUE)0); + return io; } /* @@ -7270,12 +7294,12 @@ rb_io_stdio_file(rb_io_t *fptr) * "w+" Read-write, truncates existing file to zero length * or creates a new file for reading and writing. * - * "a" Write-only, starts at end of file if file exists, - * otherwise creates a new file for writing. + * "a" Write-only, each write call appends data at end of file. + * Creates a new file for writing if file does not exist. * - * "a+" Read-write, starts at end of file if file exists, - * otherwise creates a new file for reading and - * writing. + * "a+" Read-write, each write call appends data at end of file. + * Creates a new file for reading and writing if file does + * not exist. * * The following modes must be used separately, and along with one or more of * the modes seen above. @@ -7515,8 +7539,8 @@ rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass) static VALUE rb_io_autoclose_p(VALUE io) { - rb_io_t *fptr; - GetOpenFile(io, fptr); + rb_io_t *fptr = RFILE(io)->fptr; + rb_io_check_closed(fptr); return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue; } diff --git a/iseq.c b/iseq.c index 32d996796429f9..700a161f6bc3e6 100644 --- a/iseq.c +++ b/iseq.c @@ -1943,7 +1943,7 @@ rb_iseq_clone(VALUE iseqval, VALUE newcbase) if (iseq0->cref_stack->nd_next) { RB_OBJ_WRITE(iseq1->cref_stack, &iseq1->cref_stack->nd_next, iseq0->cref_stack->nd_next); } - RB_OBJ_WRITE(iseq1, &iseq1->klass, newcbase); + RB_OBJ_WRITE(iseq1->self, &iseq1->klass, newcbase); } return newiseq; diff --git a/lib/csv.rb b/lib/csv.rb index e5ecf5c9a8a289..b8a9b97f1614c1 100644 --- a/lib/csv.rb +++ b/lib/csv.rb @@ -1148,9 +1148,9 @@ def self.generate(*args) io.seek(0, IO::SEEK_END) args.unshift(io) else - encoding = (args[-1] = args[-1].dup).delete(:encoding) if args.last.is_a?(Hash) + encoding = args[-1][:encoding] if args.last.is_a?(Hash) str = "" - str.encode!(encoding) if encoding + str.force_encoding(encoding) if encoding args.unshift(str) end csv = new(*args) # wrap @@ -1507,8 +1507,7 @@ def initialize(data, options = Hash.new) # if we can transcode the needed characters # @re_esc = "\\".encode(@encoding) rescue "" - @re_chars = /#{%"[-][\\.^$?*+{}()|# \r\n\t\f\v]".encode(@encoding)}/ - # @re_chars = /#{%"[-][\\.^$?*+{}()|# \r\n\t\f\v]".encode(@encoding, fallback: proc{""})}/ + @re_chars = /#{%"[-\\]\\[\\.^$?*+{}()|# \r\n\t\f\v]".encode(@encoding)}/ init_separators(options) init_parsers(options) @@ -1516,7 +1515,7 @@ def initialize(data, options = Hash.new) init_headers(options) init_comments(options) - options.delete(:encoding) + @force_encoding = !!(encoding || options.delete(:encoding)) options.delete(:internal_encoding) options.delete(:external_encoding) unless options.empty? @@ -1656,10 +1655,13 @@ def <<(row) output = row.map(&@quote).join(@col_sep) + @row_sep # quote and separate if @io.is_a?(StringIO) and - output.encoding != raw_encoding and - (compatible_encoding = Encoding.compatible?(@io.string, output)) - @io.set_encoding(compatible_encoding) - @io.seek(0, IO::SEEK_END) + output.encoding != (encoding = raw_encoding) + if @force_encoding + output = output.encode(encoding) + elsif (compatible_encoding = Encoding.compatible?(@io.string, output)) + @io.set_encoding(compatible_encoding) + @io.seek(0, IO::SEEK_END) + end end @io << output diff --git a/lib/erb.rb b/lib/erb.rb index 5d32c47774de04..3c3cabe209ad8a 100644 --- a/lib/erb.rb +++ b/lib/erb.rb @@ -837,7 +837,7 @@ def run(b=new_toplevel) # the results of that code. (See ERB::new for details on how this process # can be affected by _safe_level_.) # - # _b_ accepts a Binding or Proc object which is used to set the context of + # _b_ accepts a Binding object which is used to set the context of # code evaluation. # def result(b=new_toplevel) diff --git a/lib/fileutils.rb b/lib/fileutils.rb index 3b4e30213e4e79..99044e2cd63114 100644 --- a/lib/fileutils.rb +++ b/lib/fileutils.rb @@ -277,7 +277,7 @@ def rmdir(list, options = {}) Dir.rmdir(dir) end end - rescue Errno::ENOTEMPTY, Errno::ENOENT + rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT end end end @@ -455,8 +455,8 @@ def cp_r(src, dest, options = {}) # Both of +src+ and +dest+ must be a path name. # +src+ must exist, +dest+ must not exist. # - # If +preserve+ is true, this method preserves owner, group, permissions - # and modified time. + # If +preserve+ is true, this method preserves owner, group, and + # modified time. Permissions are copied regardless +preserve+. # # If +dereference_root+ is true, this method dereference tree root. # diff --git a/lib/gserver.rb b/lib/gserver.rb index 4d566fcf2ef25d..d7b4a0783efcf5 100644 --- a/lib/gserver.rb +++ b/lib/gserver.rb @@ -37,7 +37,7 @@ # super(port, *args) # end # def serve(io) -# io.puts(Time.now.to_s) +# io.puts(Time.now.to_i) # end # end # @@ -144,7 +144,7 @@ def join attr_reader :port # Host on which to bind, as a String attr_reader :host - # Maximum number of connections to accept at at ime, as a Fixnum + # Maximum number of connections to accept at a time, as a Fixnum attr_reader :maxConnections # IO Device on which log messages should be written attr_accessor :stdlog @@ -156,7 +156,7 @@ def join # Called when a client connects, if auditing is enabled. # - # +client+:: a TCPSocket instances representing the client that connected + # +client+:: a TCPSocket instance representing the client that connected # # Return true to allow this client to connect, false to prevent it. def connecting(client) @@ -192,7 +192,7 @@ def stopping() # Called if #debug is true whenever an unhandled exception is raised. # This implementation simply logs the backtrace. # - # +detail+:: The Exception that was caught + # +detail+:: the Exception that was caught def error(detail) log(detail.backtrace.join("\n")) end @@ -212,9 +212,9 @@ def log(msg) # Create a new server # - # +port+:: the port, as a Fixnum, on which to listen. + # +port+:: the port, as a Fixnum, on which to listen # +host+:: the host to bind to - # +maxConnections+:: The maximum number of simultaneous connections to + # +maxConnections+:: the maximum number of simultaneous connections to # accept # +stdlog+:: IO device on which to log messages # +audit+:: if true, lifecycle callbacks will be called. See #audit diff --git a/lib/matrix.rb b/lib/matrix.rb index f82ed659798df7..b20fd9451fafc4 100644 --- a/lib/matrix.rb +++ b/lib/matrix.rb @@ -1764,9 +1764,9 @@ def inner_product(v) # def cross_product(v) Vector.Raise ErrDimensionMismatch unless size == v.size && v.size == 3 - Vector[ v[1]*@elements[2] - v[2]*@elements[1], - v[2]*@elements[0] - v[0]*@elements[2], - v[0]*@elements[1] - v[1]*@elements[0] ] + Vector[ v[2]*@elements[1] - v[1]*@elements[2], + v[0]*@elements[2] - v[2]*@elements[0], + v[1]*@elements[0] - v[0]*@elements[1] ] end # diff --git a/lib/mkmf.rb b/lib/mkmf.rb index 2d44b123d2f293..b408ed780f8df9 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb @@ -1764,6 +1764,7 @@ def pkg_config(pkg, option=nil) libs = get['libs-only-l'] ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ") $CFLAGS += " " << cflags + $CXXFLAGS += " " << cflags $LDFLAGS = [orig_ldflags, ldflags].join(' ') $libs += " " << libs Logging::message "package configuration for %s\n", pkg @@ -1905,7 +1906,7 @@ def configuration(srcdir) INCFLAGS = -I. #$INCFLAGS DEFS = #{CONFIG['DEFS']} CPPFLAGS = #{extconf_h}#{$CPPFLAGS} -CXXFLAGS = $(CCDLFLAGS) #{CONFIG['CXXFLAGS']} $(ARCH_FLAG) +CXXFLAGS = $(CCDLFLAGS) #$CXXFLAGS $(ARCH_FLAG) ldflags = #{$LDFLAGS} dldflags = #{$DLDFLAGS} #{CONFIG['EXTDLDFLAGS']} ARCH_FLAG = #{$ARCH_FLAG} @@ -2398,6 +2399,7 @@ def init_mkmf(config = CONFIG, rbconfig = RbConfig::CONFIG) $warnflags = config['warnflags'] unless $extmk end $CFLAGS = with_config("cflags", arg_config("CFLAGS", config["CFLAGS"])).dup + $CXXFLAGS = (with_config("cxxflags", arg_config("CXXFLAGS", config["CXXFLAGS"]))||'').dup $ARCH_FLAG = with_config("arch_flag", arg_config("ARCH_FLAG", config["ARCH_FLAG"])).dup $CPPFLAGS = with_config("cppflags", arg_config("CPPFLAGS", config["CPPFLAGS"])).dup $LDFLAGS = with_config("ldflags", arg_config("LDFLAGS", config["LDFLAGS"])).dup diff --git a/lib/net/ftp.rb b/lib/net/ftp.rb index c22b9636d5d47f..a57372ac3b7124 100644 --- a/lib/net/ftp.rb +++ b/lib/net/ftp.rb @@ -420,23 +420,26 @@ def transfercmd(cmd, rest_offset = nil) # :nodoc: end else sock = makeport - if @resume and rest_offset - resp = sendcmd("REST " + rest_offset.to_s) - if resp[0] != ?3 + begin + if @resume and rest_offset + resp = sendcmd("REST " + rest_offset.to_s) + if resp[0] != ?3 + raise FTPReplyError, resp + end + end + resp = sendcmd(cmd) + # skip 2XX for some ftp servers + resp = getresp if resp[0] == ?2 + if resp[0] != ?1 raise FTPReplyError, resp end + conn = BufferedSocket.new(sock.accept) + conn.read_timeout = @read_timeout + sock.shutdown(Socket::SHUT_WR) rescue nil + sock.read rescue nil + ensure + sock.close end - resp = sendcmd(cmd) - # skip 2XX for some ftp servers - resp = getresp if resp[0] == ?2 - if resp[0] != ?1 - raise FTPReplyError, resp - end - conn = BufferedSocket.new(sock.accept) - conn.read_timeout = @read_timeout - sock.shutdown(Socket::SHUT_WR) rescue nil - sock.read rescue nil - sock.close end return conn end @@ -1102,13 +1105,16 @@ def read(len = nil) end def gets - return readuntil("\n") - rescue EOFError - return nil + line = readuntil("\n", true) + return line.empty? ? nil : line end def readline - return readuntil("\n") + line = gets + if line.nil? + raise EOFError, "end of file reached" + end + return line end end # :startdoc: diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 55c611b9c66697..1bb0b81eecdff6 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -2372,6 +2372,8 @@ def body_type_1part return body_type_msg when /\A(?:ATTACHMENT)\z/ni return body_type_attachment + when /\A(?:MIXED)\z/ni + return body_type_mixed else return body_type_basic end @@ -2454,6 +2456,13 @@ def body_type_attachment return BodyTypeAttachment.new(mtype, nil, param) end + def body_type_mixed + mtype = "MULTIPART" + msubtype = case_insensitive_string + param, disposition, language, extension = body_ext_mpart + return BodyTypeBasic.new(mtype, msubtype, param, nil, nil, nil, nil, nil, disposition, language, extension) + end + def body_type_mpart parts = [] while true diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb index 14a68e11154b6c..25477014fb090d 100644 --- a/lib/net/protocol.rb +++ b/lib/net/protocol.rb @@ -267,7 +267,7 @@ def each_list_item def write_message_0(src) prev = @written_bytes each_crlf_line(src) do |line| - write0 line.sub(/\A\./, '..') + write0 dot_stuff(line) end @written_bytes - prev end @@ -308,11 +308,15 @@ def write_message_by_block(&block) private + def dot_stuff(s) + s.sub(/\A\./, '..') + end + def using_each_crlf_line @wbuf = '' yield if not @wbuf.empty? # unterminated last line - write0 @wbuf.chomp + "\r\n" + write0 dot_stuff(@wbuf.chomp) + "\r\n" elsif @written_bytes == 0 # empty src write0 "\r\n" end diff --git a/lib/rdoc/generator/template/darkfish/js/jquery.js b/lib/rdoc/generator/template/darkfish/js/jquery.js index 48590ecb96a74f..628ed9b31604ed 100644 --- a/lib/rdoc/generator/template/darkfish/js/jquery.js +++ b/lib/rdoc/generator/template/darkfish/js/jquery.js @@ -1,18 +1,4 @@ -/*! - * jQuery JavaScript Library v1.6.2 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Jun 30 14:16:56 2011 -0400 - */ -(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i. -shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j -)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file +/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ +(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/lib/resolv.rb b/lib/resolv.rb index 6b2fa9d90333e2..60b2d9091c20e8 100644 --- a/lib/resolv.rb +++ b/lib/resolv.rb @@ -653,7 +653,9 @@ def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc: begin port = rangerand(1024..65535) udpsock.bind(bind_host, port) - rescue Errno::EADDRINUSE, Errno::EACCES + rescue Errno::EADDRINUSE, # POSIX + Errno::EACCES, # SunOS: See PRIV_SYS_NFS in privileges(5) + Errno::EPERM # FreeBSD: security.mac.portacl.port_high is configurable. See mac_portacl(4). retry end end diff --git a/lib/rinda/tuplespace.rb b/lib/rinda/tuplespace.rb index ee2bef17690d86..11532fd161960c 100644 --- a/lib/rinda/tuplespace.rb +++ b/lib/rinda/tuplespace.rb @@ -76,7 +76,7 @@ def expired? # Reset the expiry time according to +sec_or_renewer+. # # +nil+:: it is set to expire in the far future. - # +false+:: it has expired. + # +true+:: it has expired. # Numeric:: it will expire in that many seconds. # # Otherwise the argument refers to some kind of renewer object diff --git a/lib/test/unit/parallel.rb b/lib/test/unit/parallel.rb index c1ecf292632e9b..92cc7ec44b6559 100644 --- a/lib/test/unit/parallel.rb +++ b/lib/test/unit/parallel.rb @@ -155,6 +155,11 @@ def _report(res, *args) # :nodoc: end def puke(klass, meth, e) # :nodoc: + if e.is_a?(MiniTest::Skip) + new_e = MiniTest::Skip.new(e.message) + new_e.set_backtrace(e.backtrace) + e = new_e + end @partial_report << [klass.name, meth, e.is_a?(MiniTest::Assertion) ? e : ProxyError.new(e)] super end diff --git a/lib/time.rb b/lib/time.rb index 0b554803340fc3..dd7a513dbaed9b 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -278,13 +278,13 @@ def make_time(year, mon, day, hour, min, sec, sec_fraction, zone, now) # supplied with those of +now+. For the lower components, the minimum # values (1 or 0) are assumed if broken or missing. For example: # - # # Suppose it is "Thu Nov 29 14:33:20 GMT 2001" now and - # # your time zone is GMT: - # now = Time.parse("Thu Nov 29 14:33:20 GMT 2001") - # Time.parse("16:30", now) #=> 2001-11-29 16:30:00 +0900 - # Time.parse("7/23", now) #=> 2001-07-23 00:00:00 +0900 - # Time.parse("Aug 31", now) #=> 2001-08-31 00:00:00 +0900 - # Time.parse("Aug 2000", now) #=> 2000-08-01 00:00:00 +0900 + # # Suppose it is "Thu Nov 29 14:33:20 2001" now and + # # your time zone is EST which is GMT-5. + # now = Time.parse("Thu Nov 29 14:33:20 2001") + # Time.parse("16:30", now) #=> 2001-11-29 16:30:00 -0500 + # Time.parse("7/23", now) #=> 2001-07-23 00:00:00 -0500 + # Time.parse("Aug 31", now) #=> 2001-08-31 00:00:00 -0500 + # Time.parse("Aug 2000", now) #=> 2000-08-01 00:00:00 -0500 # # Since there are numerous conflicts among locally defined time zone # abbreviations all over the world, this method is not intended to diff --git a/lib/webrick/utils.rb b/lib/webrick/utils.rb index a6b5cc6a9c2db8..0723fd8a4d5da3 100644 --- a/lib/webrick/utils.rb +++ b/lib/webrick/utils.rb @@ -75,7 +75,9 @@ def create_listeners(address, port, logger=nil) sockets = Socket.tcp_server_sockets(address, port) sockets = sockets.map {|s| s.autoclose = false - TCPServer.for_fd(s.fileno) + ts = TCPServer.for_fd(s.fileno) + s.close + ts } return sockets end diff --git a/lib/xmlrpc/client.rb b/lib/xmlrpc/client.rb index 5ee3961f3018d7..95b1ea2d1755ce 100644 --- a/lib/xmlrpc/client.rb +++ b/lib/xmlrpc/client.rb @@ -507,8 +507,6 @@ def do_rpc(request, async=false) expected = resp["Content-Length"] || "" if data.nil? or data.bytesize == 0 raise "Wrong size. Was #{data.bytesize}, should be #{expected}" - elsif expected != "" and expected.to_i != data.bytesize and resp["Transfer-Encoding"].nil? - raise "Wrong size. Was #{data.bytesize}, should be #{expected}" end parse_set_cookies(resp.get_fields("Set-Cookie")) diff --git a/man/ruby.1 b/man/ruby.1 index ec79e1d07b9f03..75dff3c435f2c9 100644 --- a/man/ruby.1 +++ b/man/ruby.1 @@ -493,8 +493,6 @@ The official web site. hosting many open source ruby projects. .It https://www.ruby-toolbox.com Comprehensive catalog of Ruby libraries. -.It https://github.com/languages/Ruby -Ruby projects on Github. .El .Pp .Sh REPORTING BUGS diff --git a/marshal.c b/marshal.c index 2fe272100bc481..a0630cb35ca2ba 100644 --- a/marshal.c +++ b/marshal.c @@ -650,6 +650,11 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) else { VALUE v; + if (!RBASIC_CLASS(obj)) { + rb_raise(rb_eTypeError, "can't dump internal %s", + rb_builtin_type_name(BUILTIN_TYPE(obj))); + } + arg->infection |= (int)FL_TEST(obj, MARSHAL_INFECTION); if (rb_obj_respond_to(obj, s_mdump, TRUE)) { diff --git a/node.c b/node.c index 472a959ef954ee..fbefb3cd47faf3 100644 --- a/node.c +++ b/node.c @@ -300,7 +300,12 @@ dump_node(VALUE buf, VALUE indent, int comment, NODE *node) asgn: F_ID(nd_vid, "variable"); LAST_NODE; - F_NODE(nd_value, "rvalue"); + if (node->nd_value == (NODE *)-1) { + F_MSG(nd_value, "rvalue", "(required keyword argument)"); + } + else { + F_NODE(nd_value, "rvalue"); + } break; case NODE_GASGN: diff --git a/numeric.c b/numeric.c index f4233d946027fc..b7a4e968efdcd4 100644 --- a/numeric.c +++ b/numeric.c @@ -109,7 +109,7 @@ static VALUE fix_uminus(VALUE num); static VALUE fix_mul(VALUE x, VALUE y); static VALUE int_pow(long x, unsigned long y); -static ID id_coerce, id_to_i, id_eq, id_div; +static ID id_coerce, id_to_i, id_eq, id_div, id_cmp; VALUE rb_cNumeric; VALUE rb_cFloat; @@ -119,7 +119,7 @@ VALUE rb_cFixnum; VALUE rb_eZeroDivError; VALUE rb_eFloatDomainError; -static VALUE sym_to, sym_by; +static ID id_to, id_by; void rb_num_zerodiv(void) @@ -232,17 +232,19 @@ coerce_body(VALUE *x) return rb_funcall(x[1], id_coerce, 1, x[0]); } +NORETURN(static void coerce_failed(VALUE x, VALUE y)); +static void +coerce_failed(VALUE x, VALUE y) +{ + rb_raise(rb_eTypeError, "%"PRIsVALUE" can't be coerced into %"PRIsVALUE, + (rb_special_const_p(y)? rb_inspect(y) : rb_obj_class(y)), + rb_obj_class(x)); +} + static VALUE coerce_rescue(VALUE *x) { - volatile VALUE v = rb_inspect(x[1]); - - rb_raise(rb_eTypeError, "%s can't be coerced into %s", - rb_special_const_p(x[1])? - RSTRING_PTR(v): - rb_obj_classname(x[1]), - rb_obj_classname(x[0])); - + coerce_failed(x[0], x[1]); return Qnil; /* dummy */ } @@ -1168,7 +1170,7 @@ flo_cmp(VALUE x, VALUE y) if (a > 0.0) return INT2FIX(1); return INT2FIX(-1); } - return rb_num_coerce_cmp(x, y, rb_intern("<=>")); + return rb_num_coerce_cmp(x, y, id_cmp); } return rb_dbl_cmp(a, b); } @@ -1758,6 +1760,9 @@ ruby_float_step_size(double beg, double end, double unit, int excl) if (isinf(unit)) { return unit > 0 ? beg <= end : beg >= end; } + if (unit == 0) { + return INFINITY; + } if (err>0.5) err=0.5; if (excl) { if (n<=0) return 0; @@ -1787,6 +1792,11 @@ ruby_float_step(VALUE from, VALUE to, VALUE step, int excl) /* if unit is infinity, i*unit+beg is NaN */ if (n) rb_yield(DBL2NUM(beg)); } + else if (unit == 0) { + VALUE val = DBL2NUM(beg); + for (;;) + rb_yield(val); + } else { for (i=0; i 0 ? -1 : +1); + delta--; + } + if (delta < 0) { + return INT2FIX(0); } - result = delta / diff; - return LONG2FIX(result >= 0 ? result + 1 : 0); + return ULONG2NUM(delta / diff + 1UL); } else if (RB_TYPE_P(from, T_FLOAT) || RB_TYPE_P(to, T_FLOAT) || RB_TYPE_P(step, T_FLOAT)) { double n = ruby_float_step_size(NUM2DBL(from), NUM2DBL(to), NUM2DBL(step), excl); if (isinf(n)) return DBL2NUM(n); - return LONG2FIX(n); + if (POSFIXABLE(n)) return LONG2FIX(n); + return rb_dbl2big(n); } else { VALUE result; - ID cmp = RTEST(rb_funcall(step, '>', 1, INT2FIX(0))) ? '>' : '<'; + ID cmp = '>'; + switch (rb_cmpint(rb_num_coerce_cmp(step, INT2FIX(0), id_cmp), step, INT2FIX(0))) { + case 0: return DBL2NUM(INFINITY); + case -1: cmp = '<'; break; + } if (RTEST(rb_funcall(from, cmp, 1, to))) return INT2FIX(0); result = rb_funcall(rb_funcall(to, '-', 1, from), id_div, 1, step); if (!excl || RTEST(rb_funcall(rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step)), cmp, 1, to))) { @@ -1831,47 +1855,55 @@ ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl) } } -#define NUM_STEP_SCAN_ARGS(argc, argv, to, step, hash, desc) do { \ - argc = rb_scan_args(argc, argv, "02:", &to, &step, &hash); \ - if (!NIL_P(hash)) { \ - step = rb_hash_aref(hash, sym_by); \ - to = rb_hash_aref(hash, sym_to); \ - } \ - else { \ - /* compatibility */ \ - if (argc > 1 && NIL_P(step)) { \ - rb_raise(rb_eTypeError, "step must be numeric"); \ - } \ - if (rb_equal(step, INT2FIX(0))) { \ - rb_raise(rb_eArgError, "step can't be 0"); \ - } \ - } \ - if (NIL_P(step)) { \ - step = INT2FIX(1); \ - } \ - desc = !positive_int_p(step); \ - if (NIL_P(to)) { \ - to = desc ? DBL2NUM(-INFINITY) : DBL2NUM(INFINITY); \ - } \ -} while (0) - -#define NUM_STEP_GET_INF(to, desc, inf) do { \ - if (RB_TYPE_P(to, T_FLOAT)) { \ - double f = RFLOAT_VALUE(to); \ - inf = isinf(f) && (signbit(f) ? desc : !desc); \ - } \ - else inf = 0; \ -} while (0) +static int +num_step_scan_args(int argc, const VALUE *argv, VALUE *to, VALUE *step) +{ + VALUE hash; + int desc; + + argc = rb_scan_args(argc, argv, "02:", to, step, &hash); + if (!NIL_P(hash)) { + ID keys[2]; + VALUE values[2]; + keys[0] = id_to; + keys[1] = id_by; + rb_get_kwargs(hash, keys, 0, 2, values); + if (values[0] != Qundef) { + if (argc > 0) rb_raise(rb_eArgError, "to is given twice"); + *to = values[0]; + } + if (values[1] != Qundef) { + if (argc > 1) rb_raise(rb_eArgError, "step is given twice"); + *step = values[1]; + } + } + else { + /* compatibility */ + if (argc > 1 && NIL_P(*step)) { + rb_raise(rb_eTypeError, "step must be numeric"); + } + if (rb_equal(*step, INT2FIX(0))) { + rb_raise(rb_eArgError, "step can't be 0"); + } + } + if (NIL_P(*step)) { + *step = INT2FIX(1); + } + desc = !positive_int_p(*step); + if (NIL_P(*to)) { + *to = desc ? DBL2NUM(-INFINITY) : DBL2NUM(INFINITY); + } + return desc; +} static VALUE num_step_size(VALUE from, VALUE args, VALUE eobj) { - VALUE to, step, hash; - int desc; + VALUE to, step; int argc = args ? RARRAY_LENINT(args) : 0; VALUE *argv = args ? RARRAY_PTR(args) : 0; - NUM_STEP_SCAN_ARGS(argc, argv, to, step, hash, desc); + num_step_scan_args(argc, argv, &to, &step); return ruby_num_interval_step_size(from, to, step, FALSE); } @@ -1932,14 +1964,20 @@ num_step_size(VALUE from, VALUE args, VALUE eobj) static VALUE num_step(int argc, VALUE *argv, VALUE from) { - VALUE to, step, hash; + VALUE to, step; int desc, inf; RETURN_SIZED_ENUMERATOR(from, argc, argv, num_step_size); - NUM_STEP_SCAN_ARGS(argc, argv, to, step, hash, desc); - NUM_STEP_GET_INF(to, desc, inf); - + desc = num_step_scan_args(argc, argv, &to, &step); + if (RTEST(rb_num_coerce_cmp(step, INT2FIX(0), id_eq))) { + inf = 1; + } + else if (RB_TYPE_P(to, T_FLOAT)) { + double f = RFLOAT_VALUE(to); + inf = isinf(f) && (signbit(f) ? desc : !desc); + } + else inf = 0; if (FIXNUM_P(from) && (inf || FIXNUM_P(to)) && FIXNUM_P(step)) { long i = FIX2LONG(from); @@ -3132,7 +3170,7 @@ fix_cmp(VALUE x, VALUE y) return rb_integer_float_cmp(x, y); } else { - return rb_num_coerce_cmp(x, y, rb_intern("<=>")); + return rb_num_coerce_cmp(x, y, id_cmp); } } @@ -3261,11 +3299,7 @@ bit_coerce(VALUE *x, VALUE *y, int err) if (!FIXNUM_P(*x) && !RB_TYPE_P(*x, T_BIGNUM) && !FIXNUM_P(*y) && !RB_TYPE_P(*y, T_BIGNUM)) { if (!err) return FALSE; - rb_raise(rb_eTypeError, - "%s can't be coerced into %s for bitwise arithmetic", - rb_special_const_p(*y) ? - RSTRING_PTR(rb_inspect(*y)) : rb_obj_classname(*y), - rb_obj_classname(*x)); + coerce_failed(*x, *y); } } return TRUE; @@ -3828,6 +3862,7 @@ Init_Numeric(void) id_to_i = rb_intern("to_i"); id_eq = rb_intern("=="); id_div = rb_intern("div"); + id_cmp = rb_intern("<=>"); rb_eZeroDivError = rb_define_class("ZeroDivisionError", rb_eStandardError); rb_eFloatDomainError = rb_define_class("FloatDomainError", rb_eRangeError); @@ -4064,8 +4099,8 @@ Init_Numeric(void) rb_define_method(rb_cFloat, "infinite?", flo_is_infinite_p, 0); rb_define_method(rb_cFloat, "finite?", flo_is_finite_p, 0); - sym_to = ID2SYM(rb_intern("to")); - sym_by = ID2SYM(rb_intern("by")); + id_to = rb_intern("to"); + id_by = rb_intern("by"); } #undef rb_float_value diff --git a/object.c b/object.c index bb43b4617e5cd1..34eac51a1d1b15 100644 --- a/object.c +++ b/object.c @@ -252,6 +252,33 @@ rb_obj_singleton_class(VALUE obj) return rb_singleton_class(obj); } +void +rb_obj_copy_ivar(VALUE dest, VALUE obj) +{ + if (!(RBASIC(dest)->flags & ROBJECT_EMBED) && ROBJECT_IVPTR(dest)) { + xfree(ROBJECT_IVPTR(dest)); + ROBJECT(dest)->as.heap.ivptr = 0; + ROBJECT(dest)->as.heap.numiv = 0; + ROBJECT(dest)->as.heap.iv_index_tbl = 0; + } + if (RBASIC(obj)->flags & ROBJECT_EMBED) { + MEMCPY(ROBJECT(dest)->as.ary, ROBJECT(obj)->as.ary, VALUE, ROBJECT_EMBED_LEN_MAX); + RBASIC(dest)->flags |= ROBJECT_EMBED; + } + else { + long len = ROBJECT(obj)->as.heap.numiv; + VALUE *ptr = 0; + if (len > 0) { + ptr = ALLOC_N(VALUE, len); + MEMCPY(ptr, ROBJECT(obj)->as.heap.ivptr, VALUE, len); + } + ROBJECT(dest)->as.heap.ivptr = ptr; + ROBJECT(dest)->as.heap.numiv = len; + ROBJECT(dest)->as.heap.iv_index_tbl = ROBJECT(obj)->as.heap.iv_index_tbl; + RBASIC(dest)->flags &= ~ROBJECT_EMBED; + } +} + static void init_copy(VALUE dest, VALUE obj) { @@ -264,25 +291,7 @@ init_copy(VALUE dest, VALUE obj) rb_gc_copy_finalizer(dest, obj); switch (TYPE(obj)) { case T_OBJECT: - if (!(RBASIC(dest)->flags & ROBJECT_EMBED) && ROBJECT_IVPTR(dest)) { - xfree(ROBJECT_IVPTR(dest)); - ROBJECT(dest)->as.heap.ivptr = 0; - ROBJECT(dest)->as.heap.numiv = 0; - ROBJECT(dest)->as.heap.iv_index_tbl = 0; - } - if (RBASIC(obj)->flags & ROBJECT_EMBED) { - MEMCPY(ROBJECT(dest)->as.ary, ROBJECT(obj)->as.ary, VALUE, ROBJECT_EMBED_LEN_MAX); - RBASIC(dest)->flags |= ROBJECT_EMBED; - } - else { - long len = ROBJECT(obj)->as.heap.numiv; - VALUE *ptr = ALLOC_N(VALUE, len); - MEMCPY(ptr, ROBJECT(obj)->as.heap.ivptr, VALUE, len); - ROBJECT(dest)->as.heap.ivptr = ptr; - ROBJECT(dest)->as.heap.numiv = len; - ROBJECT(dest)->as.heap.iv_index_tbl = ROBJECT(obj)->as.heap.iv_index_tbl; - RBASIC(dest)->flags &= ~ROBJECT_EMBED; - } + rb_obj_copy_ivar(dest, obj); break; case T_CLASS: case T_MODULE: @@ -584,6 +593,8 @@ class_or_module_required(VALUE c) return c; } +static VALUE class_search_ancestor(VALUE cl, VALUE c); + /* * call-seq: * obj.instance_of?(class) -> true or false @@ -644,15 +655,27 @@ rb_obj_is_kind_of(VALUE obj, VALUE c) VALUE cl = CLASS_OF(obj); c = class_or_module_required(c); - c = RCLASS_ORIGIN(c); + return class_search_ancestor(cl, RCLASS_ORIGIN(c)) ? Qtrue : Qfalse; +} + +static VALUE +class_search_ancestor(VALUE cl, VALUE c) +{ while (cl) { if (cl == c || RCLASS_M_TBL_WRAPPER(cl) == RCLASS_M_TBL_WRAPPER(c)) - return Qtrue; + return cl; cl = RCLASS_SUPER(cl); } - return Qfalse; + return 0; } +VALUE +rb_class_search_ancestor(VALUE cl, VALUE c) +{ + cl = class_or_module_required(cl); + c = class_or_module_required(c); + return class_search_ancestor(cl, RCLASS_ORIGIN(c)); +} /* * call-seq: @@ -1548,16 +1571,12 @@ rb_class_inherited_p(VALUE mod, VALUE arg) rb_raise(rb_eTypeError, "compared with non class/module"); } arg = RCLASS_ORIGIN(arg); - while (mod) { - if (RCLASS_M_TBL_WRAPPER(mod) == RCLASS_M_TBL_WRAPPER(arg)) - return Qtrue; - mod = RCLASS_SUPER(mod); + if (class_search_ancestor(mod, arg)) { + return Qtrue; } /* not mod < arg; check if mod > arg */ - while (arg) { - if (RCLASS_M_TBL_WRAPPER(arg) == RCLASS_M_TBL_WRAPPER(start)) - return Qfalse; - arg = RCLASS_SUPER(arg); + if (class_search_ancestor(arg, start)) { + return Qfalse; } return Qnil; } diff --git a/pack.c b/pack.c index 71dd6afcb314bd..400e85c8ccfc26 100644 --- a/pack.c +++ b/pack.c @@ -946,7 +946,8 @@ static const char b64_table[] = static void encodes(VALUE str, const char *s, long len, int type, int tail_lf) { - char buff[4096]; + enum {buff_size = 4096, encoded_unit = 4}; + char buff[buff_size + 1]; /* +1 for tail_lf */ long i = 0; const char *trans = type == 'u' ? uu_table : b64_table; char padding; @@ -959,7 +960,7 @@ encodes(VALUE str, const char *s, long len, int type, int tail_lf) padding = '='; } while (len >= 3) { - while (len >= 3 && sizeof(buff)-i >= 4) { + while (len >= 3 && buff_size-i >= encoded_unit) { buff[i++] = trans[077 & (*s >> 2)]; buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))]; @@ -967,7 +968,7 @@ encodes(VALUE str, const char *s, long len, int type, int tail_lf) s += 3; len -= 3; } - if (sizeof(buff)-i < 4) { + if (buff_size-i < encoded_unit) { rb_str_buf_cat(str, buff, i); i = 0; } @@ -987,6 +988,7 @@ encodes(VALUE str, const char *s, long len, int type, int tail_lf) } if (tail_lf) buff[i++] = '\n'; rb_str_buf_cat(str, buff, i); + if ((size_t)i > sizeof(buff)) rb_bug("encodes() buffer overrun"); } static const char hex_table[] = "0123456789ABCDEF"; diff --git a/parse.y b/parse.y index 25946dccda974f..37e3cbdcd6e5da 100644 --- a/parse.y +++ b/parse.y @@ -74,6 +74,7 @@ enum lex_state_bits { EXPR_DOT_bit, /* right after `.' or `::', no reserved words. */ EXPR_CLASS_bit, /* immediate after `class', no here document. */ EXPR_VALUE_bit, /* alike EXPR_BEG but label is disallowed. */ + EXPR_LABELARG_bit, /* ignore significant, +/- is a sign. */ EXPR_MAX_STATE }; /* examine combinations */ @@ -90,7 +91,8 @@ enum lex_state_e { DEF_EXPR(DOT), DEF_EXPR(CLASS), DEF_EXPR(VALUE), - EXPR_BEG_ANY = (EXPR_BEG | EXPR_VALUE | EXPR_MID | EXPR_CLASS), + DEF_EXPR(LABELARG), + EXPR_BEG_ANY = (EXPR_BEG | EXPR_VALUE | EXPR_MID | EXPR_CLASS | EXPR_LABELARG), EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG), EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN) }; @@ -244,6 +246,7 @@ struct parser_params { int parser_brace_nest; int parser_compile_for_eval; VALUE parser_cur_mid; + int parser_in_kwarg; int parser_in_defined; char *parser_tokenbuf; int parser_tokidx; @@ -2612,12 +2615,18 @@ primary : literal $$ = dispatch1(paren, 0); %*/ } - | tLPAREN_ARG expr {lex_state = EXPR_ENDARG;} rparen + | tLPAREN_ARG { + $1 = cmdarg_stack; + cmdarg_stack = 0; + } + expr {lex_state = EXPR_ENDARG;} rparen + { + cmdarg_stack = $1; /*%%%*/ - $$ = $2; + $$ = $3; /*% - $$ = dispatch1(paren, $2); + $$ = dispatch1(paren, $3); %*/ } | tLPAREN compstmt ')' @@ -4403,9 +4412,14 @@ f_arglist : '(' f_args rparen lex_state = EXPR_BEG; command_start = TRUE; } - | f_args term + | { + $$ = parser->parser_in_kwarg; + parser->parser_in_kwarg = 1; + } + f_args term { - $$ = $1; + parser->parser_in_kwarg = $1; + $$ = $2; lex_state = EXPR_BEG; command_start = TRUE; } @@ -5255,7 +5269,7 @@ parser_yyerror(struct parser_params *parser, const char *msg) buf = ALLOCA_N(char, len+2); MEMCPY(buf, p, char, len); buf[len] = '\0'; - rb_compile_error_append("%s%s%s", pre, buf, post); + rb_compile_error_with_enc(NULL, 0, (void *)current_enc, "%s%s%s", pre, buf, post); i = (int)(lex_p - p); p2 = buf; pe = buf + len; @@ -7006,13 +7020,16 @@ parser_yylex(struct parser_params *parser) #endif /* fall through */ case '\n': - if (IS_lex_state(EXPR_BEG | EXPR_VALUE | EXPR_CLASS | EXPR_FNAME | EXPR_DOT)) { + if (IS_lex_state(EXPR_BEG | EXPR_VALUE | EXPR_CLASS | EXPR_FNAME | EXPR_DOT | EXPR_LABELARG)) { #ifdef RIPPER if (!fallthru) { ripper_dispatch_scan_event(parser, tIGNORED_NL); } fallthru = FALSE; #endif + if (IS_lex_state(EXPR_LABELARG) && parser->parser_in_kwarg) { + goto normal_newline; + } goto retry; } while ((c = nextc())) { @@ -8073,7 +8090,7 @@ parser_yylex(struct parser_params *parser) default: if (!parser_is_identchar()) { - rb_compile_error(PARSER_ARG "Invalid char `\\x%02X' in expression", c); + compile_error(PARSER_ARG "Invalid char `\\x%02X' in expression", c); goto retry; } @@ -8144,7 +8161,7 @@ parser_yylex(struct parser_params *parser) if (IS_LABEL_POSSIBLE()) { if (IS_LABEL_SUFFIX(0)) { - lex_state = EXPR_BEG; + lex_state = EXPR_LABELARG; nextc(); set_yylval_name(TOK_INTERN(!ENC_SINGLE(mb))); return tLABEL; @@ -8178,7 +8195,7 @@ parser_yylex(struct parser_params *parser) return keyword_do_block; return keyword_do; } - if (IS_lex_state_for(state, (EXPR_BEG | EXPR_VALUE))) + if (IS_lex_state_for(state, (EXPR_BEG | EXPR_VALUE | EXPR_LABELARG))) return kw->id[0]; else { if (kw->id[0] != kw->id[1]) @@ -8734,10 +8751,10 @@ is_private_local_id(ID name) #define LVAR_USED ((ID)1 << (sizeof(ID) * CHAR_BIT - 1)) -static ID -shadowing_lvar_gen(struct parser_params *parser, ID name) +static int +shadowing_lvar_0(struct parser_params *parser, ID name) { - if (is_private_local_id(name)) return name; + if (is_private_local_id(name)) return 1; if (dyna_in_block()) { if (dvar_curr(name)) { yyerror("duplicated argument name"); @@ -8748,6 +8765,7 @@ shadowing_lvar_gen(struct parser_params *parser, ID name) if (lvtbl->used) { vtable_add(lvtbl->used, (ID)ruby_sourceline | LVAR_USED); } + return 0; } } else { @@ -8755,6 +8773,13 @@ shadowing_lvar_gen(struct parser_params *parser, ID name) yyerror("duplicated argument name"); } } + return 1; +} + +static ID +shadowing_lvar_gen(struct parser_params *parser, ID name) +{ + shadowing_lvar_0(parser, name); return name; } @@ -8767,7 +8792,7 @@ new_bv_gen(struct parser_params *parser, ID name) rb_id2name(name)); return; } - shadowing_lvar(name); + if (!shadowing_lvar_0(parser, name)) return; dyna_var(name); } @@ -9669,31 +9694,26 @@ local_pop_gen(struct parser_params *parser) } #ifndef RIPPER -static ID* -vtable_tblcpy(ID *buf, const struct vtable *src) -{ - int i, cnt = vtable_size(src); - - if (cnt > 0) { - buf[0] = cnt; - for (i = 0; i < cnt; i++) { - buf[i] = src->tbl[i]; - } - return buf; - } - return 0; -} - static ID* local_tbl_gen(struct parser_params *parser) { - int cnt = vtable_size(lvtbl->args) + vtable_size(lvtbl->vars); + int cnt_args = vtable_size(lvtbl->args); + int cnt_vars = vtable_size(lvtbl->vars); + int cnt = cnt_args + cnt_vars; + int i, j; ID *buf; if (cnt <= 0) return 0; buf = ALLOC_N(ID, cnt + 1); - vtable_tblcpy(buf+1, lvtbl->args); - vtable_tblcpy(buf+vtable_size(lvtbl->args)+1, lvtbl->vars); + MEMCPY(buf+1, lvtbl->args->tbl, ID, cnt_args); + /* remove IDs duplicated to warn shadowing */ + for (i = 0, j = cnt_args+1; i < cnt_vars; ++i) { + ID id = lvtbl->vars->tbl[i]; + if (!vtable_included(lvtbl->args, id)) { + buf[j++] = id; + } + } + if (--j < cnt) REALLOC_N(buf, ID, (cnt = j) + 1); buf[0] = cnt; return buf; } @@ -10383,7 +10403,7 @@ static VALUE setup_fake_str(struct RString *fake_str, const char *name, long len) { fake_str->basic.flags = T_STRING|RSTRING_NOEMBED; - RBASIC_SET_CLASS((VALUE)fake_str, rb_cString); + RBASIC_SET_CLASS_RAW((VALUE)fake_str, rb_cString); fake_str->as.heap.len = len; fake_str->as.heap.ptr = (char *)name; fake_str->as.heap.aux.capa = len; @@ -10840,6 +10860,7 @@ parser_initialize(struct parser_params *parser) parser->parser_in_single = 0; parser->parser_in_def = 0; parser->parser_in_defined = 0; + parser->parser_in_kwarg = 0; parser->parser_compile_for_eval = 0; parser->parser_cur_mid = 0; parser->parser_tokenbuf = NULL; diff --git a/proc.c b/proc.c index e3cecb7bbe898a..cc4e71080c3e5b 100644 --- a/proc.c +++ b/proc.c @@ -1826,6 +1826,7 @@ rb_method_call_with_block(int argc, VALUE *argv, VALUE method, VALUE pass_procva if ((state = EXEC_TAG()) == 0) { rb_thread_t *th = GET_THREAD(); rb_block_t *block = 0; + VALUE defined_class; if (!NIL_P(pass_procval)) { rb_proc_t *pass_proc; @@ -1834,7 +1835,9 @@ rb_method_call_with_block(int argc, VALUE *argv, VALUE method, VALUE pass_procva } th->passed_block = block; - result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me, data->defined_class); + defined_class = data->defined_class; + if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass; + result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me, defined_class); } POP_TAG(); if (safe >= 0) @@ -1940,6 +1943,7 @@ umethod_bind(VALUE method, VALUE recv) { struct METHOD *data, *bound; VALUE methclass; + VALUE rclass; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); @@ -1961,8 +1965,18 @@ umethod_bind(VALUE method, VALUE recv) bound->me = ALLOC(rb_method_entry_t); *bound->me = *data->me; if (bound->me->def) bound->me->def->alias_count++; + rclass = CLASS_OF(recv); + if (BUILTIN_TYPE(bound->defined_class) == T_MODULE) { + VALUE ic = rb_class_search_ancestor(rclass, bound->defined_class); + if (ic) { + rclass = ic; + } + else { + rclass = rb_include_class_new(methclass, rclass); + } + } bound->recv = recv; - bound->rclass = CLASS_OF(recv); + bound->rclass = rclass; data->ume = ALLOC(struct unlinked_method_entry_list_entry); return method; diff --git a/process.c b/process.c index e50a047c8634da..f1679a0abdabf3 100644 --- a/process.c +++ b/process.c @@ -86,6 +86,12 @@ # include #endif +/* define system APIs */ +#ifdef _WIN32 +#undef open +#define open rb_w32_uopen +#endif + #if defined(HAVE_TIMES) || defined(_WIN32) static VALUE rb_cProcessTms; #endif @@ -151,20 +157,36 @@ static void check_gid_switch(void); #if defined(HAVE_PWD_H) # if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX) # define USE_GETPWNAM_R 1 +# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX) +# define GETPW_R_SIZE_DEFAULT 0x1000 +# define GETPW_R_SIZE_LIMIT 0x10000 # endif # ifdef USE_GETPWNAM_R # define PREPARE_GETPWNAM \ - long getpw_buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); \ - char *getpw_buf = ALLOCA_N(char, (getpw_buf_len < 0 ? (getpw_buf_len = 4096) : getpw_buf_len)); -# define OBJ2UID(id) obj2uid((id), getpw_buf, getpw_buf_len) -static rb_uid_t obj2uid(VALUE id, char *getpw_buf, size_t getpw_buf_len); + VALUE getpw_buf = 0 +# define FINISH_GETPWNAM \ + ALLOCV_END(getpw_buf) +# define OBJ2UID1(id) obj2uid((id), &getpw_buf) +# define OBJ2UID(id) obj2uid0(id) +static rb_uid_t obj2uid(VALUE id, VALUE *getpw_buf); +static inline rb_uid_t +obj2uid0(VALUE id) +{ + rb_uid_t uid; + PREPARE_GETPWNAM; + uid = OBJ2UID1(id); + FINISH_GETPWNAM; + return uid; +} # else # define PREPARE_GETPWNAM /* do nothing */ +# define FINISH_GETPWNAM /* do nothing */ # define OBJ2UID(id) obj2uid((id)) static rb_uid_t obj2uid(VALUE id); # endif #else # define PREPARE_GETPWNAM /* do nothing */ +# define FINISH_GETPWNAM /* do nothing */ # define OBJ2UID(id) NUM2UIDT(id) # ifdef p_uid_from_name # undef p_uid_from_name @@ -175,20 +197,37 @@ static rb_uid_t obj2uid(VALUE id); #if defined(HAVE_GRP_H) # if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX) # define USE_GETGRNAM_R +# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX) +# define GETGR_R_SIZE_DEFAULT 0x1000 +# define GETGR_R_SIZE_LIMIT 0x10000 # endif # ifdef USE_GETGRNAM_R # define PREPARE_GETGRNAM \ - long getgr_buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); \ - char *getgr_buf = ALLOCA_N(char, (getgr_buf_len < 0 ? (getgr_buf_len = 4096) : getgr_buf_len)); -# define OBJ2GID(id) obj2gid((id), getgr_buf, getgr_buf_len) -static rb_gid_t obj2gid(VALUE id, char *getgr_buf, size_t getgr_buf_len); + VALUE getgr_buf = 0 +# define FINISH_GETGRNAM \ + ALLOCV_END(getgr_buf) +# define OBJ2GID1(id) obj2gid((id), &getgr_buf) +# define OBJ2GID(id) obj2gid0(id) +static rb_gid_t obj2gid(VALUE id, VALUE *getgr_buf); +static inline rb_gid_t +obj2gid0(VALUE id) +{ + rb_gid_t gid; + PREPARE_GETGRNAM; + gid = OBJ2GID1(id); + FINISH_GETGRNAM; + return gid; +} +static rb_gid_t obj2gid(VALUE id, VALUE *getgr_buf); # else # define PREPARE_GETGRNAM /* do nothing */ +# define FINISH_GETGRNAM /* do nothing */ # define OBJ2GID(id) obj2gid((id)) static rb_gid_t obj2gid(VALUE id); # endif #else # define PREPARE_GETGRNAM /* do nothing */ +# define FINISH_GETGRNAM /* do nothing */ # define OBJ2GID(id) NUM2GIDT(id) # ifdef p_gid_from_name # undef p_gid_from_name @@ -1751,7 +1790,6 @@ rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val) } check_uid_switch(); { - PREPARE_GETPWNAM; eargp->uid = OBJ2UID(val); eargp->uid_given = 1; } @@ -1767,7 +1805,6 @@ rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val) } check_gid_switch(); { - PREPARE_GETGRNAM; eargp->gid = OBJ2GID(val); eargp->gid_given = 1; } @@ -4821,7 +4858,7 @@ check_gid_switch(void) static rb_uid_t obj2uid(VALUE id # ifdef USE_GETPWNAM_R - , char *getpw_buf, size_t getpw_buf_len + , VALUE *getpw_tmp # endif ) { @@ -4836,8 +4873,28 @@ obj2uid(VALUE id struct passwd *pwptr; #ifdef USE_GETPWNAM_R struct passwd pwbuf; - if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) - rb_sys_fail("getpwnam_r"); + char *getpw_buf; + long getpw_buf_len; + if (!*getpw_tmp) { + getpw_buf_len = GETPW_R_SIZE_INIT; + if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT; + getpw_buf = rb_alloc_tmp_buffer(getpw_tmp, getpw_buf_len); + } + else { + getpw_buf = RSTRING_PTR(*getpw_tmp); + getpw_buf_len = rb_str_capacity(*getpw_tmp); + } + errno = ERANGE; + /* gepwnam_r() on MacOS X doesn't set errno if buffer size is insufficient */ + while (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) { + if (errno != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) { + rb_free_tmp_buffer(getpw_tmp); + rb_sys_fail("getpwnam_r"); + } + rb_str_modify_expand(*getpw_tmp, getpw_buf_len); + getpw_buf = RSTRING_PTR(*getpw_tmp); + getpw_buf_len = rb_str_capacity(*getpw_tmp); + } #else pwptr = getpwnam(usrname); #endif @@ -4870,7 +4927,6 @@ obj2uid(VALUE id static VALUE p_uid_from_name(VALUE self, VALUE id) { - PREPARE_GETPWNAM return UIDT2NUM(OBJ2UID(id)); } # endif @@ -4880,7 +4936,7 @@ p_uid_from_name(VALUE self, VALUE id) static rb_gid_t obj2gid(VALUE id # ifdef USE_GETGRNAM_R - , char *getgr_buf, size_t getgr_buf_len + , VALUE *getgr_tmp # endif ) { @@ -4895,8 +4951,28 @@ obj2gid(VALUE id struct group *grptr; #ifdef USE_GETGRNAM_R struct group grbuf; - if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) - rb_sys_fail("getgrnam_r"); + char *getgr_buf; + long getgr_buf_len; + if (!*getgr_tmp) { + getgr_buf_len = GETGR_R_SIZE_INIT; + if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT; + getgr_buf = rb_alloc_tmp_buffer(getgr_tmp, getgr_buf_len); + } + else { + getgr_buf = RSTRING_PTR(*getgr_tmp); + getgr_buf_len = rb_str_capacity(*getgr_tmp); + } + errno = ERANGE; + /* gegrnam_r() on MacOS X doesn't set errno if buffer size is insufficient */ + while (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) { + if (errno != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) { + rb_free_tmp_buffer(getgr_tmp); + rb_sys_fail("getgrnam_r"); + } + rb_str_modify_expand(*getgr_tmp, getgr_buf_len); + getgr_buf = RSTRING_PTR(*getgr_tmp); + getgr_buf_len = rb_str_capacity(*getgr_tmp); + } #else grptr = getgrnam(grpname); #endif @@ -4929,7 +5005,6 @@ obj2gid(VALUE id static VALUE p_gid_from_name(VALUE self, VALUE id) { - PREPARE_GETGRNAM; return GIDT2NUM(OBJ2GID(id)); } # endif @@ -4948,7 +5023,6 @@ p_gid_from_name(VALUE self, VALUE id) static VALUE p_sys_setuid(VALUE obj, VALUE id) { - PREPARE_GETPWNAM; check_uid_switch(); if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0); return Qnil; @@ -4971,7 +5045,6 @@ p_sys_setuid(VALUE obj, VALUE id) static VALUE p_sys_setruid(VALUE obj, VALUE id) { - PREPARE_GETPWNAM; check_uid_switch(); if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0); return Qnil; @@ -4994,7 +5067,6 @@ p_sys_setruid(VALUE obj, VALUE id) static VALUE p_sys_seteuid(VALUE obj, VALUE id) { - PREPARE_GETPWNAM; check_uid_switch(); if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0); return Qnil; @@ -5019,9 +5091,13 @@ p_sys_seteuid(VALUE obj, VALUE id) static VALUE p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid) { + rb_uid_t ruid, euid; PREPARE_GETPWNAM; check_uid_switch(); - if (setreuid(OBJ2UID(rid), OBJ2UID(eid)) != 0) rb_sys_fail(0); + ruid = OBJ2UID1(rid); + euid = OBJ2UID1(eid); + FINISH_GETPWNAM; + if (setreuid(ruid, euid) != 0) rb_sys_fail(0); return Qnil; } #else @@ -5044,9 +5120,14 @@ p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid) static VALUE p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid) { + rb_uid_t ruid, euid, suid; PREPARE_GETPWNAM; check_uid_switch(); - if (setresuid(OBJ2UID(rid), OBJ2UID(eid), OBJ2UID(sid)) != 0) rb_sys_fail(0); + ruid = OBJ2UID1(rid); + euid = OBJ2UID1(eid); + suid = OBJ2UID1(sid); + FINISH_GETPWNAM; + if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0); return Qnil; } #else @@ -5086,7 +5167,6 @@ static VALUE proc_setuid(VALUE obj, VALUE id) { rb_uid_t uid; - PREPARE_GETPWNAM; check_uid_switch(); @@ -5158,7 +5238,6 @@ static VALUE p_uid_change_privilege(VALUE obj, VALUE id) { rb_uid_t uid; - PREPARE_GETPWNAM; check_uid_switch(); @@ -5328,7 +5407,6 @@ p_uid_change_privilege(VALUE obj, VALUE id) static VALUE p_sys_setgid(VALUE obj, VALUE id) { - PREPARE_GETGRNAM; check_gid_switch(); if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0); return Qnil; @@ -5351,7 +5429,6 @@ p_sys_setgid(VALUE obj, VALUE id) static VALUE p_sys_setrgid(VALUE obj, VALUE id) { - PREPARE_GETGRNAM; check_gid_switch(); if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0); return Qnil; @@ -5374,7 +5451,6 @@ p_sys_setrgid(VALUE obj, VALUE id) static VALUE p_sys_setegid(VALUE obj, VALUE id) { - PREPARE_GETGRNAM; check_gid_switch(); if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0); return Qnil; @@ -5399,9 +5475,13 @@ p_sys_setegid(VALUE obj, VALUE id) static VALUE p_sys_setregid(VALUE obj, VALUE rid, VALUE eid) { + rb_gid_t rgid, egid; PREPARE_GETGRNAM; check_gid_switch(); - if (setregid(OBJ2GID(rid), OBJ2GID(eid)) != 0) rb_sys_fail(0); + rgid = OBJ2GID(rid); + egid = OBJ2GID(eid); + FINISH_GETGRNAM; + if (setregid(rgid, egid) != 0) rb_sys_fail(0); return Qnil; } #else @@ -5423,9 +5503,14 @@ p_sys_setregid(VALUE obj, VALUE rid, VALUE eid) static VALUE p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid) { + rb_gid_t rgid, egid, sgid; PREPARE_GETGRNAM; check_gid_switch(); - if (setresgid(OBJ2GID(rid), OBJ2GID(eid), OBJ2GID(sid)) != 0) rb_sys_fail(0); + rgid = OBJ2GID(rid); + egid = OBJ2GID(eid); + sgid = OBJ2GID(sid); + FINISH_GETGRNAM; + if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0); return Qnil; } #else @@ -5493,7 +5578,6 @@ static VALUE proc_setgid(VALUE obj, VALUE id) { rb_gid_t gid; - PREPARE_GETGRNAM; check_gid_switch(); @@ -5584,7 +5668,7 @@ maxgroups(void) static VALUE proc_getgroups(VALUE obj) { - VALUE ary; + VALUE ary, tmp; int i, ngroups; rb_gid_t *groups; @@ -5592,7 +5676,7 @@ proc_getgroups(VALUE obj) if (ngroups == -1) rb_sys_fail(0); - groups = ALLOCA_N(rb_gid_t, ngroups); + groups = ALLOCV_N(rb_gid_t, tmp, ngroups); ngroups = getgroups(ngroups, groups); if (ngroups == -1) @@ -5602,6 +5686,8 @@ proc_getgroups(VALUE obj) for (i = 0; i < ngroups; i++) rb_ary_push(ary, GIDT2NUM(groups[i])); + ALLOCV_END(tmp); + return ary; } #else @@ -5628,6 +5714,7 @@ proc_setgroups(VALUE obj, VALUE ary) { int ngroups, i; rb_gid_t *groups; + VALUE tmp; PREPARE_GETGRNAM; Check_Type(ary, T_ARRAY); @@ -5636,17 +5723,20 @@ proc_setgroups(VALUE obj, VALUE ary) if (ngroups > maxgroups()) rb_raise(rb_eArgError, "too many groups, %d max", maxgroups()); - groups = ALLOCA_N(rb_gid_t, ngroups); + groups = ALLOCV_N(rb_gid_t, tmp, ngroups); for (i = 0; i < ngroups; i++) { VALUE g = RARRAY_AREF(ary, i); - groups[i] = OBJ2GID(g); + groups[i] = OBJ2GID1(g); } + FINISH_GETGRNAM; if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */ rb_sys_fail(0); + ALLOCV_END(tmp); + return proc_getgroups(obj); } #else @@ -5675,7 +5765,6 @@ proc_setgroups(VALUE obj, VALUE ary) static VALUE proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp) { - PREPARE_GETGRNAM; if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) { rb_sys_fail(0); } @@ -5857,7 +5946,6 @@ static VALUE p_gid_change_privilege(VALUE obj, VALUE id) { rb_gid_t gid; - PREPARE_GETGRNAM; check_gid_switch(); @@ -6067,7 +6155,6 @@ proc_seteuid(rb_uid_t uid) static VALUE proc_seteuid_m(VALUE mod, VALUE euid) { - PREPARE_GETPWNAM; check_uid_switch(); proc_seteuid(OBJ2UID(euid)); return euid; @@ -6133,7 +6220,6 @@ rb_seteuid_core(rb_uid_t euid) static VALUE p_uid_grant_privilege(VALUE obj, VALUE id) { - PREPARE_GETPWNAM; rb_seteuid_core(OBJ2UID(id)); return id; } @@ -6173,7 +6259,6 @@ proc_setegid(VALUE obj, VALUE egid) { #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) rb_gid_t gid; - PREPARE_GETGRNAM; #endif check_gid_switch(); @@ -6265,7 +6350,6 @@ rb_setegid_core(rb_gid_t egid) static VALUE p_gid_grant_privilege(VALUE obj, VALUE id) { - PREPARE_GETGRNAM; rb_setegid_core(OBJ2GID(id)); return id; } diff --git a/range.c b/range.c index d2d9a707c07fed..3ca9c2feda4e78 100644 --- a/range.c +++ b/range.c @@ -31,13 +31,6 @@ static ID id_cmp, id_succ, id_beg, id_end, id_excl, id_integer_p, id_div; #define RBOOL(v) ((v) ? Qtrue : Qfalse) #define EXCL(r) RTEST(RANGE_EXCL(r)) -static inline VALUE -SET_EXCL(VALUE r, VALUE v) -{ - v = RBOOL(RTEST(v)); - RANGE_SET_EXCL(r, v); - return v; -} static VALUE range_failed(void) diff --git a/rational.c b/rational.c index 53bc11c4efcf6a..7bc72063768d51 100644 --- a/rational.c +++ b/rational.c @@ -31,7 +31,7 @@ VALUE rb_cRational; static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv, - id_floor, id_idiv, id_integer_p, id_negate, id_to_f, + id_idiv, id_integer_p, id_negate, id_to_f, id_to_i, id_truncate, id_i_num, id_i_den; #define f_boolcast(x) ((x) ? Qtrue : Qfalse) @@ -91,14 +91,6 @@ f_div(VALUE x, VALUE y) return rb_funcall(x, '/', 1, y); } -inline static VALUE -f_gt_p(VALUE x, VALUE y) -{ - if (FIXNUM_P(x) && FIXNUM_P(y)) - return f_boolcast(FIX2LONG(x) > FIX2LONG(y)); - return rb_funcall(x, '>', 1, y); -} - inline static VALUE f_lt_p(VALUE x, VALUE y) { @@ -142,7 +134,6 @@ f_sub(VALUE x, VALUE y) } fun1(abs) -fun1(floor) fun1(integer_p) fun1(negate) @@ -161,8 +152,6 @@ f_to_f(VALUE x) return rb_funcall(x, id_to_f, 0); } -fun1(truncate) - inline static VALUE f_eqeq_p(VALUE x, VALUE y) { @@ -474,14 +463,6 @@ f_rational_new_bang1(VALUE klass, VALUE x) return nurat_s_new_internal(klass, x, ONE); } -inline static VALUE -f_rational_new_bang2(VALUE klass, VALUE x, VALUE y) -{ - assert(f_positive_p(y)); - assert(f_nonzero_p(y)); - return nurat_s_new_internal(klass, x, y); -} - #ifdef CANONICALIZATION_FOR_MATHN #define CANON #endif @@ -579,13 +560,6 @@ nurat_s_new(int argc, VALUE *argv, VALUE klass) return nurat_s_canonicalize_internal(klass, num, den); } -inline static VALUE -f_rational_new1(VALUE klass, VALUE x) -{ - assert(!k_rational_p(x)); - return nurat_s_canonicalize_internal(klass, x, ONE); -} - inline static VALUE f_rational_new2(VALUE klass, VALUE x, VALUE y) { @@ -594,13 +568,6 @@ f_rational_new2(VALUE klass, VALUE x, VALUE y) return nurat_s_canonicalize_internal(klass, x, y); } -inline static VALUE -f_rational_new_no_reduce1(VALUE klass, VALUE x) -{ - assert(!k_rational_p(x)); - return nurat_s_canonicalize_internal_no_reduce(klass, x, ONE); -} - inline static VALUE f_rational_new_no_reduce2(VALUE klass, VALUE x, VALUE y) { @@ -2167,13 +2134,14 @@ read_digits(const char **s, int strict, { char *b, *bb; int us = 1, ret = 1; + VALUE tmp; if (!isdecimal(**s)) { *num = ZERO; return 0; } - bb = b = ALLOCA_N(char, strlen(*s) + 1); + bb = b = ALLOCV_N(char, tmp, strlen(*s) + 1); while (isdecimal(**s) || **s == '_') { if (**s == '_') { @@ -2200,6 +2168,7 @@ read_digits(const char **s, int strict, conv: *b = '\0'; *num = rb_cstr_to_inum(bb, 10, 0); + ALLOCV_END(tmp); return ret; } @@ -2530,7 +2499,6 @@ Init_Rational(void) id_eqeq_p = rb_intern("=="); id_expt = rb_intern("**"); id_fdiv = rb_intern("fdiv"); - id_floor = rb_intern("floor"); id_idiv = rb_intern("div"); id_integer_p = rb_intern("integer?"); id_negate = rb_intern("-@"); diff --git a/re.c b/re.c index 98fbda211fa758..e9fd7acf634b3f 100644 --- a/re.c +++ b/re.c @@ -1698,20 +1698,16 @@ match_captures(VALUE match) static int name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name, const char* name_end) { - int num; - - num = onig_name_to_backref_number(RREGEXP(regexp)->ptr, + return onig_name_to_backref_number(RREGEXP(regexp)->ptr, (const unsigned char* )name, (const unsigned char* )name_end, regs); - if (num >= 1) { - return num; - } - else { - VALUE s = rb_str_new(name, (long )(name_end - name)); - rb_raise(rb_eIndexError, "undefined group name reference: %s", - StringValuePtr(s)); - } +} - UNREACHABLE; +NORETURN(static void name_to_backref_error(VALUE name)); +static void +name_to_backref_error(VALUE name) +{ + rb_raise(rb_eIndexError, "undefined group name reference: % "PRIsVALUE, + name); } /* @@ -1761,17 +1757,16 @@ match_aref(int argc, VALUE *argv, VALUE match) switch (TYPE(idx)) { case T_SYMBOL: - p = rb_id2name(SYM2ID(idx)); - goto name_to_backref; - break; + idx = rb_id2str(SYM2ID(idx)); + /* fall through */ case T_STRING: p = StringValuePtr(idx); - - name_to_backref: - num = name_to_backref_number(RMATCH_REGS(match), - RMATCH(match)->regexp, p, p + strlen(p)); + if (!rb_enc_compatible(RREGEXP(RMATCH(match)->regexp)->src, idx) || + (num = name_to_backref_number(RMATCH_REGS(match), RMATCH(match)->regexp, + p, p + RSTRING_LEN(idx))) < 1) { + name_to_backref_error(idx); + } return rb_reg_nth_match(num, match); - break; default: break; @@ -3380,7 +3375,12 @@ rb_reg_regsub(VALUE str, VALUE src, struct re_registers *regs, VALUE regexp) name_end += c == -1 ? mbclen(name_end, e, str_enc) : clen; } if (name_end < e) { - no = name_to_backref_number(regs, regexp, name, name_end); + VALUE n = rb_str_subseq(str, (long)(name - RSTRING_PTR(str)), + (long)(name_end - name)); + if (!rb_enc_compatible(RREGEXP(regexp)->src, n) || + (no = name_to_backref_number(regs, regexp, name, name_end)) < 1) { + name_to_backref_error(n); + } p = s = name_end + clen; break; } diff --git a/regerror.c b/regerror.c index 9c94d230180ad2..d32b50d12b62c1 100644 --- a/regerror.c +++ b/regerror.c @@ -133,6 +133,8 @@ onig_error_code_to_format(OnigPosition code) p = "too short multibyte code string"; break; case ONIGERR_TOO_BIG_BACKREF_NUMBER: p = "too big backref number"; break; + case ONIGERR_TOO_MANY_CAPTURE_GROUPS: + p = "too many capture groups are specified"; break; case ONIGERR_INVALID_BACKREF: #ifdef USE_NAMED_GROUP p = "invalid backref number/name"; break; diff --git a/regexec.c b/regexec.c index 997849695e5ab5..973d3eac0004e6 100644 --- a/regexec.c +++ b/regexec.c @@ -444,9 +444,26 @@ onig_region_copy(OnigRegion* to, OnigRegion* from) -#define STACK_INIT(alloc_addr, ptr_num, stack_num) do {\ - if (msa->stack_p) {\ +#define MAX_PTR_NUM 100 + +#define STACK_INIT(alloc_addr, heap_addr, ptr_num, stack_num) do {\ + if (ptr_num > MAX_PTR_NUM) {\ + alloc_addr = (char* )xmalloc(sizeof(OnigStackIndex) * (ptr_num));\ + heap_addr = alloc_addr;\ + if (msa->stack_p) {\ + stk_alloc = (OnigStackType* )(msa->stack_p);\ + stk_base = stk_alloc;\ + stk = stk_base;\ + stk_end = stk_base + msa->stack_n;\ + } else {\ + stk_alloc = (OnigStackType* )xalloca(sizeof(OnigStackType) * (stack_num));\ + stk_base = stk_alloc;\ + stk = stk_base;\ + stk_end = stk_base + (stack_num);\ + }\ + } else if (msa->stack_p) {\ alloc_addr = (char* )xalloca(sizeof(OnigStackIndex) * (ptr_num));\ + heap_addr = NULL;\ stk_alloc = (OnigStackType* )(msa->stack_p);\ stk_base = stk_alloc;\ stk = stk_base;\ @@ -455,6 +472,7 @@ onig_region_copy(OnigRegion* to, OnigRegion* from) else {\ alloc_addr = (char* )xalloca(sizeof(OnigStackIndex) * (ptr_num)\ + sizeof(OnigStackType) * (stack_num));\ + heap_addr = NULL;\ stk_alloc = (OnigStackType* )(alloc_addr + sizeof(OnigStackIndex) * (ptr_num));\ stk_base = stk_alloc;\ stk = stk_base;\ @@ -529,7 +547,11 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end, #define STACK_ENSURE(n) do {\ if (stk_end - stk < (n)) {\ int r = stack_double(&stk_base, &stk_end, &stk, stk_alloc, msa);\ - if (r != 0) { STACK_SAVE; return r; } \ + if (r != 0) {\ + STACK_SAVE;\ + if (xmalloc_base) xfree(xmalloc_base);\ + return r;\ + }\ }\ } while(0) @@ -1325,6 +1347,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, UChar *p = reg->p; UChar *pkeep; char *alloca_base; + char *xmalloc_base = NULL; OnigStackType *stk_alloc, *stk_base, *stk, *stk_end; OnigStackType *stkp; /* used as any purpose. */ OnigStackIndex si; @@ -1340,7 +1363,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, /* Stack #0 is used to store the pattern itself and used for (?R), \g<0>, etc. */ n = reg->num_repeat + (reg->num_mem + 1) * 2; - STACK_INIT(alloca_base, n, INIT_MATCH_STACK_SIZE); + STACK_INIT(alloca_base, xmalloc_base, n, INIT_MATCH_STACK_SIZE); pop_level = reg->stack_pop_level; num_mem = reg->num_mem; repeat_stk = (OnigStackIndex* )alloca_base; @@ -1354,7 +1377,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, /* Stack #0 not is used. */ n = reg->num_repeat + reg->num_mem * 2; - STACK_INIT(alloca_base, n, INIT_MATCH_STACK_SIZE); + STACK_INIT(alloca_base, xmalloc_base, n, INIT_MATCH_STACK_SIZE); pop_level = reg->stack_pop_level; num_mem = reg->num_mem; repeat_stk = (OnigStackIndex* )alloca_base; @@ -2916,20 +2939,24 @@ match_at(regex_t* reg, const UChar* str, const UChar* end, finish: STACK_SAVE; + if (xmalloc_base) xfree(xmalloc_base); return best_len; #ifdef ONIG_DEBUG stack_error: STACK_SAVE; + if (xmalloc_base) xfree(xmalloc_base); return ONIGERR_STACK_BUG; #endif bytecode_error: STACK_SAVE; + if (xmalloc_base) xfree(xmalloc_base); return ONIGERR_UNDEFINED_BYTECODE; unexpected_bytecode_error: STACK_SAVE; + if (xmalloc_base) xfree(xmalloc_base); return ONIGERR_UNEXPECTED_BYTECODE; } diff --git a/regparse.c b/regparse.c index 774ee0a9601853..ecf39ad1cf3faf 100644 --- a/regparse.c +++ b/regparse.c @@ -978,6 +978,8 @@ scan_env_add_mem_entry(ScanEnv* env) Node** p; need = env->num_mem + 1; + if (need > ONIG_MAX_CAPTURE_GROUP_NUM) + return ONIGERR_TOO_MANY_CAPTURE_GROUPS; if (need >= SCANENV_MEMNODES_SIZE) { if (env->mem_alloc <= need) { if (IS_NULL(env->mem_nodes_dynamic)) { @@ -5291,30 +5293,23 @@ set_quantifier(Node* qnode, Node* target, int group, ScanEnv* env) #ifdef USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR if (!IS_QUANTIFIER_BY_NUMBER(qn) && !IS_QUANTIFIER_BY_NUMBER(qnt) && IS_SYNTAX_BV(env->syntax, ONIG_SYN_WARN_REDUNDANT_NESTED_REPEAT)) { - UChar buf[WARN_BUFSIZE]; - switch (ReduceTypeTable[targetq_num][nestq_num]) { case RQ_ASIS: break; case RQ_DEL: - if (onig_verb_warn != onig_null_warn) { - onig_snprintf_with_pattern(buf, WARN_BUFSIZE, env->enc, - env->pattern, env->pattern_end, - (UChar* )"redundant nested repeat operator"); - (*onig_verb_warn)((char* )buf); + if (onig_warn != onig_null_warn) { + onig_syntax_warn(env, "regular expression has redundant nested repeat operator '%s'", + PopularQStr[targetq_num]); } goto warn_exit; break; default: - if (onig_verb_warn != onig_null_warn) { - onig_snprintf_with_pattern(buf, WARN_BUFSIZE, env->enc, - env->pattern, env->pattern_end, - (UChar* )"nested repeat operator %s and %s was replaced with '%s'", - PopularQStr[targetq_num], PopularQStr[nestq_num], - ReduceQStr[ReduceTypeTable[targetq_num][nestq_num]]); - (*onig_verb_warn)((char* )buf); + if (onig_warn != onig_null_warn) { + onig_syntax_warn(env, "nested repeat operator '%s' and '%s' was replaced with '%s' in regular expression", + PopularQStr[targetq_num], PopularQStr[nestq_num], + ReduceQStr[ReduceTypeTable[targetq_num][nestq_num]]); } goto warn_exit; break; diff --git a/signal.c b/signal.c index 96277e322cd449..82fad956df7ac5 100644 --- a/signal.c +++ b/signal.c @@ -343,6 +343,9 @@ ruby_default_signal(int sig) raise(sig); } +static int signal_ignored(int sig); +static void signal_enque(int sig); + /* * call-seq: * Process.kill(signal, pid, ...) -> fixnum @@ -429,6 +432,8 @@ rb_f_kill(int argc, VALUE *argv) break; } + if (argc <= 1) return INT2FIX(0); + if (sig < 0) { sig = -sig; for (i=1; imain_thread) ? getpid() : -1; + int wakeup = 0; + for (i=1; imain_thread); } } rb_thread_execute_interrupts(rb_thread_current()); @@ -543,7 +582,10 @@ ruby_signal(int signum, sighandler_t handler) rb_bug_errno("sigaction", errno); } } - return old.sa_handler; + if (old.sa_flags & SA_SIGINFO) + return (sighandler_t)old.sa_sigaction; + else + return old.sa_handler; } sighandler_t @@ -567,11 +609,32 @@ ruby_nativethread_signal(int signum, sighandler_t handler) #endif #endif -static RETSIGTYPE -sighandler(int sig) +static int +signal_ignored(int sig) +{ +#ifdef POSIX_SIGNAL + struct sigaction old; + (void)VALGRIND_MAKE_MEM_DEFINED(&old, sizeof(old)); + if (sigaction(sig, NULL, &old) < 0) return FALSE; + return old.sa_handler == SIG_IGN; +#else + sighandler_t old = signal(sig, SIG_DFL); + signal(sig, old); + return old == SIG_IGN; +#endif +} + +static void +signal_enque(int sig) { ATOMIC_INC(signal_buff.cnt[sig]); ATOMIC_INC(signal_buff.size); +} + +static RETSIGTYPE +sighandler(int sig) +{ + signal_enque(sig); rb_thread_wakeup_timer_thread(); #if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL) ruby_signal(sig, sighandler); @@ -628,21 +691,56 @@ rb_get_next_signal(void) #if defined(USE_SIGALTSTACK) || defined(_WIN32) +NORETURN(void ruby_thread_stack_overflow(rb_thread_t *th)); +#if defined(HAVE_UCONTEXT_H) && defined __linux__ && (defined __i386__ || defined __x86_64__) +# define USE_UCONTEXT_REG 1 +#endif +#ifdef USE_UCONTEXT_REG +static void +check_stack_overflow(const uintptr_t addr, const ucontext_t *ctx) +{ +# if defined REG_RSP + const greg_t sp = ctx->uc_mcontext.gregs[REG_RSP]; +# else + const greg_t sp = ctx->uc_mcontext.gregs[REG_ESP]; +# endif + enum {pagesize = 4096}; + const uintptr_t sp_page = (uintptr_t)sp / pagesize; + const uintptr_t fault_page = addr / pagesize; + + /* SP in ucontext is not decremented yet when `push` failed, so + * the fault page can be the next. */ + if (sp_page == fault_page || sp_page == fault_page + 1) { + rb_thread_t *th = ruby_current_thread; + if ((uintptr_t)th->tag->buf / pagesize == sp_page) { + /* drop the last tag if it is close to the fault, + * otherwise it can cause stack overflow again at the same + * place. */ + th->tag = th->tag->prev; + } + ruby_thread_stack_overflow(th); + } +} +#else static void check_stack_overflow(const void *addr) { int ruby_stack_overflowed_p(const rb_thread_t *, const void *); - NORETURN(void ruby_thread_stack_overflow(rb_thread_t *th)); - rb_thread_t *th = GET_THREAD(); + rb_thread_t *th = ruby_current_thread; if (ruby_stack_overflowed_p(th, addr)) { ruby_thread_stack_overflow(th); } } +#endif #ifdef _WIN32 #define CHECK_STACK_OVERFLOW() check_stack_overflow(0) #else #define FAULT_ADDRESS info->si_addr -#define CHECK_STACK_OVERFLOW() check_stack_overflow(FAULT_ADDRESS) +# ifdef USE_UCONTEXT_REG +# define CHECK_STACK_OVERFLOW() check_stack_overflow((uintptr_t)FAULT_ADDRESS, ctx) +#else +# define CHECK_STACK_OVERFLOW() check_stack_overflow(FAULT_ADDRESS) +#endif #define MESSAGE_FAULT_ADDRESS " at %p", FAULT_ADDRESS #endif #else @@ -712,6 +810,15 @@ signal_exec(VALUE cmd, int safe, int sig) volatile unsigned long old_interrupt_mask = cur_th->interrupt_mask; int state; + /* + * workaround the following race: + * 1. signal_enque queues signal for execution + * 2. user calls trap(sig, "IGNORE"), setting SIG_IGN + * 3. rb_signal_exec runs on queued signal + */ + if (IMMEDIATE_P(cmd)) + return; + cur_th->interrupt_mask |= TRAP_INTERRUPT_MASK; TH_PUSH_TAG(cur_th); if ((state = EXEC_TAG()) == 0) { @@ -863,7 +970,7 @@ trap_handler(VALUE *cmd, int sig) if (strncmp(RSTRING_PTR(command), "SIG_IGN", 7) == 0) { sig_ign: func = SIG_IGN; - *cmd = 0; + *cmd = Qtrue; } else if (strncmp(RSTRING_PTR(command), "SIG_DFL", 7) == 0) { sig_dfl: @@ -944,10 +1051,13 @@ trap(int sig, sighandler_t func, VALUE command) oldcmd = vm->trap_list[sig].cmd; switch (oldcmd) { case 0: + case Qtrue: if (oldfunc == SIG_IGN) oldcmd = rb_str_new2("IGNORE"); else if (oldfunc == sighandler) oldcmd = rb_str_new2("DEFAULT"); else oldcmd = Qnil; break; + case Qnil: + break; case Qundef: oldcmd = rb_str_new2("EXIT"); break; diff --git a/sprintf.c b/sprintf.c index 97b2126422ae0d..59d3dde0178ade 100644 --- a/sprintf.c +++ b/sprintf.c @@ -79,6 +79,9 @@ sign_bits(int base, const char *p) } while (0) #define GETARG() (nextvalue != Qundef ? nextvalue : \ + GETNEXTARG()) + +#define GETNEXTARG() ( \ posarg == -1 ? \ (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \ posarg == -2 ? \ @@ -125,7 +128,7 @@ sign_bits(int base, const char *p) tmp = GETPOSARG(n); \ } \ else { \ - tmp = GETARG(); \ + tmp = GETNEXTARG(); \ p = t; \ } \ (val) = NUM2INT(tmp); \ diff --git a/st.c b/st.c index 756f258bf533d7..37d0ebed904b67 100644 --- a/st.c +++ b/st.c @@ -428,9 +428,8 @@ find_entry(st_table *table, st_data_t key, st_index_t hash_val, st_index_t bin_p } static inline st_index_t -find_packed_index(st_table *table, st_index_t hash_val, st_data_t key) +find_packed_index_from(st_table *table, st_index_t hash_val, st_data_t key, st_index_t i) { - st_index_t i = 0; while (i < table->real_entries && (PHASH(table, i) != hash_val || !EQUAL(table, key, PKEY(table, i)))) { i++; @@ -438,6 +437,12 @@ find_packed_index(st_table *table, st_index_t hash_val, st_data_t key) return i; } +static inline st_index_t +find_packed_index(st_table *table, st_index_t hash_val, st_data_t key) +{ + return find_packed_index_from(table, hash_val, key, 0); +} + #define collision_check 0 int @@ -997,9 +1002,10 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t if (PHASH(table, i) == 0 && PKEY(table, i) == never) { break; } - i = find_packed_index(table, hash, key); - if (i == table->real_entries) { - goto deleted; + i = find_packed_index_from(table, hash, key, i); + if (i >= table->real_entries) { + i = find_packed_index(table, hash, key); + if (i >= table->real_entries) goto deleted; } /* fall through */ case ST_CONTINUE: diff --git a/string.c b/string.c index bd1e3bcfdd5cec..d4ad1cd3a7a08a 100644 --- a/string.c +++ b/string.c @@ -1956,10 +1956,10 @@ rb_str_substr(VALUE str, long beg, long len) } else { str2 = rb_str_new5(str, p, len); - rb_enc_cr_str_copy_for_substr(str2, str); OBJ_INFECT(str2, str); RB_GC_GUARD(str); } + rb_enc_cr_str_copy_for_substr(str2, str); return str2; } @@ -2034,8 +2034,8 @@ rb_str_resize(VALUE str, long len) independent = str_independent(str); ENC_CODERANGE_CLEAR(str); slen = RSTRING_LEN(str); - { + long capa; const int termlen = TERM_LEN(str); if (STR_EMBED_P(str)) { if (len == slen) return str; @@ -2061,13 +2061,12 @@ rb_str_resize(VALUE str, long len) if (len == slen) return str; str_make_independent_expand(str, len - slen); } - else if (slen < len || (RSTRING(str)->as.heap.aux.capa - len) > (len < 1024 ? len : 1024)) { + else if ((capa = RSTRING(str)->as.heap.aux.capa) < len || + (capa - len) > (len < 1024 ? len : 1024)) { REALLOC_N(RSTRING(str)->as.heap.ptr, char, len + termlen); - } - else if (len == slen) return str; - if (!STR_NOCAPA_P(str)) { RSTRING(str)->as.heap.aux.capa = len; } + else if (len == slen) return str; RSTRING(str)->as.heap.len = len; TERM_FILL(RSTRING(str)->as.heap.ptr + len, termlen); /* sentinel */ } @@ -2102,7 +2101,7 @@ str_buf_cat(VALUE str, const char *ptr, long len) if (capa <= total) { while (total > capa) { if (capa + termlen >= LONG_MAX / 2) { - capa = (total + 4095) / 4096; + capa = (total + 4095) / 4096 * 4096; break; } capa = (capa + termlen) * 2; @@ -6079,21 +6078,25 @@ rb_str_count(int argc, VALUE *argv, VALUE str) { char table[TR_TABLE_SIZE]; rb_encoding *enc = 0; - VALUE del = 0, nodel = 0; + VALUE del = 0, nodel = 0, tstr; char *s, *send; int i; int ascompat; rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); - for (i=0; i "|") diff --git a/test/date/test_switch_hitter.rb b/test/date/test_switch_hitter.rb index f18d76b393ac13..08e23015dcff60 100644 --- a/test/date/test_switch_hitter.rb +++ b/test/date/test_switch_hitter.rb @@ -312,6 +312,8 @@ def test_cmp assert_equal(-1, Date.new(2001,2,3) <=> Rational('4903888/2')) assert_equal(0, Date.new(2001,2,3) <=> Rational('4903887/2')) assert_equal(1, Date.new(2001,2,3) <=> Rational('4903886/2')) + + assert_equal(-1, Date.new(-4713,11,1,Date::GREGORIAN) <=> Date.new(-4713,12,1,Date::GREGORIAN)) end def test_eqeqeq diff --git a/test/digest/test_digest.rb b/test/digest/test_digest.rb index 86f9147428de2f..cf541a4626fd89 100755 --- a/test/digest/test_digest.rb +++ b/test/digest/test_digest.rb @@ -69,6 +69,9 @@ def test_eq assert_equal(md1, md1.clone, self.class::ALGO) + bug9913 = '[ruby-core:62967] [Bug #9913]' + assert_not_equal(md1, nil, bug9913) + md2 = self.class::ALGO.new md2 << "A" diff --git a/test/fiddle/test_import.rb b/test/fiddle/test_import.rb index 62985cfcd30c3a..d06477bfa51502 100644 --- a/test/fiddle/test_import.rb +++ b/test/fiddle/test_import.rb @@ -65,6 +65,15 @@ def test_sizeof() assert_equal(LIBC::MyStruct.size(), LIBC.sizeof(LIBC::MyStruct.malloc())) end + Fiddle.constants.grep(/\ATYPE_(?!VOID\z)(.*)/) do + type = $& + size = Fiddle.const_get("SIZEOF_#{$1}") + name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase + define_method("test_sizeof_#{name}") do + assert_equal(size, Fiddle::Importer.sizeof(name), type) + end + end + def test_unsigned_result() d = (2 ** 31) + 1 diff --git a/test/matrix/test_vector.rb b/test/matrix/test_vector.rb index 18660df574d82e..ced774c490f85b 100644 --- a/test/matrix/test_vector.rb +++ b/test/matrix/test_vector.rb @@ -146,4 +146,9 @@ def test_rational_magnitude v = Vector[Rational(1,2), 0] assert_equal(0.5, v.norm) end + + def test_cross_product + v = Vector[1, 0, 0].cross_product Vector[0, 1, 0] + assert_equal(Vector[0, 0, 1], v) + end end diff --git a/test/net/ftp/test_buffered_socket.rb b/test/net/ftp/test_buffered_socket.rb new file mode 100644 index 00000000000000..f9eefcd988a971 --- /dev/null +++ b/test/net/ftp/test_buffered_socket.rb @@ -0,0 +1,40 @@ +require "net/ftp" +require "test/unit" +require "ostruct" +require "stringio" + +class FTPTest < Test::Unit::TestCase + def test_gets_empty + sock = create_buffered_socket("") + assert_equal(nil, sock.gets) + end + + def test_gets_one_line + sock = create_buffered_socket("foo\n") + assert_equal("foo\n", sock.gets) + end + + def test_gets_one_line_without_term + sock = create_buffered_socket("foo") + assert_equal("foo", sock.gets) + end + + def test_gets_two_lines + sock = create_buffered_socket("foo\nbar\n") + assert_equal("foo\n", sock.gets) + assert_equal("bar\n", sock.gets) + end + + def test_gets_two_lines_without_term + sock = create_buffered_socket("foo\nbar") + assert_equal("foo\n", sock.gets) + assert_equal("bar", sock.gets) + end + + private + + def create_buffered_socket(s) + io = StringIO.new(s) + return Net::FTP::BufferedSocket.new(io) + end +end diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb index cecc015133063f..c4176f7b6c6312 100644 --- a/test/net/imap/test_imap_response_parser.rb +++ b/test/net/imap/test_imap_response_parser.rb @@ -248,4 +248,14 @@ def test_capability assert_equal("CAPABILITY", response.name) assert_equal("AUTH=PLAIN", response.data.last) end + + def test_mixed_boundry + parser = Net::IMAP::ResponseParser.new + response = parser.parse("* 2688 FETCH (UID 179161 BODYSTRUCTURE ((\"TEXT\" \"PLAIN\" (\"CHARSET\" \"iso-8859-1\") NIL NIL \"QUOTED-PRINTABLE\" 200 4 NIL NIL NIL)(\"MESSAGE\" \"DELIVERY-STATUS\" NIL NIL NIL \"7BIT\" 318 NIL NIL NIL)(\"MESSAGE\" \"RFC822\" NIL NIL NIL \"7BIT\" 2177 (\"Tue, 11 May 2010 18:28:16 -0400\" \"Re: Welcome letter\" ((\"David\" NIL \"info\" \"xxxxxxxx.si\")) ((\"David\" NIL \"info\" \"xxxxxxxx.si\")) ((\"David\" NIL \"info\" \"xxxxxxxx.si\")) ((\"Doretha\" NIL \"doretha.info\" \"xxxxxxxx.si\")) NIL NIL \"\" \"\") (\"MIXED\" (\"BOUNDARY\" \"000e0cd29212e3e06a0486590ae2\") NIL NIL) 37 NIL NIL NIL) \"REPORT\" (\"BOUNDARY\" \"16DuG.4XbaNOvCi.9ggvq.8Ipnyp3\" \"REPORT-TYPE\" \"delivery-status\") NIL NIL))\r\n") + empty_part = response.data.attr['BODYSTRUCTURE'].parts[2] + assert_equal(empty_part.lines, 37) + assert_equal(empty_part.body.media_type, 'MULTIPART') + assert_equal(empty_part.body.subtype, 'MIXED') + assert_equal(empty_part.body.param['BOUNDARY'], '000e0cd29212e3e06a0486590ae2') + end end diff --git a/test/net/protocol/test_protocol.rb b/test/net/protocol/test_protocol.rb index f6ee4941cfe4ce..4453422552e9c1 100644 --- a/test/net/protocol/test_protocol.rb +++ b/test/net/protocol/test_protocol.rb @@ -3,6 +3,15 @@ require "stringio" class TestProtocol < Test::Unit::TestCase + def test_should_properly_dot_stuff_period_with_no_endline + bug9627 = '[ruby-core:61441] [Bug #9627]' + sio = StringIO.new("") + imio = Net::InternetMessageIO.new(sio) + email = "To: bob@aol.com\nlook, a period with no endline\n." + imio.write_message(email) + assert_equal("To: bob@aol.com\r\nlook, a period with no endline\r\n..\r\n.\r\n", sio.string, bug9627) + end + def test_each_crlf_line assert_output('', '') do sio = StringIO.new("") diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index 42dc55de9f934f..7c4dc0bff9f7a4 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -266,4 +266,14 @@ def dump_my_heap_please File.unlink(output) end end + + def test_dump_uninitialized_file + assert_in_out_err(%[-robjspace], <<-RUBY) do |(output), (error)| + puts ObjectSpace.dump(File.allocate) + RUBY + assert_nil error + assert_match /"type":"FILE"/, output + assert_not_match /"fd":/, output + end + end end diff --git a/test/openssl/test_pair.rb b/test/openssl/test_pair.rb index 933f61292cf22c..e6af9b8c68f732 100644 --- a/test/openssl/test_pair.rb +++ b/test/openssl/test_pair.rb @@ -5,14 +5,14 @@ require 'socket' require_relative '../ruby/ut_eof' -module SSLPair +module OpenSSL::SSLPairM def server host = "127.0.0.1" port = 0 ctx = OpenSSL::SSL::SSLContext.new() ctx.ciphers = "ADH" ctx.tmp_dh_callback = proc { OpenSSL::TestUtils::TEST_KEY_DH1024 } - tcps = TCPServer.new(host, port) + tcps = create_tcp_server(host, port) ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) return ssls end @@ -21,7 +21,7 @@ def client(port) host = "127.0.0.1" ctx = OpenSSL::SSL::SSLContext.new() ctx.ciphers = "ADH" - s = TCPSocket.new(host, port) + s = create_tcp_client(host, port) ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) ssl.connect ssl.sync_close = true @@ -35,7 +35,7 @@ def ssl_pair ssls.close ns } - port = ssls.to_io.addr[1] + port = ssls.to_io.local_address.ip_port c = client(port) s = th.value if block_given? @@ -56,10 +56,31 @@ def ssl_pair end end -class OpenSSL::TestEOF1 < Test::Unit::TestCase - include TestEOF - include SSLPair +module OpenSSL::SSLPair + include OpenSSL::SSLPairM + + def create_tcp_server(host, port) + TCPServer.new(host, port) + end + + def create_tcp_client(host, port) + TCPSocket.new(host, port) + end +end + +module OpenSSL::SSLPairLowlevelSocket + include OpenSSL::SSLPairM + + def create_tcp_server(host, port) + Addrinfo.tcp(host, port).listen + end + def create_tcp_client(host, port) + Addrinfo.tcp(host, port).connect + end +end + +module OpenSSL::TestEOF1M def open_file(content) s1, s2 = ssl_pair Thread.new { s2 << content; s2.close } @@ -67,10 +88,7 @@ def open_file(content) end end -class OpenSSL::TestEOF2 < Test::Unit::TestCase - include TestEOF - include SSLPair - +module OpenSSL::TestEOF2M def open_file(content) s1, s2 = ssl_pair Thread.new { s1 << content; s1.close } @@ -78,9 +96,7 @@ def open_file(content) end end -class OpenSSL::TestPair < Test::Unit::TestCase - include SSLPair - +module OpenSSL::TestPairM def test_getc ssl_pair {|s1, s2| s1 << "a" @@ -302,7 +318,40 @@ def test_connect_accept_nonblock sock1.close if sock1 && !sock1.closed? sock2.close if sock2 && !sock2.closed? end +end + +class OpenSSL::TestEOF1 < Test::Unit::TestCase + include TestEOF + include OpenSSL::SSLPair + include OpenSSL::TestEOF1M +end + +class OpenSSL::TestEOF1LowlevelSocket < Test::Unit::TestCase + include TestEOF + include OpenSSL::SSLPairLowlevelSocket + include OpenSSL::TestEOF1M +end + +class OpenSSL::TestEOF2 < Test::Unit::TestCase + include TestEOF + include OpenSSL::SSLPair + include OpenSSL::TestEOF2M +end + +class OpenSSL::TestEOF2LowlevelSocket < Test::Unit::TestCase + include TestEOF + include OpenSSL::SSLPairLowlevelSocket + include OpenSSL::TestEOF2M +end + +class OpenSSL::TestPair < Test::Unit::TestCase + include OpenSSL::SSLPair + include OpenSSL::TestPairM +end +class OpenSSL::TestPairLowlevelSocket < Test::Unit::TestCase + include OpenSSL::SSLPairLowlevelSocket + include OpenSSL::TestPairM end end diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb index ce9bd60c2f1519..df0c6090cb3844 100644 --- a/test/openssl/test_pkey_rsa.rb +++ b/test/openssl/test_pkey_rsa.rb @@ -77,7 +77,7 @@ def test_sign_verify def test_sign_verify_memory_leak bug9743 = '[ruby-core:62038] [Bug #9743]' - assert_no_memory_leak(%w[-ropenssl], <<-PREP, <<-CODE, bug9743, rss: true) + assert_no_memory_leak(%w[-ropenssl], <<-PREP, <<-CODE, bug9743, rss: true, timeout: 30) data = 'Sign me!' digest = OpenSSL::Digest::SHA512.new pkey = OpenSSL::PKey::RSA.new(2048) @@ -89,7 +89,7 @@ def test_sign_verify_memory_leak } CODE - assert_no_memory_leak(%w[-ropenssl], <<-PREP, <<-CODE, bug9743, rss: true) + assert_no_memory_leak(%w[-ropenssl], <<-PREP, <<-CODE, bug9743, rss: true, timeout: 30) data = 'Sign me!' digest = OpenSSL::Digest::SHA512.new pkey = OpenSSL::PKey::RSA.new(2048) diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb index dd5751eb48b54b..a1922a10499dda 100644 --- a/test/openssl/test_x509cert.rb +++ b/test/openssl/test_x509cert.rb @@ -125,7 +125,7 @@ def test_extension end - def test_sign_and_verify + def test_sign_and_verify_rsa_sha1 cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::SHA1.new) assert_equal(false, cert.verify(@rsa1024)) @@ -134,7 +134,9 @@ def test_sign_and_verify assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) cert.serial = 2 assert_equal(false, cert.verify(@rsa2048)) + end + def test_sign_and_verify_rsa_md5 cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::MD5.new) assert_equal(false, cert.verify(@rsa1024)) @@ -144,7 +146,10 @@ def test_sign_and_verify assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) cert.subject = @ee1 assert_equal(false, cert.verify(@rsa2048)) + rescue OpenSSL::X509::CertificateError # RHEL7 disables MD5 + end + def test_sign_and_verify_dsa cert = issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) assert_equal(false, certificate_error_returns_false { cert.verify(@rsa1024) }) @@ -153,19 +158,21 @@ def test_sign_and_verify assert_equal(true, cert.verify(@dsa512)) cert.not_after = Time.now assert_equal(false, cert.verify(@dsa512)) + end - begin - cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], - nil, nil, OpenSSL::Digest::DSS1.new) - assert_equal(false, cert.verify(@rsa1024)) - assert_equal(true, cert.verify(@rsa2048)) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) - assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) - cert.subject = @ee1 - assert_equal(false, cert.verify(@rsa2048)) - rescue OpenSSL::X509::CertificateError - end + def test_sign_and_verify_rsa_dss1 + cert = issue_cert(@ca, @rsa2048, 1, Time.now, Time.now+3600, [], + nil, nil, OpenSSL::Digest::DSS1.new) + assert_equal(false, cert.verify(@rsa1024)) + assert_equal(true, cert.verify(@rsa2048)) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa256) }) + assert_equal(false, certificate_error_returns_false { cert.verify(@dsa512) }) + cert.subject = @ee1 + assert_equal(false, cert.verify(@rsa2048)) + rescue OpenSSL::X509::CertificateError + end + def test_sign_and_verify_dsa_md5 assert_raise(OpenSSL::X509::CertificateError){ issue_cert(@ca, @dsa512, 1, Time.now, Time.now+3600, [], nil, nil, OpenSSL::Digest::MD5.new) diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb index e6c89c5e817eb2..d0b6a5725dda45 100644 --- a/test/openssl/test_x509req.rb +++ b/test/openssl/test_x509req.rb @@ -98,7 +98,7 @@ def test_attr assert_equal(exts, get_ext_req(attrs[1].value)) end - def test_sign_and_verify + def test_sign_and_verify_rsa_sha1 req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::SHA1.new) assert_equal(true, req.verify(@rsa1024)) assert_equal(false, req.verify(@rsa2048)) @@ -106,7 +106,9 @@ def test_sign_and_verify assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) req.version = 1 assert_equal(false, req.verify(@rsa1024)) + end + def test_sign_and_verify_rsa_md5 req = issue_csr(0, @dn, @rsa2048, OpenSSL::Digest::MD5.new) assert_equal(false, req.verify(@rsa1024)) assert_equal(true, req.verify(@rsa2048)) @@ -114,7 +116,10 @@ def test_sign_and_verify assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) req.subject = OpenSSL::X509::Name.parse("/C=JP/CN=FooBar") assert_equal(false, req.verify(@rsa2048)) + rescue OpenSSL::X509::RequestError # RHEL7 disables MD5 + end + def test_sign_and_verify_dsa req = issue_csr(0, @dn, @dsa512, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) @@ -122,18 +127,21 @@ def test_sign_and_verify assert_equal(true, req.verify(@dsa512)) req.public_key = @rsa1024.public_key assert_equal(false, req.verify(@dsa512)) + end - begin - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) - assert_equal(true, req.verify(@rsa1024)) - assert_equal(false, req.verify(@rsa2048)) - assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) - req.version = 1 - assert_equal(false, req.verify(@rsa1024)) - rescue OpenSSL::X509::RequestError - end + def test_sign_and_verify_rsa_dss1 + req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) + assert_equal(true, req.verify(@rsa1024)) + assert_equal(false, req.verify(@rsa2048)) + assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) + assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) + req.version = 1 + assert_equal(false, req.verify(@rsa1024)) + rescue OpenSSL::X509::RequestError + skip + end + def test_sign_and_verify_dsa_md5 assert_raise(OpenSSL::X509::RequestError){ issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } end diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb index ec9dfa1d592443..557fae35bcf43e 100644 --- a/test/pathname/test_pathname.rb +++ b/test/pathname/test_pathname.rb @@ -88,6 +88,10 @@ def cleanpath_aggressive(path) defassert(:cleanpath_aggressive, '/', '///a/../..') end + if DOSISH + defassert(:cleanpath_aggressive, 'c:/foo/bar', 'c:\\foo\\bar') + end + def cleanpath_conservative(path) Pathname.new(path).cleanpath(true).to_s end @@ -124,6 +128,10 @@ def cleanpath_conservative(path) defassert(:cleanpath_conservative, '/a', '/../.././../a') defassert(:cleanpath_conservative, 'a/b/../../../../c/../d', 'a/b/../../../../c/../d') + if DOSISH + defassert(:cleanpath_conservative, 'c:/foo/bar', 'c:\\foo\\bar') + end + if DOSISH_UNC defassert(:cleanpath_conservative, '//', '//') else @@ -1314,4 +1322,17 @@ def test_file_join assert_equal("foo/bar", File.join(Pathname.new("foo"), Pathname.new("bar").taint)) }.call end + + def test_relative_path_from_casefold + assert_separately([], <<-'end;') # do + module File::Constants + remove_const :FNM_SYSCASE + FNM_SYSCASE = FNM_CASEFOLD + end + require 'pathname' + foo = Pathname.new("fo\u{f6}") + bar = Pathname.new("b\u{e4}r".encode("ISO-8859-1")) + assert_instance_of(Pathname, foo.relative_path_from(bar)) + end; + end end diff --git a/test/ruby/enc/test_euc_kr.rb b/test/ruby/enc/test_euc_kr.rb index 087bc795f7822c..5413fa6062e579 100644 --- a/test/ruby/enc/test_euc_kr.rb +++ b/test/ruby/enc/test_euc_kr.rb @@ -25,4 +25,12 @@ def test_mbc_case_fold def test_left_adjust_char_head assert_equal(s("\xa1\xa1"), s("\xa1\xa1\xa1\xa1").chop) end + + def test_euro_sign + assert_equal("\u{20ac}", s("\xa2\xe6").encode("utf-8")) + end + + def test_registered_mark + assert_equal("\u{00ae}", s("\xa2\xe7").encode("utf-8")) + end end diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb index de66102621cebd..fa130898d652fd 100644 --- a/test/ruby/envutil.rb +++ b/test/ruby/envutil.rb @@ -30,7 +30,9 @@ def rubybin LANG_ENVS = %w"LANG LC_ALL LC_CTYPE" def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false, - encoding: nil, timeout: 10, reprieve: 1, **opt) + encoding: nil, timeout: 10, reprieve: 1, + stdout_filter: nil, stderr_filter: nil, + **opt) in_c, in_p = IO.pipe out_p, out_c = IO.pipe if capture_stdout err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout @@ -84,6 +86,8 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = err_p.close if capture_stderr && capture_stderr != :merge_to_stdout Process.wait pid status = $? + stdout = stdout_filter.call(stdout) if stdout_filter + stderr = stderr_filter.call(stderr) if stderr_filter return stdout, stderr, status end ensure @@ -156,6 +160,22 @@ def with_default_internal(enc) end module_function :with_default_internal + def labeled_module(name, &block) + Module.new do + singleton_class.class_eval {define_method(:to_s) {name}; alias inspect to_s} + class_eval(&block) if block + end + end + module_function :labeled_module + + def labeled_class(name, superclass = Object, &block) + Class.new(superclass) do + singleton_class.class_eval {define_method(:to_s) {name}; alias inspect to_s} + class_eval(&block) if block + end + end + module_function :labeled_class + if /darwin/ =~ RUBY_PLATFORM DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports") DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S' @@ -251,9 +271,10 @@ def assert_normal_exit(testsrc, message = '', child_env: nil, **opt) pid = status.pid now = Time.now faildesc = proc do - signo = status.termsig - signame = Signal.signame(signo) - sigdesc = "signal #{signo}" + if signo = status.termsig + signame = Signal.signame(signo) + sigdesc = "signal #{signo}" + end log = EnvUtil.diagnostic_reports(signame, EnvUtil.rubybin, pid, now) if signame sigdesc = "SIG#{signame} (#{sigdesc})" @@ -337,7 +358,7 @@ class Test::Unit::Runner args.insert((Hash === args.first ? 1 : 0), "--disable=gems", *$:.map {|l| "-I#{l}"}) stdout, stderr, status = EnvUtil.invoke_ruby(args, src, true, true, **opt) abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig)) - assert(!abort, FailDesc[status, stderr]) + assert(!abort, FailDesc[status, nil, stderr]) self._assertions += stdout[/^assertions=(\d+)/, 1].to_i begin res = Marshal.load(stdout.unpack("m")[0]) diff --git a/test/ruby/test_alias.rb b/test/ruby/test_alias.rb index 956fdb41f05b0d..dec61f6d6315bc 100644 --- a/test/ruby/test_alias.rb +++ b/test/ruby/test_alias.rb @@ -132,4 +132,66 @@ class StringIO GC.verify_internal_consistency } end + + def test_cyclic_zsuper + bug9475 = '[ruby-core:60431] [Bug #9475]' + + a = Module.new do + def foo + "A" + end + end + + b = Class.new do + include a + attr_reader :b + + def foo + @b ||= 0 + raise SystemStackError if (@b += 1) > 1 + # "foo from B" + super + "B" + end + end + + c = Class.new(b) do + alias orig_foo foo + + def foo + # "foo from C" + orig_foo + "C" + end + end + + b.class_eval do + alias orig_foo foo + attr_reader :b2 + + def foo + @b2 ||= 0 + raise SystemStackError if (@b2 += 1) > 1 + # "foo from B (again)" + orig_foo + "B2" + end + end + + assert_nothing_raised(SystemStackError, bug9475) do + assert_equal("ABC", c.new.foo, bug9475) + end + end + + def test_alias_in_module + bug9663 = '[ruby-core:61635] [Bug #9663]' + + assert_separately(['-', bug9663], <<-'end;') + bug = ARGV[0] + + m = Module.new do + alias orig_to_s to_s + end + + o = Object.new.extend(m) + assert_equal(o.to_s, o.orig_to_s, bug) + end; + end end diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 6ff304acb2b9da..6e1316dc07b0c3 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -2011,6 +2011,22 @@ def test_reject assert_equal([1, 3], [0, 1, 2, 3].reject {|x| x % 2 == 0 }) end + def test_reject_with_callcc + respond_to?(:callcc, true) or require 'continuation' + bug9727 = '[ruby-dev:48101] [Bug #9727]' + cont = nil + a = [*1..10].reject do |i| + callcc {|c| cont = c} if !cont and i == 10 + false + end + if a.size < 1000 + a.unshift(:x) + cont.call + end + assert_equal(1000, a.size, bug9727) + assert_equal([:x, *1..10], a.uniq, bug9727) + end + def test_zip assert_equal([[1, :a, "a"], [2, :b, "b"], [3, nil, "c"]], [1, 2, 3].zip([:a, :b], ["a", "b", "c", "d"])) @@ -2275,6 +2291,15 @@ def test_combination2 assert_equal(:called, (0..100).to_a.combination(50) { break :called }, "[ruby-core:29240] ... must be yielded even if 100C50 > signed integer") end + def test_combination_clear + bug9939 = '[ruby-core:63149] [Bug #9939]' + assert_separately([], <<-'end;') + 100_000.times {Array.new(1000)} + a = [*0..100] + a.combination(3) {|*,x| a.clear} + end; + end + def test_product2 a = (0..100).to_a assert_raise(RangeError) do @@ -2389,7 +2414,7 @@ def test_rotate! assert_equal([], a.rotate!(13)) assert_equal([], a.rotate!(-13)) a = [].freeze - assert_raise_with_message(RuntimeError, /can't modify frozen/) {a.rotate!} + assert_raise_with_message(RuntimeError, /can\'t modify frozen/) {a.rotate!} a = [1,2,3] assert_raise(ArgumentError) { a.rotate!(1, 1) } end @@ -2428,4 +2453,28 @@ def test_bsearch_in_find_any_mode assert_include([4, 7], a.bsearch {|x| (2**100).coerce((1 - x / 4) * (2**100)).first }) end + + def test_shared_marking + reduce = proc do |s| + s.gsub(/(verify_internal_consistency_reachable_i:\sWB\smiss\s\S+\s\(T_ARRAY\)\s->\s)\S+\s\((proc|T_NONE)\)\n + \K(?:\1\S+\s\(\2\)\n)*/x) do + "...(snip #{$&.count("\n")} lines)...\n" + end + end + begin + assert_normal_exit(<<-EOS, '[Bug #9718]', timeout: 5, stdout_filter: reduce) + queue = [] + 50.times do + 10_000.times do + queue << lambda{} + end + GC.start(full_mark: false, immediate_sweep: true) + GC.verify_internal_consistency + queue.shift.call + end + EOS + rescue Timeout::Error => e + skip e.message + end + end end diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb index 6ec13e4cc5f6ad..ed36fe95f63ec7 100644 --- a/test/ruby/test_backtrace.rb +++ b/test/ruby/test_backtrace.rb @@ -214,4 +214,31 @@ def test_thread_backtrace_locations_with_range q << true end end + + def test_core_backtrace_alias + obj = BasicObject.new + e = assert_raise(NameError) do + class << obj + alias foo bar + end + end + assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label) + end + + def test_core_backtrace_undef + obj = BasicObject.new + e = assert_raise(NameError) do + class << obj + undef foo + end + end + assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label) + end + + def test_core_backtrace_hash_merge + e = assert_raise(TypeError) do + {**nil} + end + assert_not_match(/\Acore#/, e.backtrace_locations[0].base_label) + end end diff --git a/test/ruby/test_beginendblock.rb b/test/ruby/test_beginendblock.rb index 30db5024cc1c89..d9c1f569164297 100644 --- a/test/ruby/test_beginendblock.rb +++ b/test/ruby/test_beginendblock.rb @@ -112,6 +112,7 @@ def test_propagate_signaled ruby = EnvUtil.rubybin out = IO.popen( [ruby, + '-e', 'trap(:INT, "DEFAULT")', '-e', 'STDERR.reopen(STDOUT)', '-e', 'at_exit{Process.kill(:INT, $$); sleep 5 }']) {|f| timeout(10) { diff --git a/test/ruby/test_call.rb b/test/ruby/test_call.rb index 8f861d96a18b4a..5b81eb187ad1bd 100644 --- a/test/ruby/test_call.rb +++ b/test/ruby/test_call.rb @@ -16,4 +16,19 @@ def test_call assert_equal([1, 2, 3, 4], aaa(1, 2, 3, 4)) assert_equal([1, 2, 3, 4], aaa(1, *[2, 3, 4])) end + + def test_callinfo + bug9622 = '[ruby-core:61422] [Bug #9622]' + o = Class.new do + def foo(*args) + bar(:foo, *args) + end + def bar(name) + name + end + end.new + e = assert_raise(ArgumentError) {o.foo(100)} + assert_nothing_raised(ArgumentError) {o.foo} + assert_raise_with_message(ArgumentError, e.message, bug9622) {o.foo(100)} + end end diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index 17c5d57d2582b2..ddbdcf24bcabd7 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -1,4 +1,5 @@ require 'test/unit' +require_relative 'envutil' class TestEnv < Test::Unit::TestCase IGNORE_CASE = /bccwin|mswin|mingw/ =~ RUBY_PLATFORM @@ -408,4 +409,127 @@ def test_win32_blocksize keys.each {|k| ENV.delete(k)} end end + + if RUBY_PLATFORM =~ /bccwin|mswin|mingw/ + def test_memory_leak_aset + bug9977 = '[ruby-dev:48323] [Bug #9977]' + assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9977, limit: 2.0) + ENV.clear + k = 'FOO' + v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500) + doit = proc {ENV[k] = v} + 500.times(&doit) + end; + end + + def test_memory_leak_select + bug9978 = '[ruby-dev:48325] [Bug #9978]' + assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9978, limit: 2.0) + ENV.clear + k = 'FOO' + (ENV[k] = 'bar'*5000 rescue 'bar'*1500) + doit = proc {ENV.select {break}} + 500.times(&doit) + end; + end + + def test_memory_crash_select + assert_normal_exit(<<-'end;') + 1000.times {ENV["FOO#{i}"] = 'bar'} + ENV.select {ENV.clear} + end; + end + + def test_memory_leak_shift + bug9983 = '[ruby-dev:48332] [Bug #9983]' + assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9983, limit: 2.0) + ENV.clear + k = 'FOO' + v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500) + doit = proc {ENV[k] = v; ENV.shift} + 500.times(&doit) + end; + end + end + + def test_taint_aref + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV["FOO".taint] + end.call + end + end + + def test_taint_fetch + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.fetch("FOO".taint) + end.call + end + end + + def test_taint_assoc + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.assoc("FOO".taint) + end.call + end + end + + def test_taint_rassoc + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.rassoc("FOO".taint) + end.call + end + end + + def test_taint_key + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.key("FOO".taint) + end.call + end + end + + def test_taint_key_p + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.key?("FOO".taint) + end.call + end + end + + def test_taint_value_p + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV.value?("FOO".taint) + end.call + end + end + + def test_taint_aset_value + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV["FOO"] = "BAR".taint + end.call + end + end + + def test_taint_aset_key + assert_raise(SecurityError) do + proc do + $SAFE = 2 + ENV["FOO".taint] = "BAR" + end.call + end + end end diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index dfa428912e0e68..c3314568c13491 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -78,6 +78,28 @@ def test_exception_ensure_2 # just duplication? assert(!bad) end + def test_errinfo_in_debug + bug9568 = EnvUtil.labeled_class("[ruby-core:61091] [Bug #9568]", RuntimeError) do + def to_s + require '\0' + rescue LoadError + self.class.to_s + end + end + + err = EnvUtil.verbose_warning do + assert_raise(bug9568) do + $DEBUG, debug = true, $DEBUG + begin + raise bug9568 + ensure + $DEBUG = debug + end + end + end + assert_include(err, bug9568.to_s) + end + def test_break_ensure bad = true while true @@ -488,6 +510,17 @@ def test_machine_stackoverflow rescue SystemStackError end + def test_machine_stackoverflow_by_define_method + bug9454 = '[ruby-core:60113] [Bug #9454]' + assert_separately([], <<-SRC) + assert_raise(SystemStackError, #{bug9454.dump}) { + define_method(:foo) {self.foo} + self.foo + } + SRC + rescue SystemStackError + end + def test_cause msg = "[Feature #8257]" cause = nil diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb index a64a956afd73d8..bd69addef65a02 100644 --- a/test/ruby/test_file_exhaustive.rb +++ b/test/ruby/test_file_exhaustive.rb @@ -464,7 +464,7 @@ def test_expand_path_memsize path = File.expand_path("/foo") assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize, bug9934) path = File.expand_path("/a"*25) - assert_equal(51, ObjectSpace.memsize_of(path), bug9934) + assert_equal(path.bytesize+1, ObjectSpace.memsize_of(path), bug9934) end def test_expand_path_encoding diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index cbe55cc1f26899..d811598ccec1ec 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1094,6 +1094,17 @@ def test_compare_by_identity assert_predicate(h.dup, :compare_by_identity?, bug8703) end + def test_same_key + bug9646 = '[ruby-dev:48047] [Bug #9646] Infinite loop at Hash#each' + h = @cls[a=[], 1] + a << 1 + h[[]] = 2 + a.clear + cnt = 0 + r = h.each{ break nil if (cnt+=1) > 100 } + assert_not_nil(r,bug9646) + end + class ObjWithHash def initialize(value, hash) @value = value diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index a6f2b14abedb72..cf0ac9803e7dc6 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1122,6 +1122,8 @@ def test_dup_many def test_inspect with_pipe do |r, w| assert_match(/^#$/, r.inspect) + r.freeze + assert_match(/^#$/, r.inspect) end end @@ -1224,6 +1226,14 @@ def test_read_buffer_error t.value assert_equal("", s) end + with_pipe do |r, w| + s = "xxx" + t = Thread.new {r.read(2, s)} + Thread.pass until t.stop? + t.kill + t.value + assert_equal("xxx", s) + end end def test_write_nonblock @@ -2743,6 +2753,21 @@ def test_std_fileno assert_equal(2, $stderr.fileno) end + def test_frozen_fileno + bug9865 = '[ruby-dev:48241] [Bug #9865]' + with_pipe do |r,w| + fd = r.fileno + assert_equal(fd, r.freeze.fileno, bug9865) + end + end + + def test_frozen_autoclose + with_pipe do |r,w| + fd = r.fileno + assert_equal(true, r.freeze.autoclose?) + end + end + def test_sysread_locktmp bug6099 = '[ruby-dev:45297]' buf = " " * 100 @@ -2790,25 +2815,24 @@ def test_advise_pipe def assert_buffer_not_raise_shared_string_error bug6764 = '[ruby-core:46586]' + bug9847 = '[ruby-core:62643] [Bug #9847]' size = 28 data = [*"a".."z", *"A".."Z"].shuffle.join("") t = Tempfile.new("test_io") t.write(data) t.close - w = Tempfile.new("test_io") + w = [] assert_nothing_raised(RuntimeError, bug6764) do + buf = '' File.open(t.path, "r") do |r| - buf = '' while yield(r, size, buf) - w << buf + w << buf.dup end end end - w.close - assert_equal(data, w.open.read, bug6764) + assert_equal(data, w.join(""), bug9847) ensure t.close! - w.close! end def test_read_buffer_not_raise_shared_string_error @@ -2971,4 +2995,13 @@ def test_sysread_unlocktmp_ensure ensure t.kill end + + def test_exception_at_close + bug10153 = '[ruby-core:64463] [Bug #10153] exception in close at the end of block' + assert_raise(Errno::EBADF, bug10153) do + IO.pipe do |r, w| + assert_nothing_raised {IO.open(w.fileno) {}} + end + end + end end diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 03b93dbf0d0b58..e7bd11b18b0beb 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -327,6 +327,39 @@ def test_required_keyword assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar} end + def test_required_keyword_with_newline + bug9669 = '[ruby-core:61658] [Bug #9669]' + assert_nothing_raised(SyntaxError, bug9669) do + eval(<<-'end;', nil, __FILE__, __LINE__) + def bug9669.foo a: + return a + end + end; + end + assert_equal(42, bug9669.foo(a: 42)) + o = nil + assert_nothing_raised(SyntaxError, bug9669) do + eval(<<-'end;', nil, __FILE__, __LINE__) + o = { + a: + 1 + } + end; + end + assert_equal({a: 1}, o, bug9669) + end + + def test_required_keyword_with_reserved + bug10279 = '[ruby-core:65211] [Bug #10279]' + h = nil + assert_nothing_raised(SyntaxError, bug10279) do + break eval(<<-'end;', nil, __FILE__, __LINE__) + h = {a: if true then 42 end} + end; + end + assert_equal({a: 42}, h, bug10279) + end + def test_block_required_keyword feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument' b = assert_nothing_raised(SyntaxError, feature7701) do @@ -420,6 +453,40 @@ def foo(a, b, c=1, *d, e, f:2, **g) assert_equal([1, 2, 1, [], {:f=>5}, 2, {}], a.new.foo(1, 2, f:5), bug8993) end + def test_splat_keyword_nondestructive + bug9776 = '[ruby-core:62161] [Bug #9776]' + + h = {a: 1} + assert_equal({a:1, b:2}, {**h, b:2}) + assert_equal({a:1}, h, bug9776) + + pr = proc {|**opt| next opt} + assert_equal({a: 1}, pr.call(**h)) + assert_equal({a: 1, b: 2}, pr.call(**h, b: 2)) + assert_equal({a: 1}, h, bug9776) + end + + def test_splat_hash_conversion + bug9898 = '[ruby-core:62921] [Bug #9898]' + + o = Object.new + def o.to_hash() { a: 1 } end + assert_equal({a: 1}, m1(**o) {|x| break x}, bug9898) + o2 = Object.new + def o2.to_hash() { b: 2 } end + assert_equal({a: 1, b: 2}, m1(**o, **o2) {|x| break x}, bug9898) + end + + def test_implicit_hash_conversion + bug10016 = '[ruby-core:63593] [Bug #10016]' + + o = Object.new + def o.to_hash() { k: 9 } end + assert_equal([1, 42, [], o, :key, {}, nil], f9(1, o)) + assert_equal([1, 9], m1(1, o) {|a, k: 0| break [a, k]}, bug10016) + assert_equal([1, 9], m1(1, o, &->(a, k: 0) {break [a, k]}), bug10016) + end + def test_gced_object_in_stack bug8964 = '[ruby-dev:47729] [Bug #8964]' assert_normal_exit %q{ diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb index b9b85b21293afb..7d00b1aec67b0e 100644 --- a/test/ruby/test_m17n.rb +++ b/test/ruby/test_m17n.rb @@ -1037,6 +1037,11 @@ def test_count assert_raise(Encoding::CompatibilityError){s.count(a("\xa3\xb0"))} end + def test_count_sjis_trailing_byte + bug10078 = '[ruby-dev:48442] [Bug #10078]' + assert_equal(0, s("\x98\x61").count("a"), bug10078) + end + def test_delete assert_equal(1, e("\xa1\xa2").delete("z").length) s = e("\xa3\xb0\xa3\xb1\xa3\xb2\xa3\xb3\xa3\xb4") diff --git a/test/ruby/test_m17n_comb.rb b/test/ruby/test_m17n_comb.rb index 446ceccc4ae17d..55bfe3955303d1 100644 --- a/test/ruby/test_m17n_comb.rb +++ b/test/ruby/test_m17n_comb.rb @@ -87,7 +87,7 @@ def encdumpargs(args) r end - def assert_enccall(recv, meth, *args, &block) + def encdumpcall(recv, meth, *args, &block) desc = '' if String === recv desc << encdump(recv) @@ -110,6 +110,11 @@ def assert_enccall(recv, meth, *args, &block) if block desc << ' {}' end + desc + end + + def assert_enccall(recv, meth, *args, &block) + desc = encdumpcall(recv, meth, *args, &block) result = nil assert_nothing_raised(desc) { result = recv.send(meth, *args, &block) @@ -709,12 +714,13 @@ def test_str_dup def test_str_count combination(STRINGS, STRINGS) {|s1, s2| + desc = proc {encdumpcall(s1, :count, s2)} if !s1.valid_encoding? || !s2.valid_encoding? - assert_raise(ArgumentError, Encoding::CompatibilityError) { s1.count(s2) } + assert_raise(ArgumentError, Encoding::CompatibilityError, desc) { s1.count(s2) } next end if !s1.ascii_only? && !s2.ascii_only? && s1.encoding != s2.encoding - assert_raise(Encoding::CompatibilityError) { s1.count(s2) } + assert_raise(Encoding::CompatibilityError, desc) { s1.count(s2) } next end n = enccall(s1, :count, s2) diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index 2e3c2ae8b07317..f478e114867663 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -660,6 +660,7 @@ def test___dir__ assert_equal(__dir__, eval("__dir__", binding), bug8436) bug8662 = '[ruby-core:56099] [Bug #8662]' assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662) + assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662) end def test_alias_owner diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index f89071c10f270b..372a2d4ca5d08e 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -375,6 +375,25 @@ def foo assert_equal(:ok, Object.new.extend(m).foo, bug9535) end + def test_initialize_copy_empty + bug9813 = '[ruby-dev:48182] [Bug #9813]' + m = Module.new do + def x + end + const_set(:X, 1) + @x = 2 + end + assert_equal([:x], m.instance_methods) + assert_equal([:@x], m.instance_variables) + assert_equal([:X], m.constants) + m.module_eval do + initialize_copy(Module.new) + end + assert_empty(m.instance_methods, bug9813) + assert_empty(m.instance_variables, bug9813) + assert_empty(m.constants, bug9813) + end + def test_dup bug6454 = '[ruby-core:45132]' @@ -1559,17 +1578,11 @@ def test_prepend_module_ancestors end def labeled_module(name, &block) - Module.new do - singleton_class.class_eval {define_method(:to_s) {name}; alias inspect to_s} - class_eval(&block) if block - end + EnvUtil.labeled_module(name, &block) end def labeled_class(name, superclass = Object, &block) - Class.new(superclass) do - singleton_class.class_eval {define_method(:to_s) {name}; alias inspect to_s} - class_eval(&block) if block - end + EnvUtil.labeled_class(name, superclass, &block) end def test_prepend_instance_methods_false diff --git a/test/ruby/test_numeric.rb b/test/ruby/test_numeric.rb index f2c1a51ba20df2..0e70078bad8996 100644 --- a/test/ruby/test_numeric.rb +++ b/test/ruby/test_numeric.rb @@ -1,4 +1,5 @@ require 'test/unit' +require_relative 'envutil' class TestNumeric < Test::Unit::TestCase class DummyNumeric < Numeric @@ -14,6 +15,19 @@ def test_coerce assert_equal(Float, b.class) assert_raise(TypeError) { -Numeric.new } + + EnvUtil.with_default_external(Encoding::UTF_8) do + assert_raise_with_message(TypeError, /:\u{3042}/) {1+:"\u{3042}"} + assert_raise_with_message(TypeError, /:\u{3042}/) {1&:"\u{3042}"} + assert_raise_with_message(TypeError, /:\u{3042}/) {1|:"\u{3042}"} + assert_raise_with_message(TypeError, /:\u{3042}/) {1^:"\u{3042}"} + end + EnvUtil.with_default_external(Encoding::US_ASCII) do + assert_raise_with_message(TypeError, /:"\\u3042"/) {1+:"\u{3042}"} + assert_raise_with_message(TypeError, /:"\\u3042"/) {1&:"\u{3042}"} + assert_raise_with_message(TypeError, /:"\\u3042"/) {1|:"\u{3042}"} + assert_raise_with_message(TypeError, /:"\\u3042"/) {1^:"\u{3042}"} + end end def test_dummynumeric @@ -223,6 +237,8 @@ def assert_step(expected, (from, *args), inf: false) end def test_step + i, bignum = 32, 1 << 30 + bignum <<= (i <<= 1) - 32 until bignum.is_a?(Bignum) assert_raise(ArgumentError) { 1.step(10, 1, 0) { } } assert_raise(ArgumentError) { 1.step(10, 1, 0).size } assert_raise(ArgumentError) { 1.step(10, 0) { } } @@ -238,6 +254,25 @@ def test_step assert_nothing_raised { 1.step(by: nil) } assert_nothing_raised { 1.step(by: nil).size } + bug9811 = '[ruby-dev:48177] [Bug #9811]' + assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, foo: nil).size } + assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, to: 11).size } + assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11) {} } + assert_raise(ArgumentError, bug9811) { 1.step(10, 1, by: 11).size } + + assert_equal(bignum*2+1, (-bignum).step(bignum, 1).size) + assert_equal(bignum*2, (-bignum).step(bignum-1, 1).size) + + assert_equal(10+1, (0.0).step(10.0, 1.0).size) + + i, bigflo = 1, bignum.to_f + i <<= 1 until (bigflo - i).to_i < bignum + bigflo -= i >> 1 + assert_equal(bigflo.to_i, (0.0).step(bigflo-1.0, 1.0).size) + assert_operator((0.0).step(bignum.to_f, 1.0).size, :>=, bignum) # may loose precision + assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 10] assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10] assert_step [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, to: 10, by: nil] @@ -248,19 +283,35 @@ def test_step assert_step [10, 8, 6, 4, 2], [10, to: 1, by: -2] assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, 10.0, 2.0] assert_step [1.0, 3.0, 5.0, 7.0, 9.0], [1.0, to: 10.0, by: 2.0] - assert_step [1], [1, 10, 2**32] - assert_step [1], [1, to: 10, by: 2**32] + assert_step [1], [1, 10, bignum] + assert_step [1], [1, to: 10, by: bignum] + assert_step [], [2, 1, 3] + assert_step [], [-2, -1, -3] assert_step [3, 3, 3, 3], [3, by: 0], inf: true - assert_step [10], [10, 1, -(2**32)] + assert_step [3, 3, 3, 3], [3, by: 0, to: 42], inf: true + assert_step [10], [10, 1, -bignum] assert_step [], [1, 0, Float::INFINITY] assert_step [], [0, 1, -Float::INFINITY] - assert_step [10], [10, to: 1, by: -(2**32)] + assert_step [10], [10, to: 1, by: -bignum] assert_step [10, 11, 12, 13], [10], inf: true assert_step [10, 9, 8, 7], [10, by: -1], inf: true assert_step [10, 9, 8, 7], [10, by: -1, to: nil], inf: true + + assert_step [42, 42, 42, 42], [42, by: 0, to: -Float::INFINITY], inf: true + assert_step [42, 42, 42, 42], [42, by: 0, to: 42.5], inf: true + assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: 0.0], inf: true + assert_step [4.2, 4.2, 4.2, 4.2], [4.2, by: -0.0], inf: true + assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 44], inf: true + assert_step [42.0, 42.0, 42.0, 42.0], [42, by: 0.0, to: 0], inf: true + assert_step [42.0, 42.0, 42.0, 42.0], [42, by: -0.0, to: 44], inf: true + + assert_step [bignum]*4, [bignum, by: 0], inf: true + assert_step [bignum]*4, [bignum, by: 0.0], inf: true + assert_step [bignum]*4, [bignum, by: 0, to: bignum+1], inf: true + assert_step [bignum]*4, [bignum, by: 0, to: 0], inf: true end def test_num2long diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb index 1d6c6e30230ca4..e8ab6135c480ac 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -805,4 +805,14 @@ def test_type_error_message assert_raise_with_message(TypeError, "can't convert Array into Integer") {Integer([42])} assert_raise_with_message(TypeError, 'no implicit conversion of Array into Integer') {[].first([42])} end + + def test_copied_ivar_memory_leak + bug10191 = '[ruby-core:64700] [Bug #10191]' + assert_no_memory_leak([], <<-"end;", <<-"end;", bug10191, rss: true, timeout: 60, limit: 2.5) + def (a = Object.new).set; @v = nil; end + num = 500_000 + end; + num.times {a.clone.set} + end; + end end diff --git a/test/ruby/test_pack.rb b/test/ruby/test_pack.rb index 3f0931bdc0cfb2..4b089f732218d5 100644 --- a/test/ruby/test_pack.rb +++ b/test/ruby/test_pack.rb @@ -550,6 +550,14 @@ def test_pack_unpack_m assert_equal(["\0"], "AA\n".unpack("m")) assert_equal(["\0"], "AA=\n".unpack("m")) assert_equal(["\0\0"], "AAA\n".unpack("m")) + + bug10019 = '[ruby-core:63604] [Bug #10019]' + size = ((4096-4)/4*3+1) + assert_separately(%W[- #{size} #{bug10019}], <<-'end;') + size = ARGV.shift.to_i + bug = ARGV.shift + assert_equal(size, ["a"*size].pack("m#{size+2}").unpack("m")[0].size, bug) + end; end def test_pack_unpack_m0 diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index 863d37909647c8..1bea4d0918ec9f 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -1,6 +1,7 @@ # coding: US-ASCII require 'test/unit' require 'stringio' +require_relative 'envutil' class TestParse < Test::Unit::TestCase def setup @@ -658,8 +659,11 @@ def test_invalid_class_variable end def test_invalid_char + bug10117 = '[ruby-core:64243] [Bug #10117]' + invalid_char = /Invalid char `\\x01'/ x = 1 - assert_equal(1, eval("\x01x")) + assert_in_out_err(%W"-e \x01x", "", [], invalid_char, bug10117) + assert_syntax_error("\x01x", invalid_char, bug10117) assert_equal(nil, eval("\x04x")) end diff --git a/test/ruby/test_pipe.rb b/test/ruby/test_pipe.rb index 34f231ad8c9e0e..bcea91bebb6239 100644 --- a/test/ruby/test_pipe.rb +++ b/test/ruby/test_pipe.rb @@ -13,4 +13,17 @@ def open_file(content) r.close end end + class WithConversion < self + def open_file(content) + r, w = IO.pipe + w << content + w.close + r.set_encoding("us-ascii:utf-8") + begin + yield r + ensure + r.close + end + end + end end diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index ecfb417b117510..65bb83d2f669d8 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -606,6 +606,16 @@ def test_execopts_redirect } end + def test_execopts_redirect_nonascii_path + bug9946 = '[ruby-core:63185] [Bug #9946]' + with_tmpchdir {|d| + path = "t-\u{30c6 30b9 30c8 f6}.txt" + system(*ECHO["a"], out: path) + assert_file.for(bug9946).exist?(path) + assert_equal("a\n", File.read(path), bug9946) + } + end + def test_execopts_redirect_dup2_child with_tmpchdir {|d| Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", @@ -1182,6 +1192,23 @@ def test_status end def test_status_kill + return unless Process.respond_to?(:kill) + return unless Signal.list.include?("KILL") + + # assume the system supports signal if SIGQUIT is available + expected = Signal.list.include?("QUIT") ? [false, true, false, nil] : [true, false, false, true] + + with_tmpchdir do + write_file("foo", "Process.kill(:KILL, $$); exit(42)") + system(RUBY, "foo") + s = $? + assert_equal(expected, + [s.exited?, s.signaled?, s.stopped?, s.success?], + "[s.exited?, s.signaled?, s.stopped?, s.success?]") + end + end + + def test_status_quit return unless Process.respond_to?(:kill) return unless Signal.list.include?("QUIT") @@ -1196,16 +1223,14 @@ def test_status_kill end t = Time.now s = $? - assert_equal([false, true, false], - [s.exited?, s.signaled?, s.stopped?], - "[s.exited?, s.signaled?, s.stopped?]") + assert_equal([false, true, false, nil], + [s.exited?, s.signaled?, s.stopped?, s.success?], + "[s.exited?, s.signaled?, s.stopped?, s.success?]") assert_send( [["#", "#"], :include?, s.inspect]) - assert_equal(false, s.exited?) - assert_equal(nil, s.success?) EnvUtil.diagnostic_reports("QUIT", RUBY, pid, t) end end diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index d535c474241d5d..77e4789bfc7a37 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -1152,6 +1152,21 @@ def m INPUT end + def test_refine_basic_object + assert_separately([], <<-"end;") + bug10106 = '[ruby-core:64166] [Bug #10106]' + module RefinementBug + refine BasicObject do + def foo + 1 + end + end + end + + assert_raise(NoMethodError, bug10106) {Object.new.foo} + end; + end + private def eval_using(mod, s) diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb index cff2bb6d1f5707..bef770b9236306 100644 --- a/test/ruby/test_regexp.rb +++ b/test/ruby/test_regexp.rb @@ -142,6 +142,31 @@ def test_named_capture assert_equal("fbazo", s) end + def test_named_capture_with_nul + bug9902 = '[ruby-dev:48275] [Bug #9902]' + + m = /(?.*)/.match("foo") + assert_raise(IndexError, bug9902) {m["a\0foo"]} + assert_raise(IndexError, bug9902) {m["a\0foo".to_sym]} + + m = Regexp.new("(?.*)").match("xxx") + assert_raise(IndexError, bug9902) {m["foo"]} + assert_raise(IndexError, bug9902) {m["foo".to_sym]} + assert_nothing_raised(IndexError, bug9902) { + assert_equal("xxx", m["foo\0bar"], bug9902) + assert_equal("xxx", m["foo\0bar".to_sym], bug9902) + } + end + + def test_named_capture_nonascii + bug9903 = '[ruby-dev:48278] [Bug #9903]' + + key = "\xb1\xb2".force_encoding(Encoding::EUC_JP) + m = /(?<#{key}>.*)/.match("xxx") + assert_equal("xxx", m[key]) + assert_raise(IndexError, bug9903) {m[key.dup.force_encoding(Encoding::Shift_JIS)]} + end + def test_assign_named_capture assert_equal("a", eval('/(?.)/ =~ "a"; foo')) assert_equal("a", eval('foo = 1; /(?.)/ =~ "a"; foo')) diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index ba25f8a489da74..b6be5011cd971b 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -527,6 +527,7 @@ module SEGVTest \[NOTE\]\n You\smay\shave\sencountered\sa\sbug\sin\sthe\sRuby\sinterpreter\sor\sextension\slibraries.\n Bug\sreports\sare\swelcome.\n + (?:.*\n)? For\sdetails:\shttp:\/\/.*\.ruby-lang\.org/.*\n \n (?:#{additional}) diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index b106ea5494315c..5cb6d4a16e31ad 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -383,7 +383,7 @@ def test_trace_defined_method [["c-return", 3, :set_trace_func, Kernel], ["line", 6, __method__, self.class], - ["call", 6, :foobar, FooBar], + ["call", 1, :foobar, FooBar], ["return", 6, :foobar, FooBar], ["line", 7, __method__, self.class], ["c-call", 7, :set_trace_func, Kernel]].each{|e| @@ -1066,4 +1066,286 @@ def test_a_return :b_return ], events) end + + def test_const_missing + bug59398 = '[ruby-core:59398]' + events = [] + assert !defined?(MISSING_CONSTANT_59398) + TracePoint.new(:c_call, :c_return, :call, :return){|tp| + next unless tp.defined_class == Module + # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name + # but this only happens when running the full test suite + events << [tp.event,tp.method_id] if tp.method_id == :const_missing || tp.method_id == :rake_original_const_missing + }.enable{ + MISSING_CONSTANT_59398 rescue nil + } + if events.map{|e|e[1]}.include?(:rake_original_const_missing) + assert_equal([ + [:call, :const_missing], + [:c_call, :rake_original_const_missing], + [:c_return, :rake_original_const_missing], + [:return, :const_missing], + ], events, bug59398) + else + assert_equal([ + [:c_call, :const_missing], + [:c_return, :const_missing] + ], events, bug59398) + end + end + + class AliasedRubyMethod + def foo; 1; end; + alias bar foo + end + def test_aliased_ruby_method + events = [] + aliased = AliasedRubyMethod.new + TracePoint.new(:call, :return){|tp| + events << [tp.event, tp.method_id] + }.enable{ + aliased.bar + } + assert_equal([ + [:call, :foo], + [:return, :foo] + ], events, "should use original method name for tracing ruby methods") + end + class AliasedCMethod < Hash + alias original_size size + def size; original_size; end + end + + def test_aliased_c_method + events = [] + aliased = AliasedCMethod.new + TracePoint.new(:call, :return, :c_call, :c_return){|tp| + events << [tp.event, tp.method_id] + }.enable{ + aliased.size + } + assert_equal([ + [:call, :size], + [:c_call, :original_size], + [:c_return, :original_size], + [:return, :size] + ], events, "should use alias method name for tracing c methods") + end + + def test_method_missing + bug59398 = '[ruby-core:59398]' + events = [] + assert !respond_to?(:missing_method_59398) + TracePoint.new(:c_call, :c_return, :call, :return){|tp| + next unless tp.defined_class == BasicObject + # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name + # but this only happens when running the full test suite + events << [tp.event,tp.method_id] if tp.method_id == :method_missing + }.enable{ + missing_method_59398 rescue nil + } + assert_equal([ + [:c_call, :method_missing], + [:c_return, :method_missing] + ], events, bug59398) + end + + class C9759 + define_method(:foo){ + raise + } + end + + def test_define_method_on_exception + events = [] + obj = C9759.new + TracePoint.new(:call, :return){|tp| + next unless target_thread? + events << [tp.event, tp.method_id] + }.enable{ + obj.foo rescue nil + } + assert_equal([[:call, :foo], [:return, :foo]], events, 'Bug #9759') + + events = [] + begin + set_trace_func(lambda{|event, file, lineno, mid, binding, klass| + next unless target_thread? + case event + when 'call', 'return' + events << [event, mid] + end + }) + obj.foo rescue nil + set_trace_func(nil) + + assert_equal([['call', :foo], ['return', :foo]], events, 'Bug #9759') + ensure + end + end + + def test_recursive + assert_ruby_status [], %q{ + stack = [] + TracePoint.new(:c_call){|tp| + p 2 + stack << tp.method_id + }.enable{ + p 1 + } + raise if stack != [:p, :hash, :inspect] + }, '[Bug #9940]' + end + + def method_test_rescue_should_not_cause_b_return + begin + raise + rescue + return + end + end + + def method_test_ensure_should_not_cause_b_return + begin + raise + ensure + return + end + end + + def test_rescue_and_ensure_should_not_cause_b_return + curr_thread = Thread.current + trace = TracePoint.new(:b_call, :b_return){ + next if curr_thread != Thread.current + flunk("Should not reach here because there is no block.") + } + + begin + trace.enable + method_test_rescue_should_not_cause_b_return + begin + method_test_ensure_should_not_cause_b_return + rescue + # ignore + end + ensure + trace.disable + end + end + + define_method(:method_test_argument_error_on_bmethod){|correct_key: 1|} + + def test_argument_error_on_bmethod + events = [] + curr_thread = Thread.current + TracePoint.new(:call, :return){|tp| + next if curr_thread != Thread.current + events << [tp.event, tp.method_id] + }.enable do + begin + method_test_argument_error_on_bmethod(wrong_key: 2) + rescue => e + # ignore + end + end + + assert_equal [], events # should be empty. + end + + def method_prefix event + case event + when :call, :return + :n + when :c_call, :c_return + :c + when :b_call, :b_return + :b + end + end + + def method_label tp + "#{method_prefix(tp.event)}##{tp.method_id}" + end + + def assert_consistent_call_return message='', check_events: nil + check_events ||= %i(a_call a_return) + call_events = [] + return_events = [] + + TracePoint.new(*check_events){|tp| + next unless target_thread? + + case tp.event.to_s + when /call/ + call_events << method_label(tp) + when /return/ + return_events << method_label(tp) + end + }.enable do + yield + end + + assert_equal false, call_events.empty? + assert_equal false, return_events.empty? + assert_equal call_events, return_events.reverse, message + end + + def test_rb_rescue + events = [] + curr_thread = Thread.current + TracePoint.new(:a_call, :a_return){|tp| + next if curr_thread != Thread.current + events << [tp.event, tp.method_id] + }.enable do + begin + -Numeric.new + rescue => e + # ignore + end + end + + assert_equal [ + [:b_call, :test_rb_rescue], + [:c_call, :new], + [:c_call, :initialize], + [:c_return, :initialize], + [:c_return, :new], + [:c_call, :-@], + [:c_call, :coerce], + [:c_call, :new], + [:c_call, :initialize], + [:c_return, :initialize], + [:c_return, :new], + [:c_call, :exception], + [:c_return, :exception], + [:c_call, :backtrace], + [:c_return, :backtrace], + [:c_return, :coerce], # don't miss it! + [:c_call, :to_s], + [:c_return, :to_s], + [:c_call, :to_s], + [:c_return, :to_s], + [:c_call, :new], + [:c_call, :initialize], + [:c_return, :initialize], + [:c_return, :new], + [:c_call, :exception], + [:c_return, :exception], + [:c_call, :backtrace], + [:c_return, :backtrace], + [:c_return, :-@], + [:c_call, :===], + [:c_return, :===], + [:b_return, :test_rb_rescue]], events + end + + def test_b_call_with_redo + assert_consistent_call_return do + i = 0 + 1.times{ + break if (i+=1) > 10 + redo + } + end + end end diff --git a/test/ruby/test_signal.rb b/test/ruby/test_signal.rb index c7bcc4a375a745..e329df9a341252 100644 --- a/test/ruby/test_signal.rb +++ b/test/ruby/test_signal.rb @@ -255,9 +255,12 @@ def test_hup_me # that signal will be deliverd synchronously. # This ugly workaround was introduced to don't break # compatibility against silly example codes. + assert_separately([], <<-RUBY) + trap(:HUP, "DEFAULT") assert_raise(SignalException) { Process.kill('HUP', Process.pid) } + RUBY bug8137 = '[ruby-dev:47182] [Bug #8137]' assert_nothing_raised(bug8137) { Timeout.timeout(1) { @@ -265,4 +268,15 @@ def test_hup_me } } end if Process.respond_to?(:kill) and Signal.list.key?('HUP') + + def test_ignored_interrupt + bug9820 = '[ruby-dev:48203] [Bug #9820]' + assert_separately(['-', bug9820], <<-'end;') # begin + bug = ARGV.shift + trap(:INT, "IGNORE") + assert_nothing_raised(SignalException, bug) do + Process.kill(:INT, $$) + end + end; + end if Process.respond_to?(:kill) end diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb index 80e69f7fda2f11..eff35c18daac47 100644 --- a/test/ruby/test_sprintf.rb +++ b/test/ruby/test_sprintf.rb @@ -179,6 +179,10 @@ def test_invalid assert_raise(ArgumentError) { sprintf("%!", 1) } assert_raise(ArgumentError) { sprintf("%1$1$d", 1) } assert_raise(ArgumentError) { sprintf("%0%") } + + assert_raise_with_message(ArgumentError, /unnumbered\(1\) mixed with numbered/) { sprintf("%1$*d", 3) } + assert_raise_with_message(ArgumentError, /unnumbered\(1\) mixed with numbered/) { sprintf("%1$.*d", 3) } + verbose, $VERBOSE = $VERBOSE, nil assert_nothing_raised { sprintf("", 1) } ensure diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 7ce1c0666cf65a..e510a4984ccd23 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -1179,6 +1179,11 @@ def test_slice assert_equal(S("Bar"), S("FooBar").slice(S("Bar"))) assert_nil(S("FooBar").slice(S("xyzzy"))) assert_nil(S("FooBar").slice(S("plugh"))) + + bug9882 = '[ruby-core:62842] [Bug #9882]' + substr = S("\u{30c6 30b9 30c8 2019}#{bug9882}").slice(4..-1) + assert_equal(S(bug9882).hash, substr.hash, bug9882) + assert_predicate(substr, :ascii_only?, bug9882) end def test_slice! @@ -2219,6 +2224,17 @@ def =~(str) assert_equal("foo", "" =~ //) RUBY end + + def test_LSHIFT_neary_long_max + return unless @cls == String + assert_ruby_status([], <<-'end;', '[ruby-core:61886] [Bug #9709]', timeout: 20) + begin + a = "a" * 0x4000_0000 + a << "a" * 0x1_0000 + rescue NoMemoryError + end + end; + end end class TestString2 < TestString diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index 82d6e19ec4ba1c..e42782191dbd91 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -271,12 +271,12 @@ def test_double_include2 end def test_super_in_instance_eval - super_class = Class.new { + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { def foo return [:super, self] end } - sub_class = Class.new(super_class) { + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { def foo x = Object.new x.instance_eval do @@ -285,18 +285,18 @@ def foo end } obj = sub_class.new - assert_raise(TypeError) do + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do obj.foo end end def test_super_in_instance_eval_with_define_method - super_class = Class.new { + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { def foo return [:super, self] end } - sub_class = Class.new(super_class) { + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { define_method(:foo) do x = Object.new x.instance_eval do @@ -305,18 +305,18 @@ def foo end } obj = sub_class.new - assert_raise(TypeError) do + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do obj.foo end end def test_super_in_orphan_block - super_class = Class.new { + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { def foo return [:super, self] end } - sub_class = Class.new(super_class) { + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { def foo x = Object.new lambda { super() } @@ -327,12 +327,12 @@ def foo end def test_super_in_orphan_block_with_instance_eval - super_class = Class.new { + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { def foo return [:super, self] end } - sub_class = Class.new(super_class) { + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { def foo x = Object.new x.instance_eval do @@ -341,7 +341,7 @@ def foo end } obj = sub_class.new - assert_raise(TypeError) do + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do obj.foo.call end end @@ -453,4 +453,45 @@ def foo; super end m.call end end + + def test_super_in_module_unbound_method + bug9721 = '[ruby-core:61936] [Bug #9721]' + + a = Module.new do + def foo(result) + result << "A" + end + end + + b = Module.new do + def foo(result) + result << "B" + super + end + end + + um = b.instance_method(:foo) + + m = um.bind(Object.new.extend(a)) + result = [] + assert_nothing_raised(NoMethodError, bug9721) do + m.call(result) + end + assert_equal(%w[B A], result, bug9721) + + bug9740 = '[ruby-core:62017] [Bug #9740]' + + b.module_eval do + define_method(:foo) do |result| + um.bind(self).call(result) + end + end + + result.clear + o = Object.new.extend(a).extend(b) + assert_nothing_raised(NoMethodError, SystemStackError, bug9740) do + o.foo(result) + end + assert_equal(%w[B A], result, bug9721) + end end diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index cac755a3903c48..2ed57889ba5e05 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -78,6 +78,11 @@ def test_newline_in_block_parameters end end + def test_do_block_in_cmdarg + bug9726 = '[ruby-core:61950] [Bug #9726]' + assert_valid_syntax("tap (proc do end)", __FILE__, bug9726) + end + def test_keyword_rest bug5989 = '[ruby-core:42455]' assert_valid_syntax("def kwrest_test(**a) a; end", __FILE__, bug5989) @@ -397,6 +402,12 @@ def test_warning_for_cr end end + def test_error_message_encoding + bug10114 = '[ruby-core:64228] [Bug #10114]' + code = "# -*- coding: utf-8 -*-\n" "def n \"\u{2208}\"; end" + assert_syntax_error(code, /def n "\u{2208}"; end/, bug10114) + end + private def not_label(x) @result = x; @not_label ||= nil end diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb index fedab8791ead49..6568b8dfbc3a05 100644 --- a/test/ruby/test_thread.rb +++ b/test/ruby/test_thread.rb @@ -358,6 +358,24 @@ def test_status_and_stop_p c.kill if c end + def test_switch_while_busy_loop + bug1402 = "[ruby-dev:38319] [Bug #1402]" + flag = true + th = Thread.current + waiter = Thread.start { + sleep 0.1 + flag = false + sleep 1 + th.raise(bug1402) + } + assert_nothing_raised(RuntimeError, bug1402) do + nil while flag + end + assert(!flag, bug1402) + ensure + waiter.kill.join + end + def test_safe_level ok = false t = Thread.new do @@ -726,7 +744,7 @@ def test_thread_timer_and_interrupt bug5757 = '[ruby-dev:44985]' t0 = Time.now.to_f pid = nil - cmd = 'r,=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; r.read' + cmd = 'Signal.trap(:INT, "DEFAULT"); r,=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; r.read' opt = {} opt[:new_pgroup] = true if /mswin|mingw/ =~ RUBY_PLATFORM s, _err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true, opt) do |in_p, out_p, err_p, cpid| @@ -746,6 +764,7 @@ def test_thread_timer_and_interrupt def test_thread_join_in_trap assert_separately [], <<-'EOS' + Signal.trap(:INT, "DEFAULT") t0 = Thread.current assert_nothing_raised{ t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$)} @@ -761,6 +780,7 @@ def test_thread_join_in_trap def test_thread_value_in_trap assert_separately [], <<-'EOS' + Signal.trap(:INT, "DEFAULT") t0 = Thread.current t = Thread.new {Thread.pass until t0.stop?; Process.kill(:INT, $$); :normal_end} @@ -967,4 +987,25 @@ def test_blocking_mutex_unlocked_on_fork pid, status = Process.waitpid2(pid) assert_equal(false, status.success?, bug8433) end if Process.respond_to?(:fork) + + def test_fork_in_thread + bug9751 = '[ruby-core:62070] [Bug #9751]' + f = nil + th = Thread.start do + unless f = IO.popen("-") + STDERR.reopen(STDOUT) + exit + end + Process.wait2(f.pid) + end + unless th.join(3) + Process.kill(:QUIT, f.pid) + Process.kill(:KILL, f.pid) unless th.join(1) + end + _, status = th.value + output = f.read + f.close + assert_not_predicate(status, :signaled?, FailDesc[status, bug9751, output]) + assert_predicate(status, :success?, bug9751) + end if Process.respond_to?(:fork) end diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb index 744ac4c39f8b6d..d016812e3a5341 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -311,6 +311,21 @@ def test_marshal_zone end end + def test_marshal_zone_gc + assert_separately(%w(--disable-gems), <<-'end;', timeout: 30) + ENV["TZ"] = "JST-9" + s = Marshal.dump(Time.now) + t = Marshal.load(s) + n = 0 + done = 100000 + while t.zone.dup == "JST" && n < done + n += 1 + end + assert_equal done, n, "Bug #9652" + assert_equal "JST", t.zone, "Bug #9652" + end; + end + def test_marshal_to_s t1 = Time.new(2011,11,8, 0,42,25, 9*3600) t2 = Time.at(Marshal.load(Marshal.dump(t1))) diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb index 32b3d6157325e9..b902288fdd043b 100644 --- a/test/ruby/test_variable.rb +++ b/test/ruby/test_variable.rb @@ -83,6 +83,18 @@ def test_local_variables3 end.call end + def test_shadowing_local_variables + bug9486 = '[ruby-core:60501] [Bug #9486]' + x = tap {|x| break local_variables} + assert_equal([:x, :bug9486, :x], x) + end + + def test_shadowing_block_local_variables + bug9486 = '[ruby-core:60501] [Bug #9486]' + x = tap {|;x| break local_variables} + assert_equal([:x, :bug9486, :x], x) + end + def test_global_variable_0 assert_in_out_err(["-e", "$0='t'*1000;print $0"], "", /\At+\z/, []) end diff --git a/test/socket/test_addrinfo.rb b/test/socket/test_addrinfo.rb index 5bd7e2ab84b70d..61b889ed26478a 100644 --- a/test/socket/test_addrinfo.rb +++ b/test/socket/test_addrinfo.rb @@ -140,7 +140,7 @@ def test_socket_connect ai = Addrinfo.new(s1.getsockname) s2 = Socket.new(:INET, :STREAM, 0) s2.connect(ai) - s3, sender_addr = s1.accept + s3, _ = s1.accept s2.send("test-socket-connect", 0) assert_equal("test-socket-connect", s3.recv(100)) ensure @@ -166,7 +166,7 @@ def test_socket_connect_nonblock rescue Errno::EISCONN end end - s3, sender_addr = s1.accept + s3, _ = s1.accept s2.send("test-socket-connect-nonblock", 0) assert_equal("test-socket-connect-nonblock", s3.recv(100)) ensure diff --git a/test/socket/test_nonblock.rb b/test/socket/test_nonblock.rb index e395a0ad319814..882e438deb81c0 100644 --- a/test/socket/test_nonblock.rb +++ b/test/socket/test_nonblock.rb @@ -64,8 +64,8 @@ def test_udp_recvfrom_nonblock mesg, inet_addr = u1.recvfrom_nonblock(100) assert_equal(4, inet_addr.length) assert_equal("aaa", mesg) - af, port, host, addr = inet_addr - u2_port, u2_addr = Socket.unpack_sockaddr_in(u2.getsockname) + _, port, _, _ = inet_addr + u2_port, _ = Socket.unpack_sockaddr_in(u2.getsockname) assert_equal(u2_port, port) assert_raise(IO::WaitReadable) { u1.recvfrom_nonblock(100) } u2.send("", 0, u1.getsockname) @@ -111,8 +111,8 @@ def test_socket_recvfrom_nonblock IO.select [s1] mesg, sockaddr = s1.recvfrom_nonblock(100) assert_equal("aaa", mesg) - port, addr = Socket.unpack_sockaddr_in(sockaddr) - s2_port, s2_addr = Socket.unpack_sockaddr_in(s2.getsockname) + port, _ = Socket.unpack_sockaddr_in(sockaddr) + s2_port, _ = Socket.unpack_sockaddr_in(s2.getsockname) assert_equal(s2_port, port) ensure s1.close if s1 @@ -121,7 +121,7 @@ def test_socket_recvfrom_nonblock def tcp_pair serv = TCPServer.new("127.0.0.1", 0) - af, port, host, addr = serv.addr + _, port, _, addr = serv.addr c = TCPSocket.new(addr, port) s = serv.accept if block_given? @@ -268,7 +268,7 @@ def test_recv_nonblock_error def test_connect_nonblock_error serv = TCPServer.new("127.0.0.1", 0) - af, port, host, addr = serv.addr + _, port, _, _ = serv.addr c = Socket.new(:INET, :STREAM) begin c.connect_nonblock(Socket.sockaddr_in(port, "127.0.0.1")) @@ -284,7 +284,6 @@ def test_accept_nonblock_error serv = Socket.new(:INET, :STREAM) serv.bind(Socket.sockaddr_in(0, "127.0.0.1")) serv.listen(5) - port = serv.local_address.ip_port begin s, _ = serv.accept_nonblock rescue Errno::EWOULDBLOCK diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb index 5d2d0aee263853..73801811e1e566 100644 --- a/test/socket/test_socket.rb +++ b/test/socket/test_socket.rb @@ -359,7 +359,6 @@ def test_udp_server # Mac OS X may sets IFDISABLED as FreeBSD does ulSIOCGIFFLAGS = 3223349521 ulSIOCGIFINFO_IN6 = 3224398156 - ulSIOCGIFAFLAG_IN6 = 3240126793 ulIFF_POINTOPOINT = 0x10 ulND6_IFF_IFDISABLED = 8 in6_ondireq = ifr_name @@ -403,7 +402,7 @@ def test_udp_server raise "no response from #{ai.inspect} #{nd6options}ping=#{ping_p}" end msg2, addr = s.recvmsg - msg2, remote_address, local_address = Marshal.load(msg2) + msg2, _, _ = Marshal.load(msg2) assert_equal(msg1, msg2) assert_equal(ai.ip_address, addr.ip_address) } @@ -454,7 +453,7 @@ def test_timestamp Addrinfo.udp("127.0.0.1", 0).bind {|s2| s1.setsockopt(:SOCKET, :TIMESTAMP, true) s2.send "a", 0, s1.local_address - msg, addr, rflags, stamp = s1.recvmsg + msg, _, _, stamp = s1.recvmsg assert_equal("a", msg) assert(stamp.cmsg_is?(:SOCKET, :TIMESTAMP)) } @@ -481,7 +480,7 @@ def test_timestampns return end s2.send "a", 0, s1.local_address - msg, addr, rflags, stamp = s1.recvmsg + msg, _, _, stamp = s1.recvmsg assert_equal("a", msg) assert(stamp.cmsg_is?(:SOCKET, :TIMESTAMPNS)) } @@ -503,7 +502,7 @@ def test_bintime Addrinfo.udp("127.0.0.1", 0).bind {|s2| s1.setsockopt(:SOCKET, :BINTIME, true) s2.send "a", 0, s1.local_address - msg, addr, rflags, stamp = s1.recvmsg + msg, _, _, stamp = s1.recvmsg assert_equal("a", msg) assert(stamp.cmsg_is?(:SOCKET, :BINTIME)) } diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb index f10c5efaf84018..a6879bbfe4b28c 100644 --- a/test/socket/test_unix.rb +++ b/test/socket/test_unix.rb @@ -53,7 +53,7 @@ def test_fd_passing_n end assert_equal(1, ret) ret = s2.recvmsg(:scm_rights=>true) - data, srcaddr, flags, *ctls = ret + _, _, _, *ctls = ret recv_io_ary = [] ctls.each {|ctl| next if ctl.level != Socket::SOL_SOCKET || ctl.type != Socket::SCM_RIGHTS @@ -90,7 +90,7 @@ def test_fd_passing_n2 end assert_equal(1, ret) ret = s2.recvmsg(:scm_rights=>true) - data, srcaddr, flags, *ctls = ret + _, _, _, *ctls = ret recv_io_ary = [] ctls.each {|ctl| next if ctl.level != Socket::SOL_SOCKET || ctl.type != Socket::SCM_RIGHTS @@ -422,7 +422,6 @@ def test_unix_socket_pair_with_block end def test_unix_socket_pair_close_on_exec - pair = nil UNIXSocket.pair {|s1, s2| assert(s1.close_on_exec?) assert(s2.close_on_exec?) @@ -465,7 +464,7 @@ def test_getcred_ucred Dir.mktmpdir {|d| sockpath = "#{d}/sock" serv = Socket.unix_server_socket(sockpath) - c = Socket.unix(sockpath) + Socket.unix(sockpath) s, = serv.accept cred = s.getsockopt(:SOCKET, :PEERCRED) inspect = cred.inspect @@ -481,7 +480,7 @@ def test_getcred_xucred Dir.mktmpdir {|d| sockpath = "#{d}/sock" serv = Socket.unix_server_socket(sockpath) - c = Socket.unix(sockpath) + Socket.unix(sockpath) s, = serv.accept cred = s.getsockopt(0, Socket::LOCAL_PEERCRED) inspect = cred.inspect @@ -499,7 +498,7 @@ def test_sendcred_ucred s, = serv.accept s.setsockopt(:SOCKET, :PASSCRED, 1) c.print "a" - msg, cliend_ai, rflags, cred = s.recvmsg + msg, _, _, cred = s.recvmsg inspect = cred.inspect assert_equal("a", msg) assert_match(/ pid=#{$$} /, inspect) @@ -518,7 +517,7 @@ def test_sendcred_sockcred s, = serv.accept s.setsockopt(0, Socket::LOCAL_CREDS, 1) c.print "a" - msg, cliend_ai, rflags, cred = s.recvmsg + msg, _, _, cred = s.recvmsg assert_equal("a", msg) inspect = cred.inspect assert_match(/ uid=#{Process.uid} /, inspect) @@ -537,7 +536,7 @@ def test_sendcred_cmsgcred c = Socket.unix(sockpath) s, = serv.accept c.sendmsg("a", 0, nil, [:SOCKET, Socket::SCM_CREDS, ""]) - msg, cliend_ai, rflags, cred = s.recvmsg + msg, _, _, cred = s.recvmsg assert_equal("a", msg) inspect = cred.inspect assert_match(/ pid=#{$$} /, inspect) diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb index f29322b393d95f..07d89d16e10743 100644 --- a/test/stringio/test_stringio.rb +++ b/test/stringio/test_stringio.rb @@ -119,6 +119,36 @@ def o.to_s; "baz"; end f.close unless f.closed? end + def test_write_infection + bug9769 = '[ruby-dev:48118] [Bug #9769]' + s = "".untaint + f = StringIO.new(s, "w") + f.print("bar".taint) + f.close + assert_predicate(s, :tainted?, bug9769) + ensure + f.close unless f.closed? + end + + def test_write_encoding + s = "".force_encoding(Encoding::UTF_8) + f = StringIO.new(s) + f.print("\u{3053 3093 306b 3061 306f ff01}".b) + assert_equal(Encoding::UTF_8, s.encoding, "honor the original encoding over ASCII-8BIT") + end + + def test_set_encoding + bug10285 = '[ruby-core:65240] [Bug #10285]' + f = StringIO.new() + f.set_encoding(Encoding::ASCII_8BIT) + f.write("quz \x83 mat".b) + s = "foo \x97 bar".force_encoding(Encoding::WINDOWS_1252) + assert_nothing_raised(Encoding::CompatibilityError, bug10285) { + f.write(s) + } + assert_equal(Encoding::ASCII_8BIT, f.string.encoding, bug10285) + end + def test_mode_error f = StringIO.new("", "r") assert_raise(IOError) { f.write("foo") } @@ -419,6 +449,22 @@ def test_putc assert_equal("foo123", s) end + def test_putc_nonascii + s = "" + f = StringIO.new(s, "w") + f.putc("\u{3042}") + f.putc(0x3044) + f.close + assert_equal("\u{3042}D", s) + + s = "foo" + f = StringIO.new(s, "a") + f.putc("\u{3042}") + f.putc(0x3044) + f.close + assert_equal("foo\u{3042}D", s) + end + def test_read f = StringIO.new("\u3042\u3044") assert_raise(ArgumentError) { f.read(-1) } diff --git a/test/test_timeout.rb b/test/test_timeout.rb index 117c1402fa3e43..e71a09f22ca8d4 100644 --- a/test/test_timeout.rb +++ b/test/test_timeout.rb @@ -11,17 +11,11 @@ def test_queue end def test_timeout - flag = true - Thread.start { - sleep 0.01 - flag = false - } - assert_nothing_raised("[ruby-dev:38319]") do - Timeout.timeout(1) { - Thread.pass while flag + assert_raise(Timeout::Error) do + Timeout.timeout(0.1) { + nil while true } end - assert !flag, "[ruby-dev:38319]" end def test_cannot_convert_into_time_interval diff --git a/test/testunit/test_parallel.rb b/test/testunit/test_parallel.rb index 7dce42f0a94564..6276aac8bd0204 100644 --- a/test/testunit/test_parallel.rb +++ b/test/testunit/test_parallel.rb @@ -90,8 +90,7 @@ def test_p def test_done timeout(10) do @worker_in.puts "run #{TESTS}/ptest_forth.rb test" - i = 0 - 6.times { @worker_out.gets } + 7.times { @worker_out.gets } buf = @worker_out.gets assert_match(/^done (.+?)$/, buf) @@ -99,7 +98,7 @@ def test_done result = Marshal.load($1.chomp.unpack("m")[0]) - assert_equal(4, result[0]) + assert_equal(5, result[0]) assert_equal(2, result[1]) assert_kind_of(Array,result[2]) assert_kind_of(Array,result[3]) @@ -107,7 +106,8 @@ def test_done assert_kind_of(Array,result[2][1]) assert_kind_of(MiniTest::Assertion,result[2][0][2]) assert_kind_of(MiniTest::Skip,result[2][1][2]) - assert_kind_of(Exception, result[2][2][2]) + assert_kind_of(MiniTest::Skip,result[2][2][2]) + assert_kind_of(Exception, result[2][3][2]) assert_equal(result[5], "TestE") end end @@ -157,7 +157,7 @@ def test_ignore_jzero def test_should_run_all_without_any_leaks spawn_runner buf = timeout(10){@test_out.read} - assert_match(/^[SFE\.]{8}$/,buf) + assert_match(/^[SFE\.]{9}$/,buf) end def test_should_retry_failed_on_workers diff --git a/test/testunit/tests_for_parallel/ptest_forth.rb b/test/testunit/tests_for_parallel/ptest_forth.rb index ad5a7f34ce8ea5..46c88da5191a1e 100644 --- a/test/testunit/tests_for_parallel/ptest_forth.rb +++ b/test/testunit/tests_for_parallel/ptest_forth.rb @@ -15,6 +15,14 @@ def test_always_fail assert_equal(0,1) end + def test_skip_after_unknown_error + begin + raise UnknownError, "unknown error" + rescue + skip "after raise" + end + end + def test_unknown_error raise UnknownError, "unknown error" end diff --git a/test/thread/test_cv.rb b/test/thread/test_cv.rb index 9a9b407a5b1968..08459a0a04c526 100644 --- a/test/thread/test_cv.rb +++ b/test/thread/test_cv.rb @@ -4,6 +4,12 @@ require_relative '../ruby/envutil' class TestConditionVariable < Test::Unit::TestCase + def test_initialized + assert_raise(TypeError) { + ConditionVariable.allocate.wait(nil) + } + end + def test_condvar_signal_and_wait mutex = Mutex.new condvar = ConditionVariable.new @@ -188,4 +194,19 @@ def test_condvar_empty_broadcast assert_nothing_raised(Exception) { mutex.synchronize {condvar.broadcast} } end + + (DumpableCV = ConditionVariable.dup).class_eval {remove_method :marshal_dump} + + def test_dump + bug9674 = '[ruby-core:61677] [Bug #9674]' + condvar = ConditionVariable.new + assert_raise_with_message(TypeError, /#{ConditionVariable}/, bug9674) do + Marshal.dump(condvar) + end + + condvar = DumpableCV.new + assert_raise_with_message(TypeError, /internal Array/, bug9674) do + Marshal.dump(condvar) + end + end end diff --git a/test/thread/test_queue.rb b/test/thread/test_queue.rb index c99475d8dc872d..314ee98dab0ddb 100644 --- a/test/thread/test_queue.rb +++ b/test/thread/test_queue.rb @@ -5,6 +5,18 @@ require_relative '../ruby/envutil' class TestQueue < Test::Unit::TestCase + def test_queue_initialized + assert_raise(TypeError) { + Queue.allocate.push(nil) + } + end + + def test_sized_queue_initialized + assert_raise(TypeError) { + SizedQueue.allocate.push(nil) + } + end + def test_queue grind(5, 1000, 15, Queue) end @@ -207,4 +219,24 @@ def test_queue_thread_raise timeout(1) { th2.join } end end + + (DumpableQueue = Queue.dup).class_eval {remove_method :marshal_dump} + + def test_dump + bug9674 = '[ruby-core:61677] [Bug #9674]' + q = Queue.new + assert_raise_with_message(TypeError, /#{Queue}/, bug9674) do + Marshal.dump(q) + end + + sq = SizedQueue.new(1) + assert_raise_with_message(TypeError, /#{SizedQueue}/, bug9674) do + Marshal.dump(sq) + end + + q = DumpableQueue.new + assert_raise_with_message(TypeError, /internal Array/, bug9674) do + Marshal.dump(q) + end + end end diff --git a/test/webrick/test_filehandler.rb b/test/webrick/test_filehandler.rb index 5b96223da80851..10b6add1474d1b 100644 --- a/test/webrick/test_filehandler.rb +++ b/test/webrick/test_filehandler.rb @@ -184,7 +184,6 @@ def test_non_disclosure_name def test_directory_traversal config = { :DocumentRoot => File.dirname(__FILE__), } - this_file = File.basename(__FILE__) TestWEBrick.start_httpserver(config) do |server, addr, port, log| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/../../") @@ -199,7 +198,6 @@ def test_directory_traversal def test_unwise_in_path if windows? config = { :DocumentRoot => File.dirname(__FILE__), } - this_file = File.basename(__FILE__) TestWEBrick.start_httpserver(config) do |server, addr, port, log| http = Net::HTTP.new(addr, port) req = Net::HTTP::Get.new("/..%5c..") diff --git a/test/xmlrpc/test_features.rb b/test/xmlrpc/test_features.rb index 89c91f2afe42fa..48bb0d4c2154fe 100644 --- a/test/xmlrpc/test_features.rb +++ b/test/xmlrpc/test_features.rb @@ -16,11 +16,11 @@ def test_nil_create XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)} XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, false) - assert_raise(RuntimeError) { str = c.methodCall("test", *@params) } + assert_raise(RuntimeError) { c.methodCall("test", *@params) } XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)} XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, true) - assert_nothing_raised { str = c.methodCall("test", *@params) } + assert_nothing_raised { c.methodCall("test", *@params) } end end diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index 3122e7769ef7b2..bb76c23a1f55c2 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -162,7 +162,7 @@ def test_closed_p assert_equal(false, z.closed?) z << "foo" assert_equal(false, z.closed?) - s = z.finish + z.finish assert_equal(false, z.closed?) z.close assert_equal(true, z.closed?) @@ -309,9 +309,6 @@ def test_inflate def test_inflate_partial_input deflated = Zlib::Deflate.deflate "\0" - a = deflated[0...2] - b = deflated[2..-1] - z = Zlib::Inflate.new inflated = "" @@ -700,6 +697,11 @@ def test_rewind assert_equal("foo", f.read) f.rewind assert_equal("foo", f.read) + + f.rewind + bytes = [] + f.each_byte { |b| bytes << b } + assert_equal "foo".bytes.to_a, bytes, '[Bug #10101]' end open(t.path, "rb") do |f| gz = Zlib::GzipReader.new(f) diff --git a/thread.c b/thread.c index 0e743c68e0da43..d9df90272e8049 100644 --- a/thread.c +++ b/thread.c @@ -121,7 +121,7 @@ static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_regio #ifdef __ia64 #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th) \ - do{(th)->machine_register_stack_end = rb_ia64_bsp();}while(0) + do{(th)->machine.register_stack_end = rb_ia64_bsp();}while(0) #else #define RB_GC_SAVE_MACHINE_REGISTER_STACK(th) #endif @@ -129,8 +129,8 @@ static inline void blocking_region_end(rb_thread_t *th, struct rb_blocking_regio do { \ FLUSH_REGISTER_WINDOWS; \ RB_GC_SAVE_MACHINE_REGISTER_STACK(th); \ - setjmp((th)->machine_regs); \ - SET_MACHINE_STACK_END(&(th)->machine_stack_end); \ + setjmp((th)->machine.regs); \ + SET_MACHINE_STACK_END(&(th)->machine.stack_end); \ } while (0) #define GVL_UNLOCK_BEGIN() do { \ @@ -465,9 +465,9 @@ thread_cleanup_func_before_exec(void *th_ptr) { rb_thread_t *th = th_ptr; th->status = THREAD_KILLED; - th->machine_stack_start = th->machine_stack_end = 0; + th->machine.stack_start = th->machine.stack_end = 0; #ifdef __ia64 - th->machine_register_stack_start = th->machine_register_stack_end = 0; + th->machine.register_stack_start = th->machine.register_stack_end = 0; #endif } @@ -519,9 +519,9 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s ruby_thread_set_native(th); - th->machine_stack_start = stack_start; + th->machine.stack_start = stack_start; #ifdef __ia64 - th->machine_register_stack_start = register_stack_start; + th->machine.register_stack_start = register_stack_start; #endif thread_debug("thread start: %p\n", (void *)th); @@ -569,6 +569,9 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s thread_debug("thread end: %p\n", (void *)th); main_th = th->vm->main_thread; + if (main_th == th) { + ruby_stop(0); + } if (RB_TYPE_P(errinfo, T_OBJECT)) { /* treat with normal error object */ rb_threadptr_raise(main_th, 1, &errinfo); @@ -2743,22 +2746,25 @@ rb_thread_inspect(VALUE thread) return str; } -VALUE -rb_thread_local_aref(VALUE thread, ID id) +static VALUE +threadptr_local_aref(rb_thread_t *th, ID id) { - rb_thread_t *th; st_data_t val; - GetThreadPtr(thread, th); - if (!th->local_storage) { - return Qnil; - } - if (st_lookup(th->local_storage, id, &val)) { + if (th->local_storage && st_lookup(th->local_storage, id, &val)) { return (VALUE)val; } return Qnil; } +VALUE +rb_thread_local_aref(VALUE thread, ID id) +{ + rb_thread_t *th; + GetThreadPtr(thread, th); + return threadptr_local_aref(th, id); +} + /* * call-seq: * thr[sym] -> obj or nil @@ -2827,26 +2833,35 @@ rb_thread_aref(VALUE thread, VALUE key) return rb_thread_local_aref(thread, id); } -VALUE -rb_thread_local_aset(VALUE thread, ID id, VALUE val) +static VALUE +threadptr_local_aset(rb_thread_t *th, ID id, VALUE val) { - rb_thread_t *th; - GetThreadPtr(thread, th); - - if (OBJ_FROZEN(thread)) { - rb_error_frozen("thread locals"); - } if (NIL_P(val)) { if (!th->local_storage) return Qnil; st_delete_wrap(th->local_storage, id); return Qnil; } + else { if (!th->local_storage) { th->local_storage = st_init_numtable(); } st_insert(th->local_storage, id, val); return val; } +} + +VALUE +rb_thread_local_aset(VALUE thread, ID id, VALUE val) +{ + rb_thread_t *th; + GetThreadPtr(thread, th); + + if (OBJ_FROZEN(thread)) { + rb_error_frozen("thread locals"); + } + + return threadptr_local_aset(th, id, val); +} /* * call-seq: @@ -4775,6 +4790,20 @@ recursive_list_access(void) return list; } +VALUE +rb_threadptr_reset_recursive_data(rb_thread_t *th) +{ + VALUE old = threadptr_local_aref(th, recursive_key); + threadptr_local_aset(th, recursive_key, Qnil); + return old; +} + +void +rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old) +{ + threadptr_local_aset(th, recursive_key, old); +} + /* * Returns Qtrue iff obj_id (or the pair ) is already * in the recursion list. @@ -5291,13 +5320,12 @@ ruby_kill(rb_pid_t pid, int sig) { int err; rb_thread_t *th = GET_THREAD(); - rb_vm_t *vm = GET_VM(); /* * When target pid is self, many caller assume signal will be * delivered immediately and synchronously. */ - if ((sig != 0) && (th == vm->main_thread) && (pid == getpid())) { + { GVL_UNLOCK_BEGIN(); native_mutex_lock(&th->interrupt_lock); err = kill(pid, sig); @@ -5305,9 +5333,7 @@ ruby_kill(rb_pid_t pid, int sig) native_mutex_unlock(&th->interrupt_lock); GVL_UNLOCK_END(); } - else { - err = kill(pid, sig); - } - if (err < 0) + if (err < 0) { rb_sys_fail(0); + } } diff --git a/thread_pthread.c b/thread_pthread.c index aa2c49e949ab9d..581dfecaaa3d27 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -661,6 +661,18 @@ ruby_init_stack(volatile VALUE *addr ) { native_main_thread.id = pthread_self(); +#if MAINSTACKADDR_AVAILABLE + if (native_main_thread.stack_maxsize) return; + { + void* stackaddr; + size_t size; + if (get_main_stack(&stackaddr, &size) == 0) { + native_main_thread.stack_maxsize = size; + native_main_thread.stack_start = stackaddr; + return; + } + } +#endif #ifdef STACK_END_ADDRESS native_main_thread.stack_start = STACK_END_ADDRESS; #else @@ -676,18 +688,6 @@ ruby_init_stack(volatile VALUE *addr (VALUE*)bsp < native_main_thread.register_stack_start) { native_main_thread.register_stack_start = (VALUE*)bsp; } -#endif -#if MAINSTACKADDR_AVAILABLE - if (native_main_thread.stack_maxsize) return; - { - void* stackaddr; - size_t size; - if (get_main_stack(&stackaddr, &size) == 0) { - native_main_thread.stack_maxsize = size; - native_main_thread.stack_start = stackaddr; - return; - } - } #endif { #if defined(HAVE_GETRLIMIT) @@ -749,8 +749,8 @@ native_thread_init_stack(rb_thread_t *th) rb_nativethread_id_t curr = pthread_self(); if (pthread_equal(curr, native_main_thread.id)) { - th->machine_stack_start = native_main_thread.stack_start; - th->machine_stack_maxsize = native_main_thread.stack_maxsize; + th->machine.stack_start = native_main_thread.stack_start; + th->machine.stack_maxsize = native_main_thread.stack_maxsize; } else { #ifdef STACKADDR_AVAILABLE @@ -758,11 +758,11 @@ native_thread_init_stack(rb_thread_t *th) size_t size; if (get_stack(&start, &size) == 0) { - th->machine_stack_start = start; - th->machine_stack_maxsize = size; + th->machine.stack_start = start; + th->machine.stack_maxsize = size; } #elif defined get_stack_of - if (!th->machine_stack_maxsize) { + if (!th->machine.stack_maxsize) { native_mutex_lock(&th->interrupt_lock); native_mutex_unlock(&th->interrupt_lock); } @@ -771,9 +771,9 @@ native_thread_init_stack(rb_thread_t *th) #endif } #ifdef __ia64 - th->machine_register_stack_start = native_main_thread.register_stack_start; - th->machine_stack_maxsize /= 2; - th->machine_register_stack_maxsize = th->machine_stack_maxsize; + th->machine.register_stack_start = native_main_thread.register_stack_start; + th->machine.stack_maxsize /= 2; + th->machine.register_stack_maxsize = th->machine.stack_maxsize; #endif return 0; } @@ -800,7 +800,7 @@ thread_start_func_1(void *th_ptr) native_thread_init(th); /* run */ #if defined USE_NATIVE_THREAD_INIT - thread_start_func_2(th, th->machine_stack_start, rb_ia64_bsp()); + thread_start_func_2(th, th->machine.stack_start, rb_ia64_bsp()); #else thread_start_func_2(th, &stack_start, rb_ia64_bsp()); #endif @@ -922,10 +922,10 @@ native_thread_create(rb_thread_t *th) const size_t stack_size = th->vm->default_params.thread_machine_stack_size; const size_t space = space_size(stack_size); - th->machine_stack_maxsize = stack_size - space; + th->machine.stack_maxsize = stack_size - space; #ifdef __ia64 - th->machine_stack_maxsize /= 2; - th->machine_register_stack_maxsize = th->machine_stack_maxsize; + th->machine.stack_maxsize /= 2; + th->machine.register_stack_maxsize = th->machine.stack_maxsize; #endif #ifdef HAVE_PTHREAD_ATTR_INIT @@ -948,8 +948,8 @@ native_thread_create(rb_thread_t *th) #ifdef get_stack_of if (!err) { get_stack_of(th->thread_id, - &th->machine_stack_start, - &th->machine_stack_maxsize); + &th->machine.stack_start, + &th->machine.stack_maxsize); } native_mutex_unlock(&th->interrupt_lock); #endif @@ -1558,15 +1558,24 @@ ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr) const size_t water_mark = 1024 * 1024; STACK_GROW_DIR_DETECTION; - if (th) { - size = th->machine_stack_maxsize; - base = (char *)th->machine_stack_start - STACK_DIR_UPPER(0, size); - } #ifdef STACKADDR_AVAILABLE - else if (get_stack(&base, &size) == 0) { - STACK_DIR_UPPER((void)(base = (char *)base + size), (void)0); + if (get_stack(&base, &size) == 0) { +# ifdef __APPLE__ + if (pthread_equal(th->thread_id, native_main_thread.id)) { + struct rlimit rlim; + if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur > size) { + size = (size_t)rlim.rlim_cur; + } + } +# endif + base = (char *)base + STACK_DIR_UPPER(+size, -size); } + else #endif + if (th) { + size = th->machine.stack_maxsize; + base = (char *)th->machine.stack_start - STACK_DIR_UPPER(0, size); + } else { return 0; } diff --git a/thread_win32.c b/thread_win32.c index 9f851867c8cbf2..aea3fc20ac7579 100644 --- a/thread_win32.c +++ b/thread_win32.c @@ -571,8 +571,8 @@ native_thread_init_stack(rb_thread_t *th) size = end - base; space = size / 5; if (space > 1024*1024) space = 1024*1024; - th->machine_stack_start = (VALUE *)end - 1; - th->machine_stack_maxsize = size - space; + th->machine.stack_start = (VALUE *)end - 1; + th->machine.stack_maxsize = size - space; } #ifndef InterlockedExchangePointer @@ -600,7 +600,7 @@ thread_start_func_1(void *th_ptr) thread_debug("thread created (th: %p, thid: %p, event: %p)\n", th, th->thread_id, th->native_thread_data.interrupt_event); - thread_start_func_2(th, th->machine_stack_start, rb_ia64_bsp()); + thread_start_func_2(th, th->machine.stack_start, rb_ia64_bsp()); w32_close_handle(thread_id); thread_debug("thread deleted (th: %p)\n", th); @@ -754,6 +754,18 @@ ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr) return rb_thread_raised_p(th, RAISED_STACKOVERFLOW); } +#if defined(__MINGW32__) +LONG WINAPI +rb_w32_stack_overflow_handler(struct _EXCEPTION_POINTERS *exception) +{ + if (exception->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + rb_thread_raised_set(GET_THREAD(), RAISED_STACKOVERFLOW); + raise(SIGSEGV); + } + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + #ifdef RUBY_ALLOCA_CHKSTK void ruby_alloca_chkstk(size_t len, void *sp) diff --git a/time.c b/time.c index c01ca743d59a02..5ad1035c4deb99 100644 --- a/time.c +++ b/time.c @@ -2350,6 +2350,10 @@ time_timespec(VALUE num, int interval) d = modf(RFLOAT_VALUE(num), &f); if (d >= 0) { t.tv_nsec = (int)(d*1e9+0.5); + if (t.tv_nsec >= 1000000000) { + t.tv_nsec -= 1000000000; + f += 1; + } } else if ((t.tv_nsec = (int)(-d*1e9+0.5)) > 0) { t.tv_nsec = 1000000000 - t.tv_nsec; @@ -4805,7 +4809,9 @@ end_submicro: ; time_fixoff(time); } if (!NIL_P(zone)) { + zone = rb_str_new_frozen(zone); tobj->vtm.zone = RSTRING_PTR(zone); + rb_ivar_set(time, id_zone, zone); } return time; diff --git a/tool/file2lastrev.rb b/tool/file2lastrev.rb index 56e1b9f512a836..616c5f7fe446a6 100755 --- a/tool/file2lastrev.rb +++ b/tool/file2lastrev.rb @@ -31,6 +31,9 @@ def self.output=(output) opts.on("--doxygen", "Doxygen format") do self.output = :doxygen end + opts.on("--modified", "modified time") do + self.output = :modified + end opts.on("-q", "--suppress_not_found") do @suppress_not_found = true end @@ -44,7 +47,7 @@ def self.output=(output) abort "#{File.basename(Program)}: #{e.message}" unless @suppress_not_found else begin - last, changed = vcs.get_revisions(ARGV.shift) + last, changed, modified = vcs.get_revisions(ARGV.shift) rescue => e abort "#{File.basename(Program)}: #{e.message}" unless @suppress_not_found exit false @@ -58,6 +61,8 @@ def self.output=(output) puts "#define RUBY_REVISION #{changed.to_i}" when :doxygen puts "r#{changed}/r#{last}" +when :modified + puts modified.strftime('%Y-%m-%dT%H:%M:%S%z') else raise "unknown output format `#{@output}'" end diff --git a/tool/vcs.rb b/tool/vcs.rb index dbde58545ee868..cc744ca5ae8b89 100644 --- a/tool/vcs.rb +++ b/tool/vcs.rb @@ -1,7 +1,5 @@ # vcs -require 'time' - ENV.delete('PWD') unless File.respond_to? :realpath @@ -45,7 +43,11 @@ def get_revisions(path) last, changed, modified, *rest = Dir.chdir(@srcdir) {self.class.get_revisions(path)} last or raise VCS::NotFoundError, "last revision not found" changed or raise VCS::NotFoundError, "changed revision not found" - modified &&= Time.parse(modified) + if modified + /\A(\d+)-(\d+)-(\d+)\D(\d+):(\d+):(\d+(?:\.\d+)?)\s*(?:Z|([-+]\d\d)(\d\d))\z/ =~ modified or + raise "unknown time format - #{modified}" + modified = Time.mktime(*($~[1..6] + [$7 ? "#{$7}:#{$8}" : "+00:00"])) + end return last, changed, modified, *rest end @@ -96,16 +98,16 @@ class GIT < self register(".git") def self.get_revisions(path) - logcmd = %Q[git log -n1 --grep="^ *git-svn-id: .*@[0-9][0-9]* "] + logcmd = %Q[git log -n1 --date=iso --grep="^ *git-svn-id: .*@[0-9][0-9]* "] idpat = /git-svn-id: .*?@(\d+) \S+\Z/ last = `#{logcmd}`[idpat, 1] if path log = `#{logcmd} "#{path}"` changed = log[idpat, 1] - modified = `git log --format=%ai -- #{path}` else changed = last end + modified = log[/^Date:\s+(.*)/, 1] [last, changed, modified] end end diff --git a/variable.c b/variable.c index e53dc8207fd397..e0d0eded8299b9 100644 --- a/variable.c +++ b/variable.c @@ -1518,7 +1518,7 @@ const_missing(VALUE klass, ID id) VALUE rb_mod_const_missing(VALUE klass, VALUE name) { - rb_frame_pop(); /* pop frame for "const_missing" */ + rb_vm_pop_cfunc_frame(); uninitialized_constant(klass, rb_to_id(name)); UNREACHABLE; diff --git a/version.h b/version.h index 5702aec34c0701..848444ea88494c 100644 --- a/version.h +++ b/version.h @@ -1,10 +1,10 @@ -#define RUBY_VERSION "2.1.2" -#define RUBY_RELEASE_DATE "2014-05-08" -#define RUBY_PATCHLEVEL 95 +#define RUBY_VERSION "2.1.3" +#define RUBY_RELEASE_DATE "2014-09-19" +#define RUBY_PATCHLEVEL 242 #define RUBY_RELEASE_YEAR 2014 -#define RUBY_RELEASE_MONTH 5 -#define RUBY_RELEASE_DAY 8 +#define RUBY_RELEASE_MONTH 9 +#define RUBY_RELEASE_DAY 19 #include "ruby/version.h" diff --git a/vm.c b/vm.c index 947b1811e500ac..c82a00e5a234a5 100644 --- a/vm.c +++ b/vm.c @@ -277,6 +277,41 @@ vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp) return 0; } +void +rb_vm_pop_cfunc_frame(void) +{ + rb_thread_t *th = GET_THREAD(); + const rb_method_entry_t *me = th->cfp->me; + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil); + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); + vm_pop_frame(th); +} + +void +rb_vm_rewind_cfp(rb_thread_t *th, rb_control_frame_t *cfp) +{ + /* check skipped frame */ + while (th->cfp != cfp) { +#if VMDEBUG + printf("skipped frame: %s\n", vm_frametype_name(th->cfp)); +#endif + if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_CFUNC) { + vm_pop_frame(th); + } + else { /* unlikely path */ + rb_vm_pop_cfunc_frame(); + } + } +} + +/* obsolete */ +void +rb_frame_pop(void) +{ + rb_thread_t *th = GET_THREAD(); + vm_pop_frame(th); +} + /* at exit */ void @@ -699,15 +734,17 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, const rb_block_t *blockptr, const NODE *cref, VALUE defined_class) { - if (SPECIAL_CONST_P(block->iseq)) + if (SPECIAL_CONST_P(block->iseq)) { return Qnil; + } else if (BUILTIN_TYPE(block->iseq) != T_NODE) { + VALUE ret; const rb_iseq_t *iseq = block->iseq; const rb_control_frame_t *cfp; int i, opt_pc, arg_size = iseq->arg_size; - int type = block_proc_is_lambda(block->proc) ? - VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK; - + int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK; + const rb_method_entry_t *me = th->passed_bmethod_me; + th->passed_bmethod_me = 0; cfp = th->cfp; for (i=0; isp, blockptr, type == VM_FRAME_MAGIC_LAMBDA); - vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH, - self, defined_class, - VM_ENVVAL_PREV_EP_PTR(block->ep), - iseq->iseq_encoded + opt_pc, - cfp->sp + arg_size, iseq->local_size - arg_size, - th->passed_me, iseq->stack_max); - th->passed_me = 0; + if (me != 0) { + /* bmethod */ + vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD, + self, defined_class, + VM_ENVVAL_PREV_EP_PTR(block->ep), + iseq->iseq_encoded + opt_pc, + cfp->sp + arg_size, iseq->local_size - arg_size, + me, iseq->stack_max); + + RUBY_DTRACE_METHOD_ENTRY_HOOK(th, me->klass, me->called_id); + EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->called_id, me->klass, Qnil); + } + else { + vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH, + self, defined_class, + VM_ENVVAL_PREV_EP_PTR(block->ep), + iseq->iseq_encoded + opt_pc, + cfp->sp + arg_size, iseq->local_size - arg_size, + 0, iseq->stack_max); + } if (cref) { th->cfp->ep[-1] = (VALUE)cref; } - return vm_exec(th); + ret = vm_exec(th); + + if (me) { + /* bmethod */ + EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->called_id, me->klass, ret); + RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id); + } + + return ret; } else { return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr); @@ -1185,6 +1243,7 @@ vm_frametype_name(const rb_control_frame_t *cfp) case VM_FRAME_MAGIC_IFUNC: return "ifunc"; case VM_FRAME_MAGIC_EVAL: return "eval"; case VM_FRAME_MAGIC_LAMBDA: return "lambda"; + case VM_FRAME_MAGIC_RESCUE: return "rescue"; default: rb_bug("unknown frame"); } @@ -1489,7 +1548,7 @@ vm_exec(rb_thread_t *th) /* push block frame */ cfp->sp[0] = err; - vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK, + vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE, cfp->self, cfp->klass, VM_ENVVAL_PREV_EP_PTR(cfp->ep), catch_iseq->iseq_encoded, @@ -1512,7 +1571,13 @@ vm_exec(rb_thread_t *th) break; case VM_FRAME_MAGIC_BLOCK: case VM_FRAME_MAGIC_LAMBDA: - EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil); + if (VM_FRAME_TYPE_BMETHOD_P(th->cfp)) { + EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil); + EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, th->cfp->me->called_id, th->cfp->me->klass, Qnil); + } + else { + EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil); + } break; case VM_FRAME_MAGIC_CLASS: EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_END, th->cfp->self, 0, 0, Qnil); @@ -1966,11 +2031,11 @@ rb_thread_mark(void *ptr) rb_mark_tbl(th->local_storage); - if (GET_THREAD() != th && th->machine_stack_start && th->machine_stack_end) { + if (GET_THREAD() != th && th->machine.stack_start && th->machine.stack_end) { rb_gc_mark_machine_stack(th); - rb_gc_mark_locations((VALUE *)&th->machine_regs, - (VALUE *)(&th->machine_regs) + - sizeof(th->machine_regs) / sizeof(VALUE)); + rb_gc_mark_locations((VALUE *)&th->machine.regs, + (VALUE *)(&th->machine.regs) + + sizeof(th->machine.regs) / sizeof(VALUE)); } rb_vm_trace_mark_event_hooks(&th->event_hooks); @@ -2227,46 +2292,62 @@ m_core_set_postexe(VALUE self) return Qnil; } +static VALUE core_hash_merge_ary(VALUE hash, VALUE ary); +static VALUE core_hash_from_ary(VALUE ary); +static VALUE core_hash_merge_kwd(int argc, VALUE *argv); + +static VALUE +core_hash_merge(VALUE hash, long argc, const VALUE *argv) +{ + long i; + + assert(argc % 2 == 0); + for (i=0; iflag & VM_FRAME_MAGIC_MASK) /* other frame flag */ -#define VM_FRAME_FLAG_PASSED 0x0100 -#define VM_FRAME_FLAG_FINISH 0x0200 -#define VM_FRAME_TYPE_FINISH_P(cfp) (((cfp)->flag & VM_FRAME_FLAG_FINISH) != 0) +#define VM_FRAME_FLAG_PASSED 0x0100 +#define VM_FRAME_FLAG_FINISH 0x0200 +#define VM_FRAME_FLAG_BMETHOD 0x0400 +#define VM_FRAME_TYPE_FINISH_P(cfp) (((cfp)->flag & VM_FRAME_FLAG_FINISH) != 0) +#define VM_FRAME_TYPE_BMETHOD_P(cfp) (((cfp)->flag & VM_FRAME_FLAG_BMETHOD) != 0) #define RUBYVM_CFUNC_FRAME_P(cfp) \ (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC) @@ -882,6 +887,7 @@ VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method); void rb_vm_stack_to_heap(rb_thread_t *th); void ruby_thread_init_stack(rb_thread_t *th); int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp); +void rb_vm_rewind_cfp(rb_thread_t *th, rb_control_frame_t *cfp); void rb_gc_mark_machine_stack(rb_thread_t *th); @@ -1028,6 +1034,9 @@ void rb_threadptr_exec_event_hooks_and_pop_frame(struct rb_trace_arg_struct *tra #define EXEC_EVENT_HOOK_AND_POP_FRAME(th_, flag_, self_, id_, klass_, data_) \ EXEC_EVENT_HOOK_ORIG(th_, flag_, self_, id_, klass_, data_, 1) +VALUE rb_threadptr_reset_recursive_data(rb_thread_t *th); +void rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old); + RUBY_SYMBOL_EXPORT_BEGIN int rb_thread_check_trap_pending(void); diff --git a/vm_dump.c b/vm_dump.c index f691e5afeae1fd..6caea9f5a57012 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -73,6 +73,9 @@ control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp) case VM_FRAME_MAGIC_EVAL: magic = "EVAL"; break; + case VM_FRAME_MAGIC_RESCUE: + magic = "RESCUE"; + break; case 0: magic = "------"; break; @@ -268,15 +271,17 @@ vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp) /* stack trace header */ - if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD || - VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP || + if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD|| + VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS || - VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC || - VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA || + VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC || + VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA|| VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC || - VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL) { + VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL || + VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_RESCUE) + { VALUE *ptr = ep - local_size; diff --git a/vm_eval.c b/vm_eval.c index c7d6f7331399ce..cb0e637942d07a 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -686,7 +686,7 @@ raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj, { exc = make_no_method_exception(exc, format, obj, argc, argv); if (!(last_call_status & NOEX_MISSING)) { - th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); + rb_vm_pop_cfunc_frame(); } rb_exc_raise(exc); } @@ -1089,19 +1089,7 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, th->errinfo = Qnil; retval = GET_THROWOBJ_VAL(err); - /* check skipped frame */ - while (th->cfp != cfp) { -#if VMDEBUG - printf("skipped frame: %s\n", vm_frametype_name(th->cfp)); -#endif - if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) { - const rb_method_entry_t *me = th->cfp->me; - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil); - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); - } - - th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); - } + rb_vm_rewind_cfp(th, cfp); } else{ /* SDR(); printf("%p, %p\n", cdfp, escape_dfp); */ @@ -1112,10 +1100,11 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, VALUE *cep = cfp->ep; if (cep == escape_ep) { + rb_vm_rewind_cfp(th, cfp); + state = 0; th->state = 0; th->errinfo = Qnil; - th->cfp = cfp; goto iter_retry; } } @@ -1218,14 +1207,15 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *const cref_arg, VALUE absolute_path = Qnil; VALUE fname; + if (file != Qundef) { + absolute_path = file; + } + if (scope != Qnil) { bind = Check_TypedStruct(scope, &ruby_binding_data_type); { envval = bind->env; - if (file != Qundef) { - absolute_path = file; - } - else if (!NIL_P(bind->path)) { + if (NIL_P(absolute_path) && !NIL_P(bind->path)) { file = bind->path; line = bind->first_lineno; absolute_path = rb_current_realfilepath(); @@ -1858,7 +1848,7 @@ rb_catch_protect(VALUE t, rb_block_call_func *func, VALUE data, int *stateptr) val = (*func)(tag, data, 1, (const VALUE *)&tag, Qnil); } else if (state == TAG_THROW && RNODE(th->errinfo)->u1.value == tag) { - th->cfp = saved_cfp; + rb_vm_rewind_cfp(th, saved_cfp); val = th->tag->retval; th->errinfo = Qnil; state = 0; diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 1228b3f4df6976..f52a8f562d7b6c 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1067,10 +1067,15 @@ vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_inf } static inline int -vm_callee_setup_keyword_arg(const rb_iseq_t *iseq, int argc, int m, VALUE *orig_argv, VALUE *kwd) +vm_callee_setup_keyword_arg(rb_thread_t *th, const rb_iseq_t *iseq, int argc, int m, VALUE *orig_argv, VALUE *kwd) { VALUE keyword_hash = 0, orig_hash; int optional = iseq->arg_keywords - iseq->arg_keyword_required; + VALUE *const sp = th->cfp->sp; + const int mark_stack_len = th->mark_stack_len; + + th->cfp->sp += argc; + th->mark_stack_len -= argc; if (argc > m && !NIL_P(orig_hash = rb_check_hash_type(orig_argv[argc-1])) && @@ -1085,10 +1090,14 @@ vm_callee_setup_keyword_arg(const rb_iseq_t *iseq, int argc, int m, VALUE *orig_ rb_get_kwargs(keyword_hash, iseq->arg_keyword_table, iseq->arg_keyword_required, (iseq->arg_keyword_check ? optional : -1-optional), NULL); + if (!keyword_hash) { keyword_hash = rb_hash_new(); } + th->cfp->sp = sp; + th->mark_stack_len = mark_stack_len; + *kwd = keyword_hash; return argc; @@ -1111,7 +1120,7 @@ vm_callee_setup_arg_complex(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t /* keyword argument */ if (iseq->arg_keyword != -1) { - argc = vm_callee_setup_keyword_arg(iseq, argc, min, orig_argv, &keyword_hash); + argc = vm_callee_setup_keyword_arg(th, iseq, argc, min, orig_argv, &keyword_hash); } /* mandatory */ @@ -1196,23 +1205,33 @@ static VALUE vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_c static inline VALUE vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); static inline VALUE vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci); -#define VM_CALLEE_SETUP_ARG(th, ci, iseq, argv, is_lambda) \ - if (LIKELY((iseq)->arg_simple & 0x01)) { \ - /* simple check */ \ - if ((ci)->argc != (iseq)->argc) { \ - argument_error((iseq), ((ci)->argc), (iseq)->argc, (iseq)->argc); \ - } \ - (ci)->aux.opt_pc = 0; \ - CI_SET_FASTPATH((ci), UNLIKELY((ci)->flag & VM_CALL_TAILCALL) ? vm_call_iseq_setup_tailcall : vm_call_iseq_setup_normal, !(is_lambda) && !((ci)->me->flag & NOEX_PROTECTED)); \ - } \ - else { \ - (ci)->aux.opt_pc = vm_callee_setup_arg_complex((th), (ci), (iseq), (argv)); \ +static inline void +vm_callee_setup_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, + VALUE *argv, int is_lambda) +{ + if (LIKELY(iseq->arg_simple & 0x01)) { + /* simple check */ + if (ci->argc != iseq->argc) { + argument_error(iseq, ci->argc, iseq->argc, iseq->argc); + } + ci->aux.opt_pc = 0; + CI_SET_FASTPATH(ci, + (UNLIKELY(ci->flag & VM_CALL_TAILCALL) ? + vm_call_iseq_setup_tailcall : + vm_call_iseq_setup_normal), + (!is_lambda && + !(ci->flag & VM_CALL_ARGS_SPLAT) && /* argc may differ for each calls */ + !(ci->me->flag & NOEX_PROTECTED))); + } + else { + ci->aux.opt_pc = vm_callee_setup_arg_complex(th, ci, iseq, argv); } +} static VALUE vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) { - VM_CALLEE_SETUP_ARG(th, ci, ci->me->def->body.iseq, cfp->sp - ci->argc, 0); + vm_callee_setup_arg(th, ci, ci->me->def->body.iseq, cfp->sp - ci->argc, 0); return vm_call_iseq_setup_2(th, cfp, ci); } @@ -1583,17 +1602,11 @@ vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv) rb_proc_t *proc; VALUE val; - RUBY_DTRACE_METHOD_ENTRY_HOOK(th, ci->me->klass, ci->me->called_id); - EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, ci->recv, ci->me->called_id, ci->me->klass, Qnil); - /* control block frame */ - th->passed_me = ci->me; + th->passed_bmethod_me = ci->me; GetProcPtr(ci->me->def->body.proc, proc); val = vm_invoke_proc(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr); - EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, ci->recv, ci->me->called_id, ci->me->klass, val); - RUBY_DTRACE_METHOD_RETURN_HOOK(th, ci->me->klass, ci->me->called_id); - return val; } @@ -1778,6 +1791,10 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) klass = RCLASS_ORIGIN(klass); zsuper_method_dispatch: klass = RCLASS_SUPER(klass); + if (!klass) { + ci->me = 0; + goto start_method_dispatch; + } ci_temp = *ci; ci = &ci_temp; @@ -2002,6 +2019,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf } if (BUILTIN_TYPE(current_defined_class) != T_MODULE && + BUILTIN_TYPE(current_defined_class) != T_ICLASS && /* bound UnboundMethod */ !FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) && !rb_obj_is_kind_of(ci->recv, current_defined_class)) { VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ? @@ -2009,8 +2027,8 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf rb_raise(rb_eTypeError, "self has wrong type to call super in this context: " - "%s (expected %s)", - rb_obj_classname(ci->recv), rb_class2name(m)); + "%"PRIsVALUE" (expected %"PRIsVALUE")", + rb_obj_class(ci->recv), m); } switch (vm_search_superclass(GET_CFP(), iseq, sigval, ci)) { @@ -2207,7 +2225,7 @@ vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, /* keyword argument */ if (iseq->arg_keyword != -1) { - argc = vm_callee_setup_keyword_arg(iseq, argc, min, argv, &keyword_hash); + argc = vm_callee_setup_keyword_arg(th, iseq, argc, min, argv, &keyword_hash); } for (i=argc; iklass, T_ICLASS)) - defined_class = me->klass; + if (me && me->klass) { + switch (BUILTIN_TYPE(me->klass)) { + case T_CLASS: + if (RBASIC(klass)->flags & FL_SINGLETON) break; + /* fall through */ + case T_ICLASS: + defined_class = me->klass; + } + } if (ruby_running) { struct rb_classext_struct *ext = RCLASS_EXT(klass); diff --git a/vm_trace.c b/vm_trace.c index 81452997e94c64..2047d5aec8d44e 100644 --- a/vm_trace.c +++ b/vm_trace.c @@ -335,6 +335,7 @@ rb_threadptr_exec_event_hooks_orig(rb_trace_arg_t *trace_arg, int pop_p) trace_arg->self != rb_mRubyVMFrozenCore /* skip special methods. TODO: remove it. */) { const VALUE errinfo = th->errinfo; const int outer_state = th->state; + const VALUE old_recursive = rb_threadptr_reset_recursive_data(th); int state = 0; th->state = 0; th->errinfo = Qnil; @@ -355,6 +356,7 @@ rb_threadptr_exec_event_hooks_orig(rb_trace_arg_t *trace_arg, int pop_p) terminate: th->trace_arg = 0; th->vm->trace_running--; + rb_threadptr_restore_recursive_data(th, old_recursive); if (state) { if (pop_p) { diff --git a/vsnprintf.c b/vsnprintf.c index 5266927d7fb3b9..f272d73337327f 100644 --- a/vsnprintf.c +++ b/vsnprintf.c @@ -999,7 +999,7 @@ fp_begin: _double = va_arg(ap, double); */ const char *p = (char *)memchr(cp, 0, prec); - if (p != NULL && (p - cp) > prec) + if (p != NULL && (p - cp) < prec) size = (int)(p - cp); else size = prec; diff --git a/win32/win32.c b/win32/win32.c index 2c888ae4c4a192..3051a97f569050 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -1197,8 +1197,8 @@ is_batch(const char *cmd) } static UINT filecp(void); -static WCHAR *mbstr_to_wstr(UINT, const char *, int, long *); -static char *wstr_to_mbstr(UINT, const WCHAR *, int, long *); +#define mbstr_to_wstr rb_w32_mbstr_to_wstr +#define wstr_to_mbstr rb_w32_wstr_to_mbstr #define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen) #define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen) #define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen) @@ -1952,8 +1952,8 @@ filecp(void) } /* License: Ruby's */ -static char * -wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen) +char * +rb_w32_wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen) { char *ptr; int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL); @@ -1968,8 +1968,8 @@ wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen) } /* License: Ruby's */ -static WCHAR * -mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen) +WCHAR * +rb_w32_mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen) { WCHAR *ptr; int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0); @@ -3017,6 +3017,7 @@ rb_w32_accept(int s, struct sockaddr *addr, int *addrlen) if (fd != -1) { r = accept(TO_SOCKET(s), addr, addrlen); if (r != INVALID_SOCKET) { + SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0); MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); _set_osfhnd(fd, r); MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); @@ -3557,6 +3558,8 @@ open_ifs_socket(int af, int type, int protocol) } if (out == INVALID_SOCKET) out = WSASocket(af, type, protocol, NULL, 0, 0); + if (out != INVALID_SOCKET) + SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0); } free(proto_buffers); @@ -3790,6 +3793,7 @@ socketpair_internal(int af, int type, int protocol, SOCKET *sv) r = accept(svr, addr, &len); if (r == INVALID_SOCKET) break; + SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0); ret = 0; } while (0); @@ -6958,6 +6962,19 @@ rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len) return numaddr; } +/* License: Ruby's */ +int WSAAPI +rb_w32_inet_pton(int af, const char *src, void *dst) +{ + typedef int (WSAAPI inet_pton_t)(int, const char*, void *); + inet_pton_t *pInetPton; + pInetPton = (inet_pton_t *)get_proc_address("ws2_32", "inet_pton", NULL); + if (pInetPton) { + return pInetPton(af, src, dst); + } + return 0; +} + /* License: Ruby's */ char rb_w32_fd_is_text(int fd)