1. 11 Feb, 2016 13 commits
  2. 10 Feb, 2016 2 commits
  3. 05 Feb, 2016 3 commits
  4. 04 Feb, 2016 3 commits
  5. 03 Feb, 2016 1 commit
  6. 31 Jan, 2016 2 commits
  7. 30 Jan, 2016 3 commits
  8. 28 Jan, 2016 1 commit
  9. 27 Jan, 2016 1 commit
  10. 21 Jan, 2016 2 commits
    • Yukihiro "Matz" Matsumoto's avatar
      Merge pull request #3090 from kou/fix-segv-by-stack-extension-in-mrb-get-args · 2723b10a
      Yukihiro "Matz" Matsumoto authored
      Fix SEGV by stack extension in mrb_get_args()
      2723b10a
    • Kouhei Sutou's avatar
      Fix SEGV by stack extension in mrb_get_args() · c77123d2
      Kouhei Sutou authored
      mrb_get_args() keeps pointer of the current stack. But address of the
      current stack maybe changed by method call.
      
      'i' format character calls #to_i when the argument isn't integer but
      has #to_i.
      
      Here is a code that may call #to_i in mrb_get_args():
      
          case 'i':
            // ...
                  default:
                    *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i]));
                    break;
           // ...
      
      Here is a code #to_i is called:
      
          class X
            def initialize(i)
              @i = i
            end
      
            def to_i
              @i
            end
          end
      
          [][X.new(0), 0] # X#to_i is called
      
      So, mrb_get_args() shouldn't keep pointer and use it. mrb_get_args()
      should always refer mrb->ci->stack to use valid address of the current
      stack.
      c77123d2
  11. 20 Jan, 2016 3 commits
  12. 19 Jan, 2016 2 commits
    • Yukihiro "Matz" Matsumoto's avatar
      Merge pull request #3087 from kou/fix-segv-on-rerasing-no-memory-error · 17bd40a5
      Yukihiro "Matz" Matsumoto authored
      Fix SEGV on re-raising NoMemoryError
      17bd40a5
    • Kouhei Sutou's avatar
      Fix SEGV on re-raising NoMemoryError · 1d84b320
      Kouhei Sutou authored
      Think about the following Ruby script:
      
      segv.rb:
      
          begin
            lambda do
              lambda do
                "x" * 1000 # NoMemoryError
              end.call
            end.call
          rescue
            raise
          end
      
      If memory can't allocate after `"x" * 1000`, mruby crashes.
      
      Because L_RAISE: block in mrb_vm_exec() calls mrb_env_unshare() via
      cipop() and mrb_env_unshare() uses allocated memory without NULL check:
      
      L_RAISE: block:
      
          L_RAISE:
            // ...
            while (ci[0].ridx == ci[-1].ridx) {
              cipop(mrb);
              // ...
            }
      
      cipop():
      
          static void
          cipop(mrb_state *mrb)
          {
            struct mrb_context *c = mrb->c;
      
            if (c->ci->env) {
              mrb_env_unshare(mrb, c->ci->env);
            }
      
            c->ci--;
          }
      
      mrb_env_unshare():
      
          MRB_API void
          mrb_env_unshare(mrb_state *mrb, struct REnv *e)
          {
            size_t len = (size_t)MRB_ENV_STACK_LEN(e);
            // p is NULL in this case
            mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
      
            MRB_ENV_UNSHARE_STACK(e);
            if (len > 0) {
              stack_copy(p, e->stack, len); // p is NULL but used. It causes SEGV.
            }
            e->stack = p;
            mrb_write_barrier(mrb, (struct RBasic *)e);
          }
      
      To solve the SEGV, this change always raises NoMemoryError even when
      realloc() is failed after the first NoMemoryError in
      mrb_realloc(). mrb_unv_unshare() doesn't need to check NULL with this
      change.
      
      But it causes infinite loop in the following while:
      
          L_RAISE:
            // ...
            while (ci[0].ridx == ci[-1].ridx) {
              cipop(mrb);
              // ...
            }
      
      Because cipop() never pops ci.
      
      This change includes cipop() change. The change pops ci even when
      mrb_unv_unshare() is failed by NoMemoryError.
      
      This case can be reproduced by the following program:
      
          #include <stdlib.h>
          #include <mruby.h>
          #include <mruby/compile.h>
      
          static void *
          allocf(mrb_state *mrb, void *ptr, size_t size, void *ud)
          {
            static mrb_bool always_fail = FALSE;
      
            if (size == 1001) {
              always_fail = TRUE;
            }
            if (always_fail) {
              return NULL;
            }
      
            if (size == 0) {
              free(ptr);
              return NULL;
            } else {
              return realloc(ptr, size);
            }
          }
      
          int
          main(int argc, char **argv)
          {
            mrb_state *mrb;
            mrbc_context *c;
            FILE *file;
      
            mrb = mrb_open_allocf(allocf, NULL);
            c = mrbc_context_new(mrb);
            file = fopen(argv[1], "r");
            mrb_load_file_cxt(mrb, file, c);
            fclose(file);
            mrbc_context_free(mrb, c);
            mrb_close(mrb);
      
            return EXIT_SUCCESS;
          }
      
      Try the following command lines:
      
          % cc -I include -L build/host/lib -O0 -g3 -o no-memory no-memory.c -lmruby -lm
          % ./no-memory segv.rb
      1d84b320
  13. 18 Jan, 2016 2 commits
  14. 14 Jan, 2016 2 commits