diff --git a/docs/docs.lua b/docs/docs.lua index 31821145..190fff01 100644 --- a/docs/docs.lua +++ b/docs/docs.lua @@ -4529,21 +4529,19 @@ local doc = { See [Constants][] for supported address `family` output values. ]], - returns = { - { - dict( - 'string', - table({ - { 'ip', 'string' }, - { 'family', 'string' }, - { 'netmask', 'string' }, - { 'internal', 'boolean' }, - { 'mac', 'string' }, - }) - ), - 'addresses', - }, - }, + returns = ret_or_fail( + dict( + 'string', + table({ + { 'ip', 'string' }, + { 'family', 'string' }, + { 'netmask', 'string' }, + { 'internal', 'boolean' }, + { 'mac', 'string' }, + }) + ), + 'addresses' + ), }, { name = 'if_indextoname', diff --git a/docs/docs.md b/docs/docs.md index 273d231c..2369eb2e 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -4208,7 +4208,7 @@ is an array of address information where fields are `ip`, `family`, `netmask`, See [Constants][] for supported address `family` output values. -**Returns:** `table` +**Returns:** `table` or `fail` - `[string]`: `table` - `ip`: `string` - `family`: `string` diff --git a/docs/meta.lua b/docs/meta.lua index d557b730..d7ceb94c 100644 --- a/docs/meta.lua +++ b/docs/meta.lua @@ -4281,7 +4281,9 @@ function uv.gettimeofday() end --- `internal`, and `mac`. --- --- See [Constants][] for supported address `family` output values. ---- @return table addresses +--- @return table? addresses +--- @return string? err +--- @return uv.error_name? err_name function uv.interface_addresses() end --- IPv6-capable implementation of `if_indextoname(3)`. diff --git a/src/async.c b/src/async.c index db25ce45..e8cea7b5 100644 --- a/src/async.c +++ b/src/async.c @@ -44,6 +44,11 @@ static int luv_new_async(lua_State* L) { } data = luv_setup_handle(L, ctx); data->extra = (luv_thread_arg_t*)malloc(sizeof(luv_thread_arg_t)); + if (!data->extra) { + handle->data = data; + uv_close((uv_handle_t*)handle, luv_handle_free); + return luaL_error(L, "Failed to allocate async args"); + } data->extra_gc = free; memset(data->extra, 0, sizeof(luv_thread_arg_t)); handle->data = data; diff --git a/src/fs.c b/src/fs.c index 82c87ba5..a2180873 100644 --- a/src/fs.c +++ b/src/fs.c @@ -543,6 +543,8 @@ static int luv_fs_read(lua_State* L) { offset = luaL_optinteger(L, 3, offset); ref = luv_check_continuation(L, 4); } + if (len < 0) + return luaL_error(L, "Length must be non-negative"); data = (char*)malloc(len); if (!data) { luaL_unref(L, LUA_REGISTRYINDEX, ref); diff --git a/src/handle.c b/src/handle.c index ceb5c019..f4b241ba 100644 --- a/src/handle.c +++ b/src/handle.c @@ -18,9 +18,12 @@ static void* luv_newuserdata(lua_State* L, size_t sz) { void* handle = malloc(sz); - if (handle) { - *(void**)lua_newuserdata(L, sizeof(void*)) = handle; + if (!handle) { + luaL_error(L, "out of memory"); + return NULL; // unreachable } + + *(void**)lua_newuserdata(L, sizeof(void*)) = handle; return handle; } diff --git a/src/lhandle.h b/src/lhandle.h index 0465d1d8..fb01b317 100644 --- a/src/lhandle.h +++ b/src/lhandle.h @@ -50,4 +50,6 @@ typedef struct { luv_handle_extra_gc extra_gc; } luv_handle_t; +static void luv_handle_free(uv_handle_t* handle); + #endif diff --git a/src/luv.h b/src/luv.h index 6a759bff..b5b014eb 100644 --- a/src/luv.h +++ b/src/luv.h @@ -93,7 +93,7 @@ typedef int (*luv_CFcpcall) (lua_State* L, lua_CFunction func, void* ud, int fla /* Default implementation of event callback */ LUALIB_API int luv_cfpcall(lua_State* L, int nargs, int nresult, int flags); -/* Default implementation of thread entory function */ +/* Default implementation of thread entry function */ LUALIB_API int luv_cfcpcall(lua_State* L, lua_CFunction func, void* ud, int flags); typedef struct { diff --git a/src/misc.c b/src/misc.c index ae1ea6a3..5b648e1f 100644 --- a/src/misc.c +++ b/src/misc.c @@ -65,12 +65,26 @@ static uv_buf_t* luv_prep_bufs(lua_State* L, int index, size_t *count, int **ref } *count = cnt; bufs = (uv_buf_t*)malloc(sizeof(uv_buf_t) * *count); + if (!bufs) luaL_error(L, "Failed to allocate buffer array"); int *refs_array = NULL; - if (refs) + if (refs) { refs_array = (int*)malloc(sizeof(int) * (*count + 1)); + if (!refs_array) { + free(bufs); + luaL_error(L, "Failed to allocate refs array"); + } + } for (i = 0; i < *count; ++i) { lua_rawgeti(L, index, i + 1); if (!lua_isstring(L, -1)) { + /* free already-accumulated refs and heap allocations before throwing */ + if (refs_array) { + size_t j; + for (j = 0; j < i; ++j) + luaL_unref(L, LUA_REGISTRYINDEX, refs_array[j]); + free(refs_array); + } + free(bufs); luaL_argerror(L, index, lua_pushfstring(L, "expected table of strings, found %s in the table", luaL_typename(L, -1))); return NULL; } @@ -105,6 +119,7 @@ static uv_buf_t* luv_check_bufs(lua_State* L, int index, size_t* count, luv_req_ else if (lua_isstring(L, index)) { *count = 1; bufs = (uv_buf_t*)malloc(sizeof(uv_buf_t)); + if (!bufs) luaL_error(L, "Failed to allocate buffer"); luv_prep_buf(L, index, bufs); lua_pushvalue(L, index); req_data->data_ref = luaL_ref(L, LUA_REGISTRYINDEX); @@ -125,6 +140,7 @@ static uv_buf_t* luv_check_bufs_noref(lua_State* L, int index, size_t* count) { else if (lua_isstring(L, index)) { *count = 1; bufs = (uv_buf_t*)malloc(sizeof(uv_buf_t)); + if (!bufs) luaL_error(L, "Failed to allocate buffer"); luv_prep_buf(L, index, bufs); } else { @@ -290,7 +306,8 @@ static int luv_interface_addresses(lua_State* L) { char ip[INET6_ADDRSTRLEN]; char netmask[INET6_ADDRSTRLEN]; - uv_interface_addresses(&interfaces, &count); + int ret = uv_interface_addresses(&interfaces, &count); + if (ret < 0) return luv_error(L, ret); lua_newtable(L); @@ -494,7 +511,14 @@ static int luv_os_getenv(lua_State* L) { const char* name = luaL_checkstring(L, 1); size_t size = luaL_optinteger(L, 2, LUAL_BUFFERSIZE); char *buff = malloc(size); + if (!buff) return luaL_error(L, "Failed to allocate env buffer"); int ret = uv_os_getenv(name, buff, &size); + if (ret == UV_ENOBUFS) { + /* size has been updated with the required length; reallocate and retry */ + buff = realloc(buff, size); + if (!buff) return luaL_error(L, "Failed to allocate env buffer"); + ret = uv_os_getenv(name, buff, &size); + } if (ret == 0) { lua_pushlstring(L, buff, size); ret = 1; @@ -550,7 +574,7 @@ static int luv_if_indextoname(lua_State* L) { size_t scoped_addr_len = sizeof(scoped_addr); unsigned int ifindex = (unsigned int)luaL_checkinteger(L, 1); - int ret = uv_if_indextoname(ifindex - 1, scoped_addr, &scoped_addr_len); + int ret = uv_if_indextoname(ifindex, scoped_addr, &scoped_addr_len); if (ret == 0) { lua_pushlstring(L, scoped_addr, scoped_addr_len); ret = 1; @@ -565,7 +589,7 @@ static int luv_if_indextoiid(lua_State* L) { size_t interface_id_len = sizeof(interface_id); unsigned int ifindex = (unsigned int)luaL_checkinteger(L, 1); - int ret = uv_if_indextoiid(ifindex - 1, interface_id, &interface_id_len); + int ret = uv_if_indextoiid(ifindex, interface_id, &interface_id_len); if (ret == 0) { lua_pushlstring(L, interface_id, interface_id_len); ret = 1; @@ -683,14 +707,17 @@ static int luv_os_environ(lua_State* L) { #endif static int luv_sleep(lua_State* L) { - unsigned int msec = luaL_checkinteger(L, 1); + int msec = luaL_checkinteger(L, 1); + if (msec < 0) + msec = 0; + #if LUV_UV_VERSION_GEQ(1, 34, 0) - uv_sleep(msec); + uv_sleep((unsigned int)msec); #else #ifdef _WIN32 - Sleep(msec); + Sleep((unsigned int)msec); #else - usleep(msec * 1000); + usleep((unsigned int)msec * 1000); #endif #endif return 0; @@ -824,7 +851,7 @@ static int luv_utf16_to_wtf8(lua_State *L) { sz = uv_utf16_length_as_wtf8(utf16, utf16_len); /* The wtf8_ptr must contain an extra space for an extra NUL after the result */ wtf8 = malloc(sz + 1); - if (wtf8 == NULL) return luaL_error(L, "failed to allocate %zu bytes", sz + 1); + if (wtf8 == NULL) return luaL_error(L, "out of memory"); /* Note: On success, *sz will not be modified */ ret = uv_utf16_to_wtf8(utf16, utf16_len, &wtf8, &sz); if (ret == 0) { @@ -852,7 +879,7 @@ static int luv_wtf8_to_utf16(lua_State *L) { const char* wtf8 = luaL_checklstring(L, 1, &sz); ssize_t ssz = uv_wtf8_length_as_utf16(wtf8); utf16 = malloc(ssz * 2); - if (utf16 == NULL) return luaL_error(L, "failed to allocate %zu bytes", ssz * 2); + if (utf16 == NULL) return luaL_error(L, "out of memory"); uv_wtf8_to_utf16(wtf8, utf16, ssz); /* The returned string includes a NUL terminator, but we use Lua style string */ lua_pushlstring(L, (const char*)utf16, (ssz-1) * 2); diff --git a/src/private.h b/src/private.h index b4ea7fba..6aa3fc42 100644 --- a/src/private.h +++ b/src/private.h @@ -1,3 +1,19 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ #ifndef LUV_PRIVATE_H #define LUV_PRIVATE_H diff --git a/src/process.c b/src/process.c index 3085b44a..127be3d1 100644 --- a/src/process.c +++ b/src/process.c @@ -64,7 +64,7 @@ static int sparse_rawlen(lua_State* L, int tbl) { tbl = lua_absindex(L, tbl); lua_pushnil(L); - while (lua_next(L, -2)) { + while (lua_next(L, tbl)) { if (lua_type(L, -2) == LUA_TNUMBER) { int idx = lua_tonumber(L, -2); if (floor(idx) == idx && idx >= 1) { @@ -198,6 +198,11 @@ static int luv_spawn(lua_State* L) { } for (i = 0; i < len; ++i) { lua_rawgeti(L, -1, i + 1); + if (!lua_isstring(L, -1)) { + luv_clean_options(L, &options, args_refs); + return luaL_argerror(L, 2, "env table entries must be strings"); + } + options.env[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } diff --git a/src/schema.c b/src/schema.c deleted file mode 100644 index e7b82e11..00000000 --- a/src/schema.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014 The Luvit Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ diff --git a/src/stream.c b/src/stream.c index 8b3da1df..639a6d91 100644 --- a/src/stream.c +++ b/src/stream.c @@ -99,7 +99,10 @@ static int luv_accept(lua_State* L) { static void luv_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { (void)handle; buf->base = (char*)malloc(suggested_size); - assert(buf->base); + if (!buf->base) { + buf->len = 0; + return; + } buf->len = suggested_size; } diff --git a/src/tcp.c b/src/tcp.c index e7a9792a..2c2734da 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -142,6 +142,8 @@ static void parse_sockaddr(lua_State* L, struct sockaddr_storage* address) { struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)address; uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, INET6_ADDRSTRLEN); port = ntohs(addrin6->sin6_port); + } else { + ip[0] = '\0'; } lua_pushstring(L, luv_af_num_to_string(addr->sa_family)); diff --git a/src/test.c b/src/test.c index 71e14f79..93fd05f7 100644 --- a/src/test.c +++ b/src/test.c @@ -1,3 +1,19 @@ +/* + * Copyright 2014 The Luvit Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ #include "luv.h" #include "util.h" #include "lhandle.h" diff --git a/src/thread.c b/src/thread.c index 32656cd9..fa48ed4f 100644 --- a/src/thread.c +++ b/src/thread.c @@ -95,6 +95,16 @@ static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int { const char* p = lua_tolstring(L, i, &arg->val.str.len); arg->val.str.base = malloc(arg->val.str.len); + if (!arg->val.str.base) { + for (int j = 0; j < i - idx; j++) { + luv_val_t* arg = args->argv + j; + if (arg->type == LUA_TSTRING && arg->ref[side] == LUA_NOREF) { + free((void*)arg->val.str.base); + } + } + + return luaL_error(L, "Failed to allocate thread arg string"); + } memcpy((void*)arg->val.str.base, p, arg->val.str.len); } else { arg->val.str.base = lua_tolstring(L, i, &arg->val.str.len); @@ -159,7 +169,7 @@ static void luv_thread_arg_clear(lua_State* L, luv_thread_arg_t* args, int flags lua_rawgeti(L, LUA_REGISTRYINDEX, arg->ref[side]); lua_pushnil(L); lua_setmetatable(L, -2); - lua_pop(L, -1); + lua_pop(L, 1); } luaL_unref(L, LUA_REGISTRYINDEX, arg->ref[side]); arg->ref[side] = LUA_NOREF; @@ -390,6 +400,7 @@ static int luv_new_thread(lua_State* L) { luv_thread_dumped(L, cbidx); len = lua_rawlen(L, -1); code = malloc(len); + if (!code) return luaL_error(L, "Failed to allocate thread code buffer"); memcpy(code, lua_tostring(L, -1), len); thread = (luv_thread_t*)lua_newuserdata(L, sizeof(*thread)); @@ -405,7 +416,6 @@ static int luv_new_thread(lua_State* L) { if (thread->argc < 0) { return luv_thread_arg_error(L); } - thread->len = len; thread->notify.data = thread; thread->ref = LUA_NOREF; diff --git a/src/udp.c b/src/udp.c index 36fcee46..fb122850 100644 --- a/src/udp.c +++ b/src/udp.c @@ -102,7 +102,12 @@ static int luv_new_udp(lua_State* L) { if (flags & UV_UDP_RECVMMSG) { // store the number of msgs to be received for use in alloc_cb int* extra_data = malloc(sizeof(int)); - assert(extra_data); + if (!extra_data) { + uv_close((uv_handle_t*)handle, NULL); + free(handle->data); + free(handle); + return luaL_error(L, "Failed to allocate UDP recvmmsg state"); + } *extra_data = mmsg_num_msgs; ((luv_handle_t*)handle->data)->extra = extra_data; ((luv_handle_t*)handle->data)->extra_gc = free; @@ -373,17 +378,35 @@ static int luv_udp_try_send2(lua_State* L) { } addrs = malloc(sizeof(struct sockaddr_storage) * num_msgs); + if (!addrs) return luaL_error(L, "Failed to allocate addrs"); addr_ptrs = malloc(sizeof(struct sockaddr_storage*) * num_msgs); + if (!addr_ptrs) { + free(addrs); + return luaL_error(L, "Failed to allocate addr_ptrs"); + } counts = malloc(sizeof(unsigned int) * num_msgs); + if (!counts) { + free(addrs); free(addr_ptrs); + return luaL_error(L, "Failed to allocate counts"); + } bufs = malloc(sizeof(uv_buf_t*) * num_msgs); + if (!bufs) { + free(addrs); free(addr_ptrs); free(counts); + return luaL_error(L, "Failed to allocate bufs"); + } + memset(bufs, 0, sizeof(uv_buf_t*) * num_msgs); for (unsigned int i=0; i UINT_MAX) - return luaL_error(L, "data at index %d contains too many bufs (max is %d)", UINT_MAX); + if (count > UINT_MAX) { + unsigned int j; + for (j = 0; j <= i; ++j) free(bufs[j]); + free(bufs); free(counts); free(addr_ptrs); free(addrs); + return luaL_error(L, "data at index %d contains too many bufs", i+1); + } counts[i] = count; lua_pop(L, 1); lua_getfield(L, element_index, "addr"); @@ -494,7 +517,10 @@ static void luv_udp_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_ buffer_size = MAX_DGRAM_SIZE * num_msgs; } buf->base = (char*)malloc(buffer_size); - assert(buf->base); + if (!buf->base) { + buf->len = 0; + return; + } buf->len = buffer_size; } #endif diff --git a/src/work.c b/src/work.c index 144b9d81..3d6a5267 100644 --- a/src/work.c +++ b/src/work.c @@ -136,8 +136,24 @@ static lua_State* luv_work_acquire_vm(luv_work_vms_t* vms) lua_setglobal(L, "_THREAD"); uv_mutex_lock(&vms->vm_mutex); + if (vms->idx_vms >= vms->nvms) { + vms->nvms *= 2; + + lua_State **new_vms= realloc(vms->vms, sizeof(lua_State*) * vms->nvms); + if (!new_vms) { + uv_mutex_unlock(&vms->vm_mutex); + return L; // we failed to realloc, so we will leak this vm, but we have no choice at this point + } + vms->vms = new_vms; + + for (unsigned int i = vms->idx_vms; i < vms->nvms; i++) { + vms->vms[i] = NULL; + } + } + vms->vms[vms->idx_vms] = L; vms->idx_vms += 1; + uv_mutex_unlock(&vms->vm_mutex); } return L; @@ -205,6 +221,7 @@ static int luv_new_work(lua_State* L) { luv_thread_dumped(L, 1); len = lua_rawlen(L, -1); code = malloc(len); + if (!code) return luaL_error(L, "Failed to allocate work code buffer"); memcpy(code, lua_tostring(L, -1), len); lua_pop(L, 1); @@ -314,6 +331,11 @@ static void luv_work_init(lua_State* L) { } vms->vms = (lua_State**)calloc(nvms, sizeof(lua_State*)); + if (!vms->vms) { + fprintf(stderr, "*** threadpool not works\n"); + fprintf(stderr, "Error to allocate thread pool vm array\n"); + abort(); + } vms->nvms = nvms; vms->idx_vms = 0;