upb/upb/bindings/lua/upb.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2021, Google LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of Google LLC nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /*
29  * require("lua") -- A Lua extension for upb.
30  *
31  * Exposes only the core library
32  * (sub-libraries are exposed in other extensions).
33  *
34  * 64-bit woes: Lua can only represent numbers of type lua_Number (which is
35  * double unless the user specifically overrides this). Doubles can represent
36  * the entire range of 64-bit integers, but lose precision once the integers are
37  * greater than 2^53.
38  *
39  * Lua 5.3 is adding support for integers, which will allow for 64-bit
40  * integers (which can be interpreted as signed or unsigned).
41  *
42  * LuaJIT supports 64-bit signed and unsigned boxed representations
43  * through its "cdata" mechanism, but this is not portable to regular Lua.
44  *
45  * Hopefully Lua 5.3 will come soon enough that we can either use Lua 5.3
46  * integer support or LuaJIT 64-bit cdata for users that need the entire
47  * domain of [u]int64 values.
48  */
49 
50 #include "upb/bindings/lua/upb.h"
51 
52 #include <float.h>
53 #include <math.h>
54 #include <stdint.h>
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #include "lauxlib.h"
59 #include "upb/msg.h"
60 
61 /* Lua compatibility code *****************************************************/
62 
63 /* Shims for upcoming Lua 5.3 functionality. */
64 static bool lua_isinteger(lua_State* L, int argn) {
65  LUPB_UNUSED(L);
66  LUPB_UNUSED(argn);
67  return false;
68 }
69 
70 /* Utility functions **********************************************************/
71 
72 void lupb_checkstatus(lua_State* L, upb_Status* s) {
73  if (!upb_Status_IsOk(s)) {
74  lua_pushstring(L, upb_Status_ErrorMessage(s));
75  lua_error(L);
76  }
77 }
78 
79 /* Pushes a new userdata with the given metatable. */
80 void* lupb_newuserdata(lua_State* L, size_t size, int n, const char* type) {
81 #if LUA_VERSION_NUM >= 504
82  void* ret = lua_newuserdatauv(L, size, n);
83 #else
84  void* ret = lua_newuserdata(L, size);
85  lua_createtable(L, 0, n);
86  lua_setuservalue(L, -2);
87 #endif
88 
89  /* Set metatable. */
90  luaL_getmetatable(L, type);
91  assert(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */
92  lua_setmetatable(L, -2);
93 
94  return ret;
95 }
96 
97 #if LUA_VERSION_NUM < 504
98 int lua_setiuservalue(lua_State* L, int index, int n) {
99  lua_getuservalue(L, index);
100  lua_insert(L, -2);
101  lua_rawseti(L, -2, n);
102  lua_pop(L, 1);
103  return 1;
104 }
105 
106 int lua_getiuservalue(lua_State* L, int index, int n) {
107  lua_getuservalue(L, index);
108  lua_rawgeti(L, -1, n);
109  lua_replace(L, -2);
110  return 1;
111 }
112 #endif
113 
114 /* We use this function as the __index metamethod when a type has both methods
115  * and an __index metamethod. */
116 int lupb_indexmm(lua_State* L) {
117  /* Look up in __index table (which is a closure param). */
118  lua_pushvalue(L, 2);
119  lua_rawget(L, lua_upvalueindex(1));
120  if (!lua_isnil(L, -1)) {
121  return 1;
122  }
123 
124  /* Not found, chain to user __index metamethod. */
125  lua_pushvalue(L, lua_upvalueindex(2));
126  lua_pushvalue(L, 1);
127  lua_pushvalue(L, 2);
128  lua_call(L, 2, 1);
129  return 1;
130 }
131 
132 void lupb_register_type(lua_State* L, const char* name, const luaL_Reg* m,
133  const luaL_Reg* mm) {
134  luaL_newmetatable(L, name);
135 
136  if (mm) {
137  lupb_setfuncs(L, mm);
138  }
139 
140  if (m) {
141  lua_createtable(L, 0, 0); /* __index table */
142  lupb_setfuncs(L, m);
143 
144  /* Methods go in the mt's __index slot. If the user also specified an
145  * __index metamethod, use our custom lupb_indexmm() that can check both. */
146  lua_getfield(L, -2, "__index");
147  if (lua_isnil(L, -1)) {
148  lua_pop(L, 1);
149  } else {
150  lua_pushcclosure(L, &lupb_indexmm, 2);
151  }
152  lua_setfield(L, -2, "__index");
153  }
154 
155  lua_pop(L, 1); /* The mt. */
156 }
157 
158 /* Scalar type mapping ********************************************************/
159 
160 /* Functions that convert scalar/primitive values (numbers, strings, bool)
161  * between Lua and C/upb. Handles type/range checking. */
162 
163 bool lupb_checkbool(lua_State* L, int narg) {
164  if (!lua_isboolean(L, narg)) {
165  luaL_error(L, "must be true or false");
166  }
167  return lua_toboolean(L, narg);
168 }
169 
170 /* Unlike luaL_checkstring(), this does not allow implicit conversion to
171  * string. */
172 const char* lupb_checkstring(lua_State* L, int narg, size_t* len) {
173  if (lua_type(L, narg) != LUA_TSTRING) {
174  luaL_error(L, "Expected string");
175  }
176 
177  return lua_tolstring(L, narg, len);
178 }
179 
180 /* Unlike luaL_checkinteger, these do not implicitly convert from string or
181  * round an existing double value. We allow floating-point input, but only if
182  * the actual value is integral. */
183 #define INTCHECK(type, ctype, min, max) \
184  ctype lupb_check##type(lua_State* L, int narg) { \
185  double n; \
186  if (lua_isinteger(L, narg)) { \
187  return lua_tointeger(L, narg); \
188  } \
189  \
190  /* Prevent implicit conversion from string. */ \
191  luaL_checktype(L, narg, LUA_TNUMBER); \
192  n = lua_tonumber(L, narg); \
193  \
194  /* Check this double has no fractional part and remains in bounds. \
195  * Consider INT64_MIN and INT64_MAX: \
196  * 1. INT64_MIN -(2^63) is a power of 2, so this converts to a double. \
197  * 2. INT64_MAX (2^63 - 1) is not a power of 2, and conversion of \
198  * out-of-range integer values to a double can lead to undefined behavior. \
199  * On some compilers, this conversion can return 0, but it also can return \
200  * the max value. To deal with this, we can first divide by 2 to prevent \
201  * the overflow, multiply it back, and add 1 to find the true limit. */ \
202  double i; \
203  double max_value = (((double)max / 2) * 2) + 1; \
204  if ((modf(n, &i) != 0.0) || n < min || n >= max_value) { \
205  luaL_error(L, "number %f was not an integer or out of range for " #type, \
206  n); \
207  } \
208  return (ctype)n; \
209  } \
210  void lupb_push##type(lua_State* L, ctype val) { \
211  /* TODO: push integer for Lua >= 5.3, 64-bit cdata for LuaJIT. */ \
212  /* This is lossy for some [u]int64 values, which isn't great, but */ \
213  /* crashing when we encounter these values seems worse. */ \
214  lua_pushnumber(L, val); \
215  }
216 
221 
222 double lupb_checkdouble(lua_State* L, int narg) {
223  /* If we were being really hard-nosed here, we'd check whether the input was
224  * an integer that has no precise double representation. But doubles aren't
225  * generally expected to be exact like integers are, and worse this could
226  * cause data-dependent runtime errors: one run of the program could work fine
227  * because the integer calculations happened to be exactly representable in
228  * double, while the next could crash because of subtly different input. */
229 
230  luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */
231  return lua_tonumber(L, narg);
232 }
233 
234 float lupb_checkfloat(lua_State* L, int narg) {
235  /* We don't worry about checking whether the input can be exactly converted to
236  * float -- see above. */
237 
238  luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */
239  return lua_tonumber(L, narg);
240 }
241 
242 void lupb_pushdouble(lua_State* L, double d) { lua_pushnumber(L, d); }
243 
244 void lupb_pushfloat(lua_State* L, float d) { lua_pushnumber(L, d); }
245 
246 /* Library entry point ********************************************************/
247 
248 int luaopen_lupb(lua_State* L) {
249 #if LUA_VERSION_NUM == 501
250  const struct luaL_Reg funcs[] = {{NULL, NULL}};
251  luaL_register(L, "upb_c", funcs);
252 #else
253  lua_createtable(L, 0, 8);
254 #endif
257  return 1; /* Return package table. */
258 }
lupb_newuserdata
void * lupb_newuserdata(lua_State *L, size_t size, int n, const char *type)
Definition: upb/upb/bindings/lua/upb.c:80
lupb_def_registertypes
void lupb_def_registertypes(lua_State *L)
Definition: upb/upb/bindings/lua/def.c:889
lupb_pushfloat
void lupb_pushfloat(lua_State *L, float d)
Definition: upb/upb/bindings/lua/upb.c:237
google::protobuf::int64
int64_t int64
Definition: third_party/bloaty/third_party/protobuf/src/google/protobuf/stubs/port.h:151
INT64_MAX
#define INT64_MAX
Definition: stdint-msvc2008.h:139
string.h
UINT64_MAX
#define UINT64_MAX
Definition: stdint-msvc2008.h:143
google::protobuf::uint32
uint32_t uint32
Definition: third_party/bloaty/third_party/protobuf/src/google/protobuf/stubs/port.h:155
UINT32_MAX
#define UINT32_MAX
Definition: stdint-msvc2008.h:142
setup.name
name
Definition: setup.py:542
lupb_indexmm
int lupb_indexmm(lua_State *L)
Definition: upb/upb/bindings/lua/upb.c:116
upb_Status_ErrorMessage
const char * upb_Status_ErrorMessage(const upb_Status *status)
Definition: upb/upb/upb.c:52
msg.h
lupb_checkstring
const char * lupb_checkstring(lua_State *L, int narg, size_t *len)
Definition: upb/upb/bindings/lua/upb.c:172
LUPB_UNUSED
#define LUPB_UNUSED(var)
Definition: upb/upb/bindings/lua/upb.h:117
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
lua_setiuservalue
int lua_setiuservalue(lua_State *L, int index, int n)
Definition: upb/upb/bindings/lua/upb.c:98
lupb_checkdouble
double lupb_checkdouble(lua_State *L, int narg)
Definition: upb/upb/bindings/lua/upb.c:215
google::protobuf::int32
int32_t int32
Definition: third_party/bloaty/third_party/protobuf/src/google/protobuf/stubs/port.h:150
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
lua_getiuservalue
int lua_getiuservalue(lua_State *L, int index, int n)
Definition: upb/upb/bindings/lua/upb.c:106
lupb_checkstatus
void lupb_checkstatus(lua_State *L, upb_Status *s)
Definition: upb/upb/bindings/lua/upb.c:72
lupb_register_type
void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, const luaL_Reg *mm)
Definition: upb/upb/bindings/lua/upb.c:132
lua_isinteger
static bool lua_isinteger(lua_State *L, int argn)
Definition: upb/upb/bindings/lua/upb.c:64
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
lupb_checkfloat
float lupb_checkfloat(lua_State *L, int narg)
Definition: upb/upb/bindings/lua/upb.c:227
google::protobuf::uint64
uint64_t uint64
Definition: third_party/bloaty/third_party/protobuf/src/google/protobuf/stubs/port.h:156
upb_Status
Definition: upb/upb/upb.h:52
upb.h
lupb_checkbool
bool lupb_checkbool(lua_State *L, int narg)
Definition: upb/upb/bindings/lua/upb.c:163
luaopen_lupb
int luaopen_lupb(lua_State *L)
Definition: upb/upb/bindings/lua/upb.c:241
d
static const fe d
Definition: curve25519_tables.h:19
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
stdint.h
INT64_MIN
#define INT64_MIN
Definition: stdint-msvc2008.h:138
lupb_pushdouble
void lupb_pushdouble(lua_State *L, double d)
Definition: upb/upb/bindings/lua/upb.c:235
INT32_MIN
#define INT32_MIN
Definition: stdint-msvc2008.h:136
upb_Status_IsOk
bool upb_Status_IsOk(const upb_Status *status)
Definition: upb/upb/upb.c:50
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
L
lua_State * L
Definition: upb/upb/bindings/lua/main.c:35
INTCHECK
#define INTCHECK(type, ctype, min, max)
Definition: upb/upb/bindings/lua/upb.c:183
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
INT32_MAX
#define INT32_MAX
Definition: stdint-msvc2008.h:137
regress.m
m
Definition: regress/regress.py:25
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
lupb_msg_registertypes
void lupb_msg_registertypes(lua_State *L)
Definition: bindings/lua/msg.c:1097


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:47