mirror of
https://github.com/luau-lang/luau.git
synced 2025-04-16 01:43:51 +01:00
# Old Solver: - Fix a bug in the old solver where a user could use the keyword `typeof` as the name of a type alias. - Fix stringification of scientific notation to omit a trailing decimal place when not followed by a digit e.g. `1.e+20` -> `1e+20` # New Solver - Continuing work on the New non-strict mode - Introduce `keyof` and `rawkeyof` type function for acquiring the type of all keys in a table or class (https://github.com/luau-lang/rfcs/pull/16) --- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
283 lines
7.3 KiB
C++
283 lines
7.3 KiB
C++
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
#include "lualib.h"
|
|
|
|
#include "lcommon.h"
|
|
#include "lbuffer.h"
|
|
|
|
#if defined(LUAU_BIG_ENDIAN)
|
|
#include <endian.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
// while C API returns 'size_t' for binary compatibility in case of future extensions,
|
|
// in the current implementation, length and offset are limited to 31 bits
|
|
// because offset is limited to an integer, a single 64bit comparison can be used and will not overflow
|
|
#define isoutofbounds(offset, len, accessize) (uint64_t(unsigned(offset)) + (accessize) > uint64_t(len))
|
|
|
|
static_assert(MAX_BUFFER_SIZE <= INT_MAX, "current implementation can't handle a larger limit");
|
|
|
|
#if defined(LUAU_BIG_ENDIAN)
|
|
template<typename T>
|
|
inline T buffer_swapbe(T v)
|
|
{
|
|
if (sizeof(T) == 8)
|
|
return htole64(v);
|
|
else if (sizeof(T) == 4)
|
|
return htole32(v);
|
|
else if (sizeof(T) == 2)
|
|
return htole16(v);
|
|
else
|
|
return v;
|
|
}
|
|
#endif
|
|
|
|
static int buffer_create(lua_State* L)
|
|
{
|
|
int size = luaL_checkinteger(L, 1);
|
|
|
|
luaL_argcheck(L, size >= 0, 1, "size");
|
|
|
|
lua_newbuffer(L, size);
|
|
return 1;
|
|
}
|
|
|
|
static int buffer_fromstring(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
const char* val = luaL_checklstring(L, 1, &len);
|
|
|
|
void* data = lua_newbuffer(L, len);
|
|
memcpy(data, val, len);
|
|
return 1;
|
|
}
|
|
|
|
static int buffer_tostring(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* data = luaL_checkbuffer(L, 1, &len);
|
|
|
|
lua_pushlstring(L, (char*)data, len);
|
|
return 1;
|
|
}
|
|
|
|
template<typename T>
|
|
static int buffer_readinteger(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* buf = luaL_checkbuffer(L, 1, &len);
|
|
int offset = luaL_checkinteger(L, 2);
|
|
|
|
if (isoutofbounds(offset, len, sizeof(T)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
T val;
|
|
memcpy(&val, (char*)buf + offset, sizeof(T));
|
|
|
|
#if defined(LUAU_BIG_ENDIAN)
|
|
val = buffer_swapbe(val);
|
|
#endif
|
|
|
|
lua_pushnumber(L, double(val));
|
|
return 1;
|
|
}
|
|
|
|
template<typename T>
|
|
static int buffer_writeinteger(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* buf = luaL_checkbuffer(L, 1, &len);
|
|
int offset = luaL_checkinteger(L, 2);
|
|
int value = luaL_checkunsigned(L, 3);
|
|
|
|
if (isoutofbounds(offset, len, sizeof(T)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
T val = T(value);
|
|
|
|
#if defined(LUAU_BIG_ENDIAN)
|
|
val = buffer_swapbe(val);
|
|
#endif
|
|
|
|
memcpy((char*)buf + offset, &val, sizeof(T));
|
|
return 0;
|
|
}
|
|
|
|
template<typename T, typename StorageType>
|
|
static int buffer_readfp(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* buf = luaL_checkbuffer(L, 1, &len);
|
|
int offset = luaL_checkinteger(L, 2);
|
|
|
|
if (isoutofbounds(offset, len, sizeof(T)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
T val;
|
|
|
|
#if defined(LUAU_BIG_ENDIAN)
|
|
static_assert(sizeof(T) == sizeof(StorageType), "type size must match to reinterpret data");
|
|
StorageType tmp;
|
|
memcpy(&tmp, (char*)buf + offset, sizeof(tmp));
|
|
tmp = buffer_swapbe(tmp);
|
|
|
|
memcpy(&val, &tmp, sizeof(tmp));
|
|
#else
|
|
memcpy(&val, (char*)buf + offset, sizeof(T));
|
|
#endif
|
|
|
|
lua_pushnumber(L, double(val));
|
|
return 1;
|
|
}
|
|
|
|
template<typename T, typename StorageType>
|
|
static int buffer_writefp(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* buf = luaL_checkbuffer(L, 1, &len);
|
|
int offset = luaL_checkinteger(L, 2);
|
|
double value = luaL_checknumber(L, 3);
|
|
|
|
if (isoutofbounds(offset, len, sizeof(T)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
T val = T(value);
|
|
|
|
#if defined(LUAU_BIG_ENDIAN)
|
|
static_assert(sizeof(T) == sizeof(StorageType), "type size must match to reinterpret data");
|
|
StorageType tmp;
|
|
memcpy(&tmp, &val, sizeof(tmp));
|
|
tmp = buffer_swapbe(tmp);
|
|
|
|
memcpy((char*)buf + offset, &tmp, sizeof(tmp));
|
|
#else
|
|
memcpy((char*)buf + offset, &val, sizeof(T));
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int buffer_readstring(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* buf = luaL_checkbuffer(L, 1, &len);
|
|
int offset = luaL_checkinteger(L, 2);
|
|
int size = luaL_checkinteger(L, 3);
|
|
|
|
luaL_argcheck(L, size >= 0, 3, "size");
|
|
|
|
if (isoutofbounds(offset, len, unsigned(size)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
lua_pushlstring(L, (char*)buf + offset, size);
|
|
return 1;
|
|
}
|
|
|
|
static int buffer_writestring(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* buf = luaL_checkbuffer(L, 1, &len);
|
|
int offset = luaL_checkinteger(L, 2);
|
|
size_t size = 0;
|
|
const char* val = luaL_checklstring(L, 3, &size);
|
|
int count = luaL_optinteger(L, 4, int(size));
|
|
|
|
luaL_argcheck(L, count >= 0, 4, "count");
|
|
|
|
if (size_t(count) > size)
|
|
luaL_error(L, "string length overflow");
|
|
|
|
// string size can't exceed INT_MAX at this point
|
|
if (isoutofbounds(offset, len, unsigned(count)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
memcpy((char*)buf + offset, val, count);
|
|
return 0;
|
|
}
|
|
|
|
static int buffer_len(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
luaL_checkbuffer(L, 1, &len);
|
|
|
|
lua_pushnumber(L, double(unsigned(len)));
|
|
return 1;
|
|
}
|
|
|
|
static int buffer_copy(lua_State* L)
|
|
{
|
|
size_t tlen = 0;
|
|
void* tbuf = luaL_checkbuffer(L, 1, &tlen);
|
|
int toffset = luaL_checkinteger(L, 2);
|
|
|
|
size_t slen = 0;
|
|
void* sbuf = luaL_checkbuffer(L, 3, &slen);
|
|
int soffset = luaL_optinteger(L, 4, 0);
|
|
|
|
int size = luaL_optinteger(L, 5, int(slen) - soffset);
|
|
|
|
if (size < 0)
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
if (isoutofbounds(soffset, slen, unsigned(size)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
if (isoutofbounds(toffset, tlen, unsigned(size)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
memmove((char*)tbuf + toffset, (char*)sbuf + soffset, size);
|
|
return 0;
|
|
}
|
|
|
|
static int buffer_fill(lua_State* L)
|
|
{
|
|
size_t len = 0;
|
|
void* buf = luaL_checkbuffer(L, 1, &len);
|
|
int offset = luaL_checkinteger(L, 2);
|
|
unsigned value = luaL_checkunsigned(L, 3);
|
|
int size = luaL_optinteger(L, 4, int(len) - offset);
|
|
|
|
if (size < 0)
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
if (isoutofbounds(offset, len, unsigned(size)))
|
|
luaL_error(L, "buffer access out of bounds");
|
|
|
|
memset((char*)buf + offset, value & 0xff, size);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg bufferlib[] = {
|
|
{"create", buffer_create},
|
|
{"fromstring", buffer_fromstring},
|
|
{"tostring", buffer_tostring},
|
|
{"readi8", buffer_readinteger<int8_t>},
|
|
{"readu8", buffer_readinteger<uint8_t>},
|
|
{"readi16", buffer_readinteger<int16_t>},
|
|
{"readu16", buffer_readinteger<uint16_t>},
|
|
{"readi32", buffer_readinteger<int32_t>},
|
|
{"readu32", buffer_readinteger<uint32_t>},
|
|
{"readf32", buffer_readfp<float, uint32_t>},
|
|
{"readf64", buffer_readfp<double, uint64_t>},
|
|
{"writei8", buffer_writeinteger<int8_t>},
|
|
{"writeu8", buffer_writeinteger<uint8_t>},
|
|
{"writei16", buffer_writeinteger<int16_t>},
|
|
{"writeu16", buffer_writeinteger<uint16_t>},
|
|
{"writei32", buffer_writeinteger<int32_t>},
|
|
{"writeu32", buffer_writeinteger<uint32_t>},
|
|
{"writef32", buffer_writefp<float, uint32_t>},
|
|
{"writef64", buffer_writefp<double, uint64_t>},
|
|
{"readstring", buffer_readstring},
|
|
{"writestring", buffer_writestring},
|
|
{"len", buffer_len},
|
|
{"copy", buffer_copy},
|
|
{"fill", buffer_fill},
|
|
{NULL, NULL},
|
|
};
|
|
|
|
int luaopen_buffer(lua_State* L)
|
|
{
|
|
luaL_register(L, LUA_BUFFERLIBNAME, bufferlib);
|
|
|
|
return 1;
|
|
}
|