Exemplo n.º 1
0
int output(lua_State* lua)
{
    void* luserdata = lua_touserdata(lua, lua_upvalueindex(1));
    if (NULL == luserdata) {
        lua_pushstring(lua, "output() invalid lightuserdata");
        lua_error(lua);
    }
    lua_sandbox* lsb = (lua_sandbox*)luserdata;

    int n = lua_gettop(lua);
    if (n == 0) {
        lua_pushstring(lua, "output() must have at least one argument");
        lua_error(lua);
    }

    int result = 0;
    void* ud = NULL;
    for (int i = 1; result == 0 && i <= n; ++i) {
        switch (lua_type(lua, i)) {
        case LUA_TNUMBER:
            if (dynamic_snprintf(&lsb->m_output, "%0.9g",
                                 lua_tonumber(lua, i))) {
                result = 1;
            }
            break;
        case LUA_TSTRING:
            if (dynamic_snprintf(&lsb->m_output, "%s", lua_tostring(lua, i))) {
                result = 1;
            }
            break;
        case LUA_TNIL:
            if (dynamic_snprintf(&lsb->m_output, "nil")) {
                result = 1;
            }
            break;
        case LUA_TUSERDATA:
            ud = lua_touserdata(lua, i);
            if (heka_circular_buffer == userdata_type(lua, ud, i)) {
                if (output_circular_buffer((circular_buffer*)ud,
                                           &lsb->m_output)) {
                    result = 1;
                }
            }
            break;
        }
    }
    lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT] = lsb->m_output.m_pos;
    if (lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT]
        > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_MAXIMUM]) {
        lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_MAXIMUM] =
          lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT];
    }
    if (result != 0
        || lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT]
        > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_LIMIT]) {
        lua_pushstring(lua, "output_limit exceeded");
        lua_error(lua);
    }
    return 0;
}
Exemplo n.º 2
0
int serialize_data(lua_sandbox* lsb, int index, output_data* output)
{
    output->m_pos = 0;
    switch (lua_type(lsb->m_lua, index)) {
    case LUA_TNUMBER:
        if (serialize_double(output, lua_tonumber(lsb->m_lua, index))) {
            return 1;
        }
        break;
    case LUA_TSTRING:
        // The stack is cleaned up on failure by preserve_global_data
        // but for clarity it is incrementally cleaned up anyway.
        lua_checkstack(lsb->m_lua, 4);
        lua_getglobal(lsb->m_lua, "string");
        if (!lua_istable(lsb->m_lua, -1)) {
            snprintf(lsb->m_error_message, ERROR_SIZE,
                     "serialize_data cannot access the string table");
            lua_pop(lsb->m_lua, 1); // Remove bogus string table.
            return 1;
        }
        lua_getfield(lsb->m_lua, -1, "format");
        if (!lua_isfunction(lsb->m_lua, -1)) {
            snprintf(lsb->m_error_message, ERROR_SIZE,
                     "serialize_data cannot access the string format function");
            lua_pop(lsb->m_lua, 2); // Remove the bogus format function and
                                    // string table.
            return 1;
        }
        lua_pushstring(lsb->m_lua, "%q");
        lua_pushvalue(lsb->m_lua, index - 3);
        if (lua_pcall(lsb->m_lua, 2, 1, 0) == 0) {
            if (dynamic_snprintf(output, "%s", lua_tostring(lsb->m_lua, -1))) {
                lua_pop(lsb->m_lua, 1); // Remove the string table.
                return 1;
            }
        } else {
            snprintf(lsb->m_error_message, ERROR_SIZE,
                     "serialize_data '%s'", lua_tostring(lsb->m_lua, -1));
            lua_pop(lsb->m_lua, 2); // Remove the error message and the string
                                    // table.
            return 1;
        }
        lua_pop(lsb->m_lua, 2); // Remove the pcall result and the string table.
        break;
    case LUA_TBOOLEAN:
        if (dynamic_snprintf(output, "%s",
                             lua_toboolean(lsb->m_lua, index)
                             ? "true" : "false")) {
            return 1;
        }
        break;
    default:
        snprintf(lsb->m_error_message, ERROR_SIZE,
                 "serialize_data cannot preserve type '%s'",
                 lua_typename(lsb->m_lua, lua_type(lsb->m_lua, index)));
        return 1;
    }
    return 0;
}
Exemplo n.º 3
0
int serialize_kvp_as_json(lua_sandbox* lsb,
                          serialization_data* data,
                          int isHash)
{
    static const char* array_start = "[", *array_end = "]";
    static const char* hash_start = "{", *hash_end = "}";
    int kindex = -2, vindex = -1, result = 0;

    if (ignore_value_type_json(lsb, vindex)) return 0;
    if (ignore_key(lsb, kindex)) return 0;
    if (isHash) {
        if (serialize_data_as_json(lsb, kindex, &lsb->m_output)) return 1;
        if (dynamic_snprintf(&lsb->m_output, ":")) return 1;
    }

    if (lua_type(lsb->m_lua, vindex) == LUA_TTABLE) {
        const void* ptr = lua_topointer(lsb->m_lua, vindex);
        table_ref* seen = find_table_ref(&data->m_tables, ptr);
        if (seen == NULL) {
            seen = add_table_ref(&data->m_tables, ptr, 0);
            if (seen != NULL) {
                const char* start, *end;
                lua_rawgeti(lsb->m_lua, vindex, 1);
                int hash = lua_isnil(lsb->m_lua, -1);
                lua_pop(lsb->m_lua, 1); // remove the test value
                if (hash) {
                    start = hash_start;
                    end = hash_end;
                } else {
                    start = array_start;
                    end = array_end;
                }
                if (dynamic_snprintf(&lsb->m_output, start)) return 1;
                if (serialize_table_as_json(lsb, data, hash)) return 1;
                if (dynamic_snprintf(&lsb->m_output, end)) return 1;
            } else {
                snprintf(lsb->m_error_message, ERROR_SIZE,
                         "serialize table out of memory");
                return 1;
            }
        } else {
            snprintf(lsb->m_error_message, ERROR_SIZE,
                     "table contains an internal or circular reference");
            return 1;
        }
    } else {
        result = serialize_data_as_json(lsb, vindex, &lsb->m_output);
    }
    return result;
}
Exemplo n.º 4
0
int serialize_table_as_json(lua_sandbox* lsb,
                            serialization_data* data,
                            int isHash)
{
    int result = 0;
    lua_checkstack(lsb->m_lua, 2);
    lua_pushnil(lsb->m_lua);
    int had_output = 0;
    size_t start = 0;
    while (result == 0 && lua_next(lsb->m_lua, -2) != 0) {
        if (had_output) {
            if (dynamic_snprintf(&lsb->m_output, ",")) return 1;
        }
        start = lsb->m_output.m_pos;
        result = serialize_kvp_as_json(lsb, data, isHash);
        lua_pop(lsb->m_lua, 1); // Remove the value leaving the key on top for
                                // the next interation.
        if (start != lsb->m_output.m_pos) {
            had_output = 1;
        } else {
            had_output = 0;
        }
    }
    if (start != 0 && had_output == 0) { // remove the trailing comma
        size_t reset_pos = start - 1;
        if (lsb->m_output.m_data[reset_pos] == ',') {
            lsb->m_output.m_data[reset_pos] = 0;
            lsb->m_output.m_pos = reset_pos;
        }
    }
    return result;
}
Exemplo n.º 5
0
int serialize_circular_buffer(const char* key, circular_buffer* cb, 
                              output_data* output)
{
    output->m_pos = 0;
    if (dynamic_snprintf(output, 
                         "if %s == nil then %s = circular_buffer.new(%d, %d, %d) end\n", 
                         key, 
                         key, 
                         cb->m_rows, 
                         cb->m_columns, 
                         cb->m_seconds_per_row)) {
        return 1;
    }

    unsigned column_idx;
    for (column_idx = 0; column_idx < cb->m_columns; ++column_idx) {
        if (dynamic_snprintf(output, "%s:set_header(%d, \"%s\", \"%s\")\n",
                             key, 
                             column_idx+1, 
                             cb->m_headers[column_idx].m_name,
                             column_type_names[cb->m_headers[column_idx].m_type])) {
            return 1;
        }
    }

    if (dynamic_snprintf(output, "%s:fromstring(\"%lld %d",
                         key,
                         cb->m_current_time, 
                         cb->m_current_row)) {
        return 1;
    }
    for (unsigned row_idx = 0; row_idx < cb->m_rows; ++row_idx) {
        for (column_idx = 0; column_idx < cb->m_columns; ++column_idx) {
            if (dynamic_snprintf(output, " %0.9g",
                                 cb->m_values[(row_idx * cb->m_columns) + column_idx])) {
                return 1;
            }
        }
    }
    if (dynamic_snprintf(output, "\")\n")) {
        return 1;
    }
    return 0;
}
Exemplo n.º 6
0
int preserve_global_data(lua_sandbox* lsb, const char* data_file)
{
    static const char* G = "_G";
    lua_getglobal(lsb->m_lua, G);
    if (!lua_istable(lsb->m_lua, -1)) {
        snprintf(lsb->m_error_message, ERROR_SIZE,
                 "preserve_global_data cannot access the global table");
        return 1;
    }

    FILE* fh = fopen(data_file, "wb");
    if (fh == NULL) {
        snprintf(lsb->m_error_message, ERROR_SIZE,
                 "preserve_global_data could not open: %s", data_file);
        return 1;
    }

    int result = 0;
    serialization_data data;
    data.m_fh = fh;
    data.m_keys.m_size = OUTPUT_SIZE;
    data.m_keys.m_pos = 0;
    data.m_keys.m_data = malloc(data.m_keys.m_size);
    data.m_tables.m_size = 64;
    data.m_tables.m_pos = 0;
    data.m_tables.m_array = malloc(data.m_tables.m_size * sizeof(table_ref));
    if (data.m_tables.m_array == NULL || data.m_keys.m_data == NULL) {
        snprintf(lsb->m_error_message, ERROR_SIZE,
                 "preserve_global_data out of memory");
        result = 1;
    } else {
        dynamic_snprintf(&data.m_keys, "%s", G);
        data.m_keys.m_pos += 1;
        data.m_globals = lua_topointer(lsb->m_lua, -1);
        lua_checkstack(lsb->m_lua, 2);
        lua_pushnil(lsb->m_lua);
        while (result == 0 && lua_next(lsb->m_lua, -2) != 0) {
            result = serialize_kvp(lsb, &data, 0);
            lua_pop(lsb->m_lua, 1);
        }
        lua_pop(lsb->m_lua, lua_gettop(lsb->m_lua));
        // Wipe the entire Lua stack.  Since incremental cleanup on failure
        // was added the stack should only contain table _G.
    }
    free(data.m_tables.m_array);
    free(data.m_keys.m_data);
    fclose(fh);
    if (result != 0) {
        remove(data_file);
    }
    return result;
}
Exemplo n.º 7
0
int serialize_kvp(lua_sandbox* lsb, serialization_data* data, size_t parent)
{
    int kindex = -2, vindex = -1;

    if (ignore_value_type(lsb, data, vindex)) return 0;
    int result = serialize_data(lsb, kindex, &lsb->m_output);
    if (result != 0) return result;

    size_t pos = data->m_keys.m_pos;
    if (dynamic_snprintf(&data->m_keys, "%s[%s]", data->m_keys.m_data + parent,
                         lsb->m_output.m_data)) {
        return 1;
    }

    fprintf(data->m_fh, "%s = ", data->m_keys.m_data + pos);
    if (lua_type(lsb->m_lua, vindex) == LUA_TTABLE) {
        const void* ptr = lua_topointer(lsb->m_lua, vindex);
        table_ref* seen = find_table_ref(&data->m_tables, ptr);
        if (seen == NULL) {
            seen = add_table_ref(&data->m_tables, ptr, pos);
            if (seen != NULL) {
                data->m_keys.m_pos += 1;
                fprintf(data->m_fh, "{}\n");
                result = serialize_table(lsb, data, pos);
            } else {
                snprintf(lsb->m_error_message, ERROR_SIZE,
                         "preserve table out of memory");
                return 1;
            }
        } else {
            data->m_keys.m_pos = pos;
            fprintf(data->m_fh, "%s\n", data->m_keys.m_data + seen->m_name_pos);
        }
    } else {
        data->m_keys.m_pos = pos;
        result = serialize_data(lsb, vindex, &lsb->m_output);
        if (result == 0) {
            fprintf(data->m_fh, "%s\n", lsb->m_output.m_data);
        }
    }
    return result;
}
Exemplo n.º 8
0
int output_circular_buffer(circular_buffer* cb, output_data* output)
{
    // output header
    if (dynamic_snprintf(output, 
                         "{\"time\":%d,\"rows\":%d,\"columns\":%d,\"seconds_per_row\":%d,\"column_info\":[",
                         cb->m_current_time - (cb->m_seconds_per_row * (cb->m_rows - 1)),
                         cb->m_rows,
                         cb->m_columns,
                         cb->m_seconds_per_row)) {
        return 1;
    }

    unsigned column_idx;
    for (column_idx = 0; column_idx < cb->m_columns; ++column_idx) {
        if (column_idx != 0) {
            if (dynamic_snprintf(output, ",")) return 1;
        }
        if (dynamic_snprintf(output, "{\"name\":\"%s\",\"type\":\"%s\"}", 
                             cb->m_headers[column_idx].m_name,
                             column_type_names[cb->m_headers[column_idx].m_type])) {
            return 1;
        }
    }
    if (dynamic_snprintf(output, "]}\n")) return 1;

    // output buffer data
    unsigned row_idx = cb->m_current_row + 1;
    for (unsigned i = 0; i < cb->m_rows; ++i, ++row_idx) {
        if (row_idx >= cb->m_rows) row_idx = 0;
        for (column_idx = 0; column_idx < cb->m_columns; ++column_idx) {
            if (column_idx != 0) {
                if (dynamic_snprintf(output, "\t")) return 1;
            }
            if (dynamic_snprintf(output, "%0.9g",
                                 cb->m_values[(row_idx * cb->m_columns) + column_idx])) {
                return 1;
            }
        }
        if (dynamic_snprintf(output, "\n")) return 1;
    }
    return 0;
}
Exemplo n.º 9
0
int output(lua_State* lua)
{
    void* luserdata = lua_touserdata(lua, lua_upvalueindex(1));
    if (NULL == luserdata) {
        luaL_error(lua, "output() invalid lightuserdata");
    }
    lua_sandbox* lsb = (lua_sandbox*)luserdata;

    int n = lua_gettop(lua);
    if (n == 0) {
        luaL_error(lua, "output() must have at least one argument");
    }

    int result = 0;
    void* ud = NULL;
    for (int i = 1; result == 0 && i <= n; ++i) {
        switch (lua_type(lua, i)) {
        case LUA_TNUMBER:
            if (serialize_double(&lsb->m_output, lua_tonumber(lua, i))) {
                result = 1;
            }
            break;
        case LUA_TSTRING:
            if (dynamic_snprintf(&lsb->m_output, "%s", lua_tostring(lua, i))) {
                result = 1;
            }
            break;
        case LUA_TNIL:
            if (dynamic_snprintf(&lsb->m_output, "nil")) {
                result = 1;
            }
            break;
        case LUA_TBOOLEAN:
            if (dynamic_snprintf(&lsb->m_output, "%s",
                                 lua_toboolean(lsb->m_lua, i)
                                 ? "true" : "false")) {
                result = 1;
            }
            break;
        case LUA_TTABLE:
            if (!dynamic_snprintf(&lsb->m_output, "{")) {
                serialization_data data;
                data.m_globals = NULL;
                data.m_tables.m_size = 64;
                data.m_tables.m_pos = 0;
                data.m_tables.m_array = malloc(data.m_tables.m_size * sizeof(table_ref));
                if (data.m_tables.m_array == NULL) {
                    snprintf(lsb->m_error_message, ERROR_SIZE,
                             "json table serialization out of memory");
                    result = 1;
                } else {
                    lua_checkstack(lsb->m_lua, 2);
                    lua_getfield(lsb->m_lua, i, "_name");
                    if (lua_type(lsb->m_lua, -1) != LUA_TSTRING) {
                        lua_pop(lsb->m_lua, 1); // remove the failed _name result
                        lua_pushstring(lsb->m_lua, "table"); // add default name
                    }
                    lua_pushvalue(lsb->m_lua, i);
                    result = serialize_kvp_as_json(lsb, &data, 1);
                    if (result == 0) {
                        result = dynamic_snprintf(&lsb->m_output, "}\n");
                    }
                    lua_pop(lsb->m_lua, 2); // remove the name and copy of the table
                    free(data.m_tables.m_array);
                }
            } else {
                result = 1;
            }
            break;
        case LUA_TUSERDATA:
            ud = lua_touserdata(lua, i);
            if (heka_circular_buffer == userdata_type(lua, ud, i)) {
                if (output_circular_buffer(lua, (circular_buffer*)ud,
                                           &lsb->m_output)) {
                    result = 1;
                }
            }
            break;
        }
    }
    update_output_stats(lsb);
    if (result != 0
        || lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT]
        > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_LIMIT]) {
        if (lsb->m_error_message[0] == 0) {
            luaL_error(lua, "output_limit exceeded");
        }
        luaL_error(lua, lsb->m_error_message);
    }
    return 0;
}
Exemplo n.º 10
0
int serialize_data_as_json(lua_sandbox* lsb, int index, output_data* output)
{
    const char* s;
    size_t len = 0;
    size_t start_pos = output->m_pos;
    size_t escaped_len = 0;
    switch (lua_type(lsb->m_lua, index)) {
    case LUA_TNUMBER:
        if (serialize_double(output, lua_tonumber(lsb->m_lua, index))) {
            return 1;
        }
        break;
    case LUA_TSTRING:
        s = lua_tolstring(lsb->m_lua, index, &len);
        escaped_len = len + 3; // account for the quotes and terminator
        for (size_t i = 0; i < len; ++i) {
            // buffer needs at least enough room for quotes, terminator, and an
            // escaped character
            if (output->m_pos + 5 > output->m_size) {
                size_t needed = escaped_len - (output->m_pos - start_pos);
                if (realloc_output(output, needed)) return 1;
            }
            if (i == 0) {
                output->m_data[output->m_pos++] = '"';
            }
            switch (s[i]) {
            case '"':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = '"';
                ++escaped_len;
                break;
            case '\\':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = '\\';
                ++escaped_len;
                break;
            case '/':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = '/';
                ++escaped_len;
                break;
            case '\b':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = 'b';
                ++escaped_len;
                break;
            case '\f':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = 'f';
                ++escaped_len;
                break;
            case '\n':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = 'n';
                ++escaped_len;
                break;
            case '\r':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = 'r';
                ++escaped_len;
                break;
            case '\t':
                output->m_data[output->m_pos++] = '\\';
                output->m_data[output->m_pos++] = 't';
                ++escaped_len;
                break;
            default:
                output->m_data[output->m_pos++] = s[i];
            }
        }
        output->m_data[output->m_pos++] = '"';
        output->m_data[output->m_pos] = 0;
        break;
    case LUA_TBOOLEAN:
        if (dynamic_snprintf(output, "%s",
                             lua_toboolean(lsb->m_lua, index)
                             ? "true" : "false")) {
            return 1;
        }
        break;
    default:
        snprintf(lsb->m_error_message, ERROR_SIZE,
                 "serialize_data_as_json cannot preserve type '%s'",
                 lua_typename(lsb->m_lua, lua_type(lsb->m_lua, index)));
        return 1;
    }
    return 0;
}
Exemplo n.º 11
0
int serialize_double(output_data* output, double d)
{
    if (d > INT_MAX) {
        return dynamic_snprintf(output, "%0.9g", d);
    }

    const int precision = 8;
    const unsigned magnitude = 100000000;
    char buffer[20];
    char* p = buffer;
    int negative = 0;

    if (d < 0) {
        negative = 1;
        d = -d;
    }

    int number = (int)d;
    double tmp = (d - number) * magnitude;
    unsigned fraction = (unsigned)tmp;
    double diff = tmp - fraction;

    if (diff > 0.5) {
        ++fraction;
        if (fraction >= magnitude) {
            fraction = 0;
            ++number;
        }
    } else if (diff == 0.5 && ((fraction == 0) || (fraction & 1))) {
        // bankers rounding
        ++fraction;
    }

    // output decimal fraction
    if (fraction != 0) {
        int nodigits = 1;
        char c = 0;
        for (int x = 0; x < precision; ++x) {
            c = fraction % 10;
            if (!(c == 0 && nodigits)) {
                *p++ = c + '0';
                nodigits = 0;
            }
            fraction /= 10;
        }
        *p++ = '.';
    }

    // output number
    do {
        *p++ = (number % 10) + '0';
        number /= 10;
    }
    while (number > 0);

    size_t remaining = output->m_size - output->m_pos;
    size_t len = (p - buffer) + negative;
    if (len >= remaining) {
        size_t newsize = output->m_size * 2;
        while (len >= newsize - output->m_pos) {
            newsize *= 2;
        }
        void* ptr = realloc(output->m_data, newsize);
        if (ptr == NULL) return 1;
        output->m_data = ptr;
        output->m_size = newsize;
    }

    if (negative) {
        output->m_data[output->m_pos++] = '-';
    }
    do {
        --p;
        output->m_data[output->m_pos++] = *p;
    }
    while (p != buffer);
    output->m_data[output->m_pos] = 0;

    return 0;
}