1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 /*
9 * require("lua") -- A Lua extension for upb.
10 *
11 * Exposes only the core library
12 * (sub-libraries are exposed in other extensions).
13 *
14 * 64-bit woes: Lua can only represent numbers of type lua_Number (which is
15 * double unless the user specifically overrides this). Doubles can represent
16 * the entire range of 64-bit integers, but lose precision once the integers are
17 * greater than 2^53.
18 *
19 * Lua 5.3 is adding support for integers, which will allow for 64-bit
20 * integers (which can be interpreted as signed or unsigned).
21 *
22 * LuaJIT supports 64-bit signed and unsigned boxed representations
23 * through its "cdata" mechanism, but this is not portable to regular Lua.
24 *
25 * Hopefully Lua 5.3 will come soon enough that we can either use Lua 5.3
26 * integer support or LuaJIT 64-bit cdata for users that need the entire
27 * domain of [u]int64 values.
28 */
29
30 #include "lua/upb.h"
31
32 #include <float.h>
33 #include <math.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "lauxlib.h"
39 #include "upb/message/message.h"
40
41 /* Lua compatibility code *****************************************************/
42
43 /* Shims for upcoming Lua 5.3 functionality. */
lua_isinteger(lua_State * L,int argn)44 static bool lua_isinteger(lua_State* L, int argn) {
45 LUPB_UNUSED(L);
46 LUPB_UNUSED(argn);
47 return false;
48 }
49
50 /* Utility functions **********************************************************/
51
lupb_checkstatus(lua_State * L,upb_Status * s)52 void lupb_checkstatus(lua_State* L, upb_Status* s) {
53 if (!upb_Status_IsOk(s)) {
54 lua_pushstring(L, upb_Status_ErrorMessage(s));
55 lua_error(L);
56 }
57 }
58
59 /* Pushes a new userdata with the given metatable. */
lupb_newuserdata(lua_State * L,size_t size,int n,const char * type)60 void* lupb_newuserdata(lua_State* L, size_t size, int n, const char* type) {
61 #if LUA_VERSION_NUM >= 504
62 void* ret = lua_newuserdatauv(L, size, n);
63 #else
64 void* ret = lua_newuserdata(L, size);
65 lua_createtable(L, 0, n);
66 lua_setuservalue(L, -2);
67 #endif
68
69 /* Set metatable. */
70 luaL_getmetatable(L, type);
71 assert(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */
72 lua_setmetatable(L, -2);
73
74 return ret;
75 }
76
77 #if LUA_VERSION_NUM < 504
lua_setiuservalue(lua_State * L,int index,int n)78 int lua_setiuservalue(lua_State* L, int index, int n) {
79 lua_getuservalue(L, index);
80 lua_insert(L, -2);
81 lua_rawseti(L, -2, n);
82 lua_pop(L, 1);
83 return 1;
84 }
85
lua_getiuservalue(lua_State * L,int index,int n)86 int lua_getiuservalue(lua_State* L, int index, int n) {
87 lua_getuservalue(L, index);
88 lua_rawgeti(L, -1, n);
89 lua_replace(L, -2);
90 return 1;
91 }
92 #endif
93
94 /* We use this function as the __index metamethod when a type has both methods
95 * and an __index metamethod. */
lupb_indexmm(lua_State * L)96 int lupb_indexmm(lua_State* L) {
97 /* Look up in __index table (which is a closure param). */
98 lua_pushvalue(L, 2);
99 lua_rawget(L, lua_upvalueindex(1));
100 if (!lua_isnil(L, -1)) {
101 return 1;
102 }
103
104 /* Not found, chain to user __index metamethod. */
105 lua_pushvalue(L, lua_upvalueindex(2));
106 lua_pushvalue(L, 1);
107 lua_pushvalue(L, 2);
108 lua_call(L, 2, 1);
109 return 1;
110 }
111
lupb_register_type(lua_State * L,const char * name,const luaL_Reg * m,const luaL_Reg * mm)112 void lupb_register_type(lua_State* L, const char* name, const luaL_Reg* m,
113 const luaL_Reg* mm) {
114 luaL_newmetatable(L, name);
115
116 if (mm) {
117 lupb_setfuncs(L, mm);
118 }
119
120 if (m) {
121 lua_createtable(L, 0, 0); /* __index table */
122 lupb_setfuncs(L, m);
123
124 /* Methods go in the mt's __index slot. If the user also specified an
125 * __index metamethod, use our custom lupb_indexmm() that can check both. */
126 lua_getfield(L, -2, "__index");
127 if (lua_isnil(L, -1)) {
128 lua_pop(L, 1);
129 } else {
130 lua_pushcclosure(L, &lupb_indexmm, 2);
131 }
132 lua_setfield(L, -2, "__index");
133 }
134
135 lua_pop(L, 1); /* The mt. */
136 }
137
138 /* Scalar type mapping ********************************************************/
139
140 /* Functions that convert scalar/primitive values (numbers, strings, bool)
141 * between Lua and C/upb. Handles type/range checking. */
142
lupb_checkbool(lua_State * L,int narg)143 bool lupb_checkbool(lua_State* L, int narg) {
144 if (!lua_isboolean(L, narg)) {
145 luaL_error(L, "must be true or false");
146 }
147 return lua_toboolean(L, narg);
148 }
149
150 /* Unlike luaL_checkstring(), this does not allow implicit conversion to
151 * string. */
lupb_checkstring(lua_State * L,int narg,size_t * len)152 const char* lupb_checkstring(lua_State* L, int narg, size_t* len) {
153 if (lua_type(L, narg) != LUA_TSTRING) {
154 luaL_error(L, "Expected string");
155 }
156
157 return lua_tolstring(L, narg, len);
158 }
159
160 /* Unlike luaL_checkinteger, these do not implicitly convert from string or
161 * round an existing double value. We allow floating-point input, but only if
162 * the actual value is integral. */
163 #define INTCHECK(type, ctype, min, max) \
164 ctype lupb_check##type(lua_State* L, int narg) { \
165 double n; \
166 if (lua_isinteger(L, narg)) { \
167 return lua_tointeger(L, narg); \
168 } \
169 \
170 /* Prevent implicit conversion from string. */ \
171 luaL_checktype(L, narg, LUA_TNUMBER); \
172 n = lua_tonumber(L, narg); \
173 \
174 /* Check this double has no fractional part and remains in bounds. \
175 * Consider INT64_MIN and INT64_MAX: \
176 * 1. INT64_MIN -(2^63) is a power of 2, so this converts to a double. \
177 * 2. INT64_MAX (2^63 - 1) is not a power of 2, and conversion of \
178 * out-of-range integer values to a double can lead to undefined behavior. \
179 * On some compilers, this conversion can return 0, but it also can return \
180 * the max value. To deal with this, we can first divide by 2 to prevent \
181 * the overflow, multiply it back, and add 1 to find the true limit. */ \
182 double i; \
183 double max_value = (((double)max / 2) * 2) + 1; \
184 if ((modf(n, &i) != 0.0) || n < min || n >= max_value) { \
185 luaL_error(L, "number %f was not an integer or out of range for " #type, \
186 n); \
187 } \
188 return (ctype)n; \
189 } \
190 void lupb_push##type(lua_State* L, ctype val) { \
191 /* TODO: push integer for Lua >= 5.3, 64-bit cdata for LuaJIT. */ \
192 /* This is lossy for some [u]int64 values, which isn't great, but */ \
193 /* crashing when we encounter these values seems worse. */ \
194 lua_pushnumber(L, val); \
195 }
196
INTCHECK(int64,int64_t,INT64_MIN,INT64_MAX)197 INTCHECK(int64, int64_t, INT64_MIN, INT64_MAX)
198 INTCHECK(int32, int32_t, INT32_MIN, INT32_MAX)
199 INTCHECK(uint64, uint64_t, 0, UINT64_MAX)
200 INTCHECK(uint32, uint32_t, 0, UINT32_MAX)
201
202 double lupb_checkdouble(lua_State* L, int narg) {
203 /* If we were being really hard-nosed here, we'd check whether the input was
204 * an integer that has no precise double representation. But doubles aren't
205 * generally expected to be exact like integers are, and worse this could
206 * cause data-dependent runtime errors: one run of the program could work fine
207 * because the integer calculations happened to be exactly representable in
208 * double, while the next could crash because of subtly different input. */
209
210 luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */
211 return lua_tonumber(L, narg);
212 }
213
lupb_checkfloat(lua_State * L,int narg)214 float lupb_checkfloat(lua_State* L, int narg) {
215 /* We don't worry about checking whether the input can be exactly converted to
216 * float -- see above. */
217
218 luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */
219 return lua_tonumber(L, narg);
220 }
221
lupb_pushdouble(lua_State * L,double d)222 void lupb_pushdouble(lua_State* L, double d) { lua_pushnumber(L, d); }
223
lupb_pushfloat(lua_State * L,float d)224 void lupb_pushfloat(lua_State* L, float d) { lua_pushnumber(L, d); }
225
226 /* Library entry point ********************************************************/
227
luaopen_lupb(lua_State * L)228 int luaopen_lupb(lua_State* L) {
229 #if LUA_VERSION_NUM == 501
230 const struct luaL_Reg funcs[] = {{NULL, NULL}};
231 luaL_register(L, "upb_c", funcs);
232 #else
233 lua_createtable(L, 0, 8);
234 #endif
235 lupb_def_registertypes(L);
236 lupb_msg_registertypes(L);
237 return 1; /* Return package table. */
238 }
239