lsb_err_value lsb_serialize_binary(lsb_output_buffer *ob, const void *src, size_t len)
{
  lsb_err_value ret = NULL;
  const char *uc = (const char *)src;
  for (unsigned i = 0; !ret && i < len; ++i) {
    switch (uc[i]) {
    case '\n':
      ret = lsb_outputs(ob, "\\n", 2);
      break;
    case '\r':
      ret = lsb_outputs(ob, "\\r", 2);
      break;
    case '"':
      ret = lsb_outputs(ob, "\\\"", 2);
      break;
    case '\\':
      ret = lsb_outputs(ob, "\\\\", 2);
      break;
    default:
      ret = lsb_outputc(ob, uc[i]);
      break;
    }
  }
  return ret;
}
lsb_err_value lsb_serialize_double(lsb_output_buffer *ob, double d)
{
  if (isnan(d)) {
    return lsb_outputs(ob, "0/0", 3);
  }
  if (d == INFINITY) {
    return lsb_outputs(ob, "1/0", 3);
  }
  if (d == -INFINITY) {
    return lsb_outputs(ob, "-1/0", 4);
  }
  return lsb_outputfd(ob, d);
}
Exemple #3
0
lsb_err_value lsb_outputd(lsb_output_buffer *b, double d)
{
  if (!b) return LSB_ERR_UTIL_NULL;

  if (isnan(d)) {
    return lsb_outputs(b, "nan", 3);
  }
  if (d == INFINITY) {
    return lsb_outputs(b, "inf", 3);
  }
  if (d == -INFINITY) {
    return lsb_outputs(b, "-inf", 4);
  }
  return lsb_outputfd(b, d);
}
static int
serialize_bloom_filter(lua_State *lua) {
  lsb_output_buffer* ob = lua_touserdata(lua, -1);
  const char *key = lua_touserdata(lua, -2);
  bloom_filter* bf = lua_touserdata(lua, -3);
  if (!(ob && key && bf)) {
    return 1;
  }
  if (lsb_outputf(ob,
                  "if %s == nil then %s = bloom_filter.new(%u, %g) end\n",
                  key,
                  key,
                  (unsigned)bf->items,
                  bf->probability)) {
    return 1;
  }

  if (lsb_outputf(ob, "%s:fromstring(%u, \"", key, (unsigned)bf->cnt)) {
    return 1;
  }
  if (lsb_serialize_binary(ob, bf->data, bf->bytes)) return 1;
  if (lsb_outputs(ob, "\")\n", 3)) {
    return 1;
  }
  return 0;
}
static int output_hyperloglog(lua_State *lua)
{
  lsb_output_buffer *ob = lua_touserdata(lua, -1);
  hyperloglog *hll = lua_touserdata(lua, -2);
  if (!(ob && hll)) return 1;
  if (lsb_outputs(ob, (const char *)hll, sizeof(hyperloglog) - 1)) return 1;
  return 0;
}
static int serialize_hyperloglog(lua_State *lua)
{
  lsb_output_buffer *ob = lua_touserdata(lua, -1);
  const char *key = lua_touserdata(lua, -2);
  hyperloglog *hll = lua_touserdata(lua, -3);
  if (!(ob && key && hll)) return 1;

  if (lsb_outputf(ob,
                  "if %s == nil then %s = hyperloglog.new() end\n", key, key)) {
    return 1;
  }

  if (lsb_outputf(ob, "%s:fromstring(\"", key)) return 1;
  if (lsb_serialize_binary(ob, hll, sizeof(hyperloglog) - 1)) return 1;
  if (lsb_outputs(ob, "\")\n", 3)) return 1;
  return 0;
}
lsb_err_value preserve_global_data(lsb_lua_sandbox *lsb)
{

  if (!lsb->lua || !lsb->state_file) {
    return NULL;
  }
  lua_sethook(lsb->lua, NULL, 0, 0);

  // make sure the string library is loaded before we start
  lua_getglobal(lsb->lua, LUA_STRLIBNAME);
  if (!lua_istable(lsb->lua, -1)) {
    lua_getglobal(lsb->lua, "require");
    if (!lua_iscfunction(lsb->lua, -1)) {
      snprintf(lsb->error_message, LSB_ERROR_SIZE,
               "preserve_global_data 'require' function not found");
      return LSB_ERR_LUA;
    }
    lua_pushstring(lsb->lua, LUA_STRLIBNAME);
    if (lua_pcall(lsb->lua, 1, 1, 0)) {
      int len = snprintf(lsb->error_message, LSB_ERROR_SIZE,
                         "preserve_global_data failed loading 'string'");
      if (len >= LSB_ERROR_SIZE || len < 0) {
        lsb->error_message[LSB_ERROR_SIZE - 1] = 0;
      }
      return LSB_ERR_LUA;
    }
  }
  lua_pop(lsb->lua, 1);

  lua_pushvalue(lsb->lua, LUA_GLOBALSINDEX);

  FILE *fh = fopen(lsb->state_file, "wb" CLOSE_ON_EXEC);
  if (fh == NULL) {
    int len = snprintf(lsb->error_message, LSB_ERROR_SIZE,
                       "preserve_global_data could not open: %s",
                       lsb->state_file);
    if (len >= LSB_ERROR_SIZE || len < 0) {
      lsb->error_message[LSB_ERROR_SIZE - 1] = 0;
    }
    return LSB_ERR_LUA;;
  }

  lsb_err_value ret = NULL;
  serialization_data data;
  data.fh = fh;

// Clear the sandbox limits during preservation.
#ifdef LUA_JIT
  lua_gc(lsb->lua, LUA_GCSETMEMLIMIT, 0);
#else
//  size_t limit = lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT];
  lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = 0;
#endif
//  size_t cur_output_size = lsb->output.size;
//  size_t max_output_size = lsb->output.maxsize;
  lsb->output.maxsize = 0;
// end clear

  data.tables.size = 64;
  data.tables.pos = 0;
  data.tables.array = malloc(data.tables.size * sizeof(table_ref));
  if (data.tables.array == NULL || lsb_init_output_buffer(&data.keys, 0)) {
    snprintf(lsb->error_message, LSB_ERROR_SIZE,
             "preserve_global_data out of memory");
    ret = LSB_ERR_UTIL_OOM;
  } else {
    fprintf(data.fh, "if %s and %s ~= %d then return end\n",
            preservation_version,
            preservation_version,
            get_preservation_version(lsb->lua));
    ret = lsb_outputs(&data.keys, "_G", 2);
    if (!ret) {
      data.keys.pos += 1; // preserve the NUL in this use case
      data.globals = lua_topointer(lsb->lua, -1);
      lua_checkstack(lsb->lua, 2);
      lua_pushnil(lsb->lua);
      while (!ret && lua_next(lsb->lua, -2) != 0) {
        ret = serialize_kvp(lsb, &data, 0);
        lua_pop(lsb->lua, 1);
      }
    }
    lua_pop(lsb->lua, lua_gettop(lsb->lua));
    // Wipe the entire Lua stack.  Since incremental cleanup on failure
    // was added the stack should only contain table _G.
  }
  free(data.tables.array);
  lsb_free_output_buffer(&data.keys);
  fclose(fh);
  if (ret) remove(lsb->state_file);

// Uncomment if we start preserving state when not destroying the sandbox
// Note: serialization uses the output buffer, inprogress output can be
// destroyed if the user was collecting output between calls.
/*
// Restore the sandbox limits after preservation
#ifdef LUA_JIT
  lua_gc(lsb->lua, LUA_GCSETMEMLIMIT,
         lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT]);
#else
  lua_gc(lsb->lua, LUA_GCCOLLECT, 0);
  lsb->usage[LSB_UT_MEMORY][LSB_US_LIMIT] = limit;
  lsb->usage[LSB_UT_MEMORY][LSB_US_MAXIMUM] =
    lsb->usage[LSB_UT_MEMORY][LSB_US_CURRENT];
#endif
  lsb->output.maxsize = max_output_size;
  lsb_clear_output_buffer(lsb->output);
  if (lsb->output.size > cur_output_size) {
    void* ptr = realloc(lsb->output.data, cur_output_size);
    if (!ptr) return 1;
    lsb->output.data = ptr;
    lsb->output.size = cur_output_size;
  }
// end restore
*/
  return ret;
}