Branch: Tag:

2018-03-30

2018-03-30 16:06:39 by Arne Goedeke <el@laramies.com>

Interpreter: fixed handling of SAVE_LOCALS bitmask

Since the introduction of save_locals_bitmask, expendible_offset was
never set. Also since the handling of expendible_offset and
save_locals_bitmask were handled by the same case, the code was broken.

During pop entries handling of the save_locals bitmask could lead
to situations where locals above expendible_offset were 'copied' into
the trampoline frame. Those locals could have already been popped from
the stack by the RETURN_LOCAL opcode.

Also slightly refactored the code to not allocate more space for locals
than needed and removed some unnecessary casts.

This became visible and could lead to crashes when building for 32bit
on 64bit x86 machines.

1056:    ); \    debug_malloc_touch (cc); \    UNSETJMP (cc->recovery); \ -  frame_set_expendible(Pike_fp, cc->save_expendible); \ +     Pike_interpreter.catch_ctx = cc->prev; \    really_free_catch_context (cc); \    } while (0)
1077:    ); \    debug_malloc_touch (cc); \    UNSETJMP (cc->recovery); \ -  frame_set_expendible(Pike_fp, cc->save_expendible); \ +     Pike_interpreter.catch_ctx = cc->prev; \    really_free_catch_context (cc); \    } while (0)
1205: Inside #if defined(PIKE_USE_MACHINE_CODE) and #if defined(OPCODE_INLINE_RETURN)
  #else    init_recovery (&new_catch_ctx->recovery, 0);   #endif -  new_catch_ctx->save_expendible = frame_get_expendible(Pike_fp); +     new_catch_ctx->continue_reladdr = (INT32)get_unaligned32(addr)    /* We need to run the entry prologue... */    - ENTRY_PROLOGUE_SIZE;
1218: Inside #if defined(PIKE_USE_MACHINE_CODE)
   });    }    -  Pike_fp->expendible_offset = Pike_fp->num_locals; -  +     /* Need to adjust next_addr by sizeof(INT32) to skip past the jump    * address to the continue position after the catch block. */    addr = (PIKE_OPCODE_T *) ((INT32 *) addr + 1);
1282: Inside #if defined(PIKE_USE_MACHINE_CODE)
      debug_malloc_touch_named (cc, "(3)");    UNSETJMP (cc->recovery); -  frame_set_expendible(Pike_fp, cc->save_expendible); +     move_svalue (Pike_sp++, &throw_value);    mark_free_svalue (&throw_value);    low_destruct_objects_to_destruct();
1337: Inside #if defined(OPCODE_INLINE_CATCH)
  #else    init_recovery (&new_catch_ctx->recovery, 0);   #endif -  new_catch_ctx->save_expendible = frame_get_expendible(Pike_fp); +        /* Note: no prologue. */    new_catch_ctx->continue_reladdr = (INT32)get_unaligned32(addr);
