• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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