1350:    });    }    -  Pike_fp->expendible_offset = Pike_fp->num_locals; -  +     /* Need to adjust next_addr by sizeof(INT32) to skip past the jump    * address to the continue position after the catch block. */    return (PIKE_OPCODE_T *) ((INT32 *) addr + 1) + ENTRY_PROLOGUE_SIZE;
1375:       debug_malloc_touch_named (cc, "(3)");    UNSETJMP (cc->recovery); -  frame_set_expendible(Pike_fp, cc->save_expendible); +     move_svalue (Pike_sp++, &throw_value);    mark_free_svalue (&throw_value);    low_destruct_objects_to_destruct();
2036:    X->scope=0;    X->current_object=0;    X->flags=0; -  X->expendible_offset=0; +     X->locals=0;    );    X->next = free_pike_frame;
2088:      void LOW_POP_PIKE_FRAME_slow_path(struct pike_frame *frame)   { -  ptrdiff_t exp_offset = frame->expendible_offset; +     debug_malloc_touch(frame); -  if (exp_offset || (frame->flags & PIKE_FRAME_SAVE_LOCALS)) { +  +  if (frame->flags & PIKE_FRAME_SAVE_LOCALS) { +  int num_new_locals = 0; +  int num_locals = frame->num_locals; +  int i; +  +  /* find the highest set bit */ +  for (i = num_locals - 1; i >= 0; i--) { +  unsigned INT16 bitmask = frame->save_locals_bitmask[i / 16]; +  +  if (bitmask & (1 << (i % 16))) { +  num_new_locals = i + 1; +  break; +  } +  } +  +  if (num_new_locals) +  { +  struct svalue *s = xcalloc(sizeof(struct svalue), num_new_locals);    struct svalue *locals = frame->locals; -  struct svalue *s; -  INT16 num_new_locals = 0; -  unsigned int num_bitmask_entries = 0; -  if(frame->flags & PIKE_FRAME_SAVE_LOCALS) { -  ptrdiff_t offset; -  for (offset = 0; -  offset < (ptrdiff_t)((frame->num_locals >> 4) + 1); -  offset++) { -  if (*(frame->save_locals_bitmask + offset)) -  num_bitmask_entries = offset + 1; +  unsigned INT16 bitmask = 0; +  +  for (i = 0; i < num_new_locals; i++) { +  unsigned INT16 bitmask = frame->save_locals_bitmask[i / 16]; +  +  if (bitmask & (1 << (i % 16))) { +  assign_svalue_no_free(s + i, locals + i);    } -  } else { +    #ifdef PIKE_DEBUG -  if( (locals + frame->num_locals > Pike_sp) || -  (Pike_sp < locals + exp_offset) || -  (exp_offset < 0) || (exp_offset > frame->num_locals)) -  Pike_fatal("Stack failure in POP_PIKE_FRAME " -  "%p+%d=%p %p %hd!n", -  locals, frame->num_locals, -  locals + frame->num_locals, -  Pike_sp, exp_offset); +  else +  mark_free_svalue(s + i);   #endif    }    -  num_new_locals = MAXIMUM(exp_offset, num_bitmask_entries << 4); -  -  s=(struct svalue *)xalloc(sizeof(struct svalue)* -  num_new_locals); -  memset(s, 0, sizeof(struct svalue) * num_new_locals); -  -  { -  int idx; -  unsigned INT16 bitmask=0; -  -  for (idx = 0; idx < num_new_locals; idx++) { -  if (!(idx % 16)) { -  ptrdiff_t offset = (ptrdiff_t)(idx >> 4); -  if (offset < num_bitmask_entries) { -  bitmask = *(frame->save_locals_bitmask + offset); +  frame->locals = s; +  frame->flags |= PIKE_FRAME_MALLOCED_LOCALS;    } else { -  bitmask = 0; +  frame->locals = NULL;    } -  } -  if (bitmask & (1 << (idx % 16)) || idx < exp_offset) { -  assign_svalue_no_free(s + (ptrdiff_t)idx, -  locals + (ptrdiff_t)idx); -  } -  } -  } -  if(frame->flags & PIKE_FRAME_SAVE_LOCALS) { +     frame->flags &= ~PIKE_FRAME_SAVE_LOCALS; -  +     free(frame->save_locals_bitmask); -  } +     frame->num_locals = num_new_locals; -  frame->locals=s; -  frame->flags|=PIKE_FRAME_MALLOCED_LOCALS; +     } else { -  frame->locals=0; +  frame->locals = NULL;    } -  +     frame->next=0;   }   
2250:    new_frame->locals = save_sp;    new_frame->args = args;    new_frame->save_sp_offset = 0; -  new_frame->expendible_offset = 0; +       #ifdef PIKE_DEBUG    if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_FREE)
3013:    add_ref(new_frame->current_program = prog);    new_frame->context = prog->inherits;    new_frame->locals = Pike_sp; -  new_frame->expendible_offset=0; +     new_frame->args = 0;    new_frame->num_args=0;    new_frame->num_locals=0;