/src/tarantool/src/box/lua/call.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2010-2016, Tarantool AUTHORS, please see AUTHORS file. |
3 | | * |
4 | | * Redistribution and use in source and binary forms, with or |
5 | | * without modification, are permitted provided that the following |
6 | | * conditions are met: |
7 | | * |
8 | | * 1. Redistributions of source code must retain the above |
9 | | * copyright notice, this list of conditions and the |
10 | | * following disclaimer. |
11 | | * |
12 | | * 2. Redistributions in binary form must reproduce the above |
13 | | * copyright notice, this list of conditions and the following |
14 | | * disclaimer in the documentation and/or other materials |
15 | | * provided with the distribution. |
16 | | * |
17 | | * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND |
18 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
19 | | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
21 | | * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
22 | | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
25 | | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
26 | | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
28 | | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | | * SUCH DAMAGE. |
30 | | */ |
31 | | #include "box/box.h" |
32 | | #include "box/lua/call.h" |
33 | | #include "box/call.h" |
34 | | #include "box/error.h" |
35 | | #include "box/func.h" |
36 | | #include "box/func_def.h" |
37 | | #include "box/schema.h" |
38 | | #include "fiber.h" |
39 | | #include "tt_static.h" |
40 | | |
41 | | #include "lua/utils.h" |
42 | | #include "lua/serializer.h" |
43 | | #include "lua/msgpack.h" |
44 | | #include "lua/trigger.h" |
45 | | |
46 | | #include "box/port.h" |
47 | | #include "box/lua/misc.h" |
48 | | #include "box/lua/tuple.h" |
49 | | #include "small/obuf.h" |
50 | | #include "trivia/util.h" |
51 | | #include "mpstream/mpstream.h" |
52 | | #include "box/session.h" |
53 | | #include "box/iproto_features.h" |
54 | | #include "core/mp_ctx.h" |
55 | | |
56 | | /** |
57 | | * Handlers identifiers to obtain lua_Cfunction reference from |
58 | | * Lua registry table. These handlers are initialized on Tarantool |
59 | | * startup and are used until the Lua universe is destroyed. |
60 | | * Such approach reduces Lua GC usage since there is no need to |
61 | | * create short-lived GCfunc objects for the corresponding C |
62 | | * function on each iproto CALL/EVAL request or stored Lua |
63 | | * procedure call. |
64 | | */ |
65 | | enum handlers { |
66 | | HANDLER_CALL, |
67 | | HANDLER_CALL_BY_REF, |
68 | | HANDLER_ENCODE_CALL, |
69 | | HANDLER_ENCODE_CALL_16, |
70 | | HANDLER_EVAL, |
71 | | HANDLER_MAX, |
72 | | }; |
73 | | |
74 | | static int execute_lua_refs[HANDLER_MAX]; |
75 | | |
76 | | /** |
77 | | * A copy of the default serializer with encode_error_as_ext option disabled. |
78 | | * Changes to the default serializer are propagated via an update trigger. |
79 | | * It is used for returning errors in the legacy format to clients that do |
80 | | * not support the MP_ERROR MsgPack extension. |
81 | | */ |
82 | | static struct luaL_serializer call_serializer_no_error_ext; |
83 | | |
84 | | /** |
85 | | * Returns a serializer that should be used for encoding CALL/EVAL result. |
86 | | */ |
87 | | static struct luaL_serializer * |
88 | | get_call_serializer(void) |
89 | 0 | { |
90 | 0 | if (!iproto_features_test(¤t_session()->meta.features, |
91 | 0 | IPROTO_FEATURE_ERROR_EXTENSION)) { |
92 | 0 | return &call_serializer_no_error_ext; |
93 | 0 | } else { |
94 | 0 | return luaL_msgpack_default; |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | int |
99 | | box_lua_find(lua_State *L, const char *name, const char *name_end) |
100 | 0 | { |
101 | 0 | lua_checkstack(L, 2); /* No more than 2 entries are needed. */ |
102 | 0 | int top = lua_gettop(L); |
103 | | |
104 | | /* Take the first token. */ |
105 | 0 | const char *start = name; |
106 | 0 | while (start != name_end && *start != '.' && |
107 | 0 | *start != ':' && *start != '[') |
108 | 0 | start++; |
109 | 0 | lua_pushlstring(L, name, start - name); |
110 | 0 | lua_gettable(L, LUA_GLOBALSINDEX); |
111 | | |
112 | | /* Take the rest tokens. */ |
113 | 0 | while (start != name_end) { |
114 | 0 | if (!lua_istable(L, -1) && |
115 | 0 | !lua_islightuserdata(L, -1) && !lua_isuserdata(L, -1)) |
116 | 0 | goto no_such_proc; |
117 | | |
118 | 0 | char delim = *start++; /* skip delimiter. */ |
119 | 0 | if (delim == '.') { |
120 | | /* Look for the next token. */ |
121 | 0 | const char *end = start; |
122 | 0 | while (end != name_end && *end != '.' && |
123 | 0 | *end != ':' && *end != '[') |
124 | 0 | end++; |
125 | 0 | lua_pushlstring(L, start, end - start); |
126 | 0 | start = end; |
127 | 0 | } else if (delim == ':') { |
128 | 0 | lua_pushlstring(L, start, name_end - start); |
129 | 0 | lua_gettable(L, -2); /* get function from object. */ |
130 | 0 | lua_insert(L, -2); /* swap function and object. */ |
131 | 0 | break; |
132 | 0 | } else if (delim == '[') { |
133 | 0 | const char *end = memchr(start, ']', name_end - start); |
134 | 0 | if (end == NULL) |
135 | 0 | goto no_such_proc; |
136 | | |
137 | 0 | if (end - start >= 2 && start[0] == end[-1] && |
138 | 0 | (start[0] == '"' || start[0] == '\'')) { |
139 | | /* Quoted string, just extract it. */ |
140 | 0 | lua_pushlstring(L, start + 1, end - start - 2); |
141 | 0 | } else { |
142 | | /* Must be a number, convert from string. */ |
143 | 0 | lua_pushlstring(L, start, end - start); |
144 | 0 | int success; |
145 | 0 | lua_Number num = lua_tonumberx(L, -1, &success); |
146 | 0 | if (!success) |
147 | 0 | goto no_such_proc; |
148 | 0 | lua_pop(L, 1); |
149 | 0 | lua_pushnumber(L, num); |
150 | 0 | } |
151 | 0 | start = end + 1; /* skip closing bracket. */ |
152 | 0 | } else { |
153 | 0 | goto no_such_proc; |
154 | 0 | } |
155 | | |
156 | 0 | lua_gettable(L, -2); /* get child object from parent object. */ |
157 | 0 | lua_remove(L, -2); /* drop previous parent object. */ |
158 | 0 | } |
159 | | |
160 | | /* Now at top+1 must be the function, and at top+2 may be the object. */ |
161 | 0 | assert(lua_gettop(L) - top >= 1 && lua_gettop(L) - top <= 2); |
162 | 0 | if (!lua_isfunction(L, top + 1) && !lua_istable(L, top + 1)) { |
163 | | /* lua_call or lua_gettable would raise a type error |
164 | | * for us, but our own message is more verbose. */ |
165 | 0 | goto no_such_proc; |
166 | 0 | } |
167 | | |
168 | 0 | return lua_gettop(L) - top; |
169 | | |
170 | 0 | no_such_proc: |
171 | 0 | diag_set(ClientError, ER_NO_SUCH_PROC, tt_cstr(name, name_end - name)); |
172 | 0 | return -1; |
173 | 0 | } |
174 | | |
175 | | /** |
176 | | * A helper to find lua stored procedures for box.call. |
177 | | * box.call iteslf is pure Lua, to avoid issues |
178 | | * with infinite call recursion smashing C |
179 | | * thread stack. |
180 | | */ |
181 | | |
182 | | static int |
183 | | lbox_call_loadproc(struct lua_State *L) |
184 | 0 | { |
185 | 0 | const char *name; |
186 | 0 | size_t name_len; |
187 | 0 | name = lua_tolstring(L, 1, &name_len); |
188 | 0 | int count = box_lua_find(L, name, name + name_len); |
189 | 0 | if (count < 0) |
190 | 0 | return luaT_error(L); |
191 | 0 | return count; |
192 | 0 | } |
193 | | |
194 | | /* |
195 | | * Encode CALL_16 result. |
196 | | * |
197 | | * To allow clients to understand a complex return from |
198 | | * a procedure, we are compatible with SELECT protocol, |
199 | | * and return the number of return values first, and |
200 | | * then each return value as a tuple. |
201 | | * |
202 | | * The following conversion rules apply: |
203 | | * |
204 | | * If a Lua stack contains at least one scalar, each |
205 | | * value on the stack is converted to a tuple. A stack |
206 | | * containing a single Lua table with scalars is converted to |
207 | | * a tuple with multiple fields. |
208 | | * |
209 | | * If the stack is a Lua table, each member of which is |
210 | | * not scalar, each member of the table is converted to |
211 | | * a tuple. This way very large lists of return values can |
212 | | * be used, since Lua stack size is limited by 8000 elements, |
213 | | * while Lua table size is pretty much unlimited. |
214 | | * |
215 | | * Please read gh-291 carefully before "fixing" this code. |
216 | | */ |
217 | | static inline uint32_t |
218 | | luamp_encode_call_16(lua_State *L, struct luaL_serializer *cfg, |
219 | | struct mpstream *stream) |
220 | 0 | { |
221 | 0 | int nrets = lua_gettop(L); |
222 | 0 | if (nrets == 0) { |
223 | 0 | return 0; |
224 | 0 | } else if (nrets > 1) { |
225 | | /* |
226 | | * Multireturn: |
227 | | * `return 1, box.tuple.new(...), array, 3, ...` |
228 | | */ |
229 | 0 | for (int i = 1; i <= nrets; ++i) { |
230 | 0 | struct luaL_field field; |
231 | 0 | if (luaL_tofield(L, cfg, i, &field) < 0) |
232 | 0 | return luaT_error(L); |
233 | 0 | struct tuple *tuple; |
234 | 0 | if (field.type == MP_EXT && |
235 | 0 | (tuple = luaT_istuple(L, i)) != NULL) { |
236 | | /* `return ..., box.tuple.new(...), ...` */ |
237 | 0 | tuple_to_mpstream(tuple, stream); |
238 | 0 | } else if (field.type != MP_ARRAY) { |
239 | | /* |
240 | | * `return ..., scalar, ... => |
241 | | * ..., { scalar }, ...` |
242 | | */ |
243 | 0 | lua_pushvalue(L, i); |
244 | 0 | mpstream_encode_array(stream, 1); |
245 | 0 | if (luamp_encode_r(L, cfg, stream, &field, 0) != 0) |
246 | 0 | return luaT_error(L); |
247 | 0 | lua_pop(L, 1); |
248 | 0 | } else { |
249 | | /* `return ..., array, ...` */ |
250 | 0 | if (luamp_encode(L, cfg, stream, i) != 0) |
251 | 0 | return luaT_error(L); |
252 | 0 | } |
253 | 0 | } |
254 | 0 | return nrets; |
255 | 0 | } |
256 | 0 | assert(nrets == 1); |
257 | | |
258 | | /* |
259 | | * Inspect the first result |
260 | | */ |
261 | 0 | struct luaL_field root; |
262 | 0 | if (luaL_tofield(L, cfg, 1, &root) < 0) |
263 | 0 | return luaT_error(L); |
264 | 0 | struct tuple *tuple; |
265 | 0 | if (root.type == MP_EXT && (tuple = luaT_istuple(L, 1)) != NULL) { |
266 | | /* `return box.tuple()` */ |
267 | 0 | tuple_to_mpstream(tuple, stream); |
268 | 0 | return 1; |
269 | 0 | } else if (root.type != MP_ARRAY) { |
270 | | /* |
271 | | * `return scalar` |
272 | | * `return map` |
273 | | */ |
274 | 0 | mpstream_encode_array(stream, 1); |
275 | 0 | assert(lua_gettop(L) == 1); |
276 | 0 | if (luamp_encode_r(L, cfg, stream, &root, 0) != 0) |
277 | 0 | return luaT_error(L); |
278 | 0 | return 1; |
279 | 0 | } |
280 | | |
281 | 0 | assert(root.type == MP_ARRAY); |
282 | 0 | if (root.size == 0) { |
283 | | /* `return {}` => `{ box.tuple() }` */ |
284 | 0 | mpstream_encode_array(stream, 0); |
285 | 0 | return 1; |
286 | 0 | } |
287 | | |
288 | | /* `return { tuple, scalar, tuple }` */ |
289 | 0 | assert(root.type == MP_ARRAY && root.size > 0); |
290 | 0 | for (uint32_t t = 1; t <= root.size; t++) { |
291 | 0 | lua_rawgeti(L, 1, t); |
292 | 0 | struct luaL_field field; |
293 | 0 | if (luaL_tofield(L, cfg, -1, &field) < 0) |
294 | 0 | return luaT_error(L); |
295 | 0 | if (field.type == MP_EXT && (tuple = luaT_istuple(L, -1))) { |
296 | 0 | tuple_to_mpstream(tuple, stream); |
297 | 0 | } else if (field.type != MP_ARRAY) { |
298 | | /* The first member of root table is not tuple/array */ |
299 | 0 | if (t == 1) { |
300 | | /* |
301 | | * `return { scalar, ... } => |
302 | | * box.tuple.new(scalar, ...)` |
303 | | */ |
304 | 0 | mpstream_encode_array(stream, root.size); |
305 | | /* |
306 | | * Encode the first field of tuple using |
307 | | * existing information from luaL_tofield |
308 | | */ |
309 | 0 | if (luamp_encode_r(L, cfg, stream, &field, 0) != 0) |
310 | 0 | return luaT_error(L); |
311 | 0 | lua_pop(L, 1); |
312 | 0 | assert(lua_gettop(L) == 1); |
313 | | /* Encode remaining fields as usual */ |
314 | 0 | for (uint32_t f = 2; f <= root.size; f++) { |
315 | 0 | lua_rawgeti(L, 1, f); |
316 | 0 | if (luamp_encode(L, cfg, stream, -1) != 0) |
317 | 0 | return luaT_error(L); |
318 | 0 | lua_pop(L, 1); |
319 | 0 | } |
320 | 0 | return 1; |
321 | 0 | } |
322 | | /* |
323 | | * `return { tuple/array, ..., scalar, ... } => |
324 | | * { tuple/array, ..., { scalar }, ... }` |
325 | | */ |
326 | 0 | mpstream_encode_array(stream, 1); |
327 | 0 | if (luamp_encode_r(L, cfg, stream, &field, 0) != 0) |
328 | 0 | return luaT_error(L); |
329 | |
|
330 | 0 | } else { |
331 | | /* `return { tuple/array, ..., tuple/array, ... }` */ |
332 | 0 | if (luamp_encode_r(L, cfg, stream, &field, 0) != 0) |
333 | 0 | return luaT_error(L); |
334 | 0 | } |
335 | 0 | lua_pop(L, 1); |
336 | 0 | assert(lua_gettop(L) == 1); |
337 | 0 | } |
338 | 0 | return root.size; |
339 | 0 | } |
340 | | |
341 | | static const struct port_vtab port_lua_vtab; |
342 | | |
343 | | void |
344 | | port_lua_create_at(struct port *port, struct lua_State *L, int bottom) |
345 | 0 | { |
346 | 0 | struct port_lua *port_lua = (struct port_lua *) port; |
347 | 0 | memset(port_lua, 0, sizeof(*port_lua)); |
348 | 0 | port_lua->vtab = &port_lua_vtab; |
349 | 0 | port_lua->L = L; |
350 | | /* |
351 | | * Allow to destroy the port even if no ref. |
352 | | * @Sa luaL_unref. |
353 | | */ |
354 | 0 | port_lua->ref = -1; |
355 | 0 | port_lua->bottom = bottom; |
356 | 0 | } |
357 | | |
358 | | bool |
359 | | port_is_lua(struct port *port) |
360 | 0 | { |
361 | 0 | return port->vtab == &port_lua_vtab; |
362 | 0 | } |
363 | | |
364 | | struct execute_lua_ctx { |
365 | | int lua_ref; |
366 | | const char *name; |
367 | | uint32_t name_len; |
368 | | bool takes_raw_args; |
369 | | struct port *args; |
370 | | }; |
371 | | |
372 | | static inline void |
373 | | push_lua_args(lua_State *L, struct execute_lua_ctx *ctx) |
374 | 0 | { |
375 | 0 | port_dump_lua(ctx->args, L, ctx->takes_raw_args ? |
376 | 0 | PORT_DUMP_LUA_MODE_MP_OBJECT : |
377 | 0 | PORT_DUMP_LUA_MODE_FLAT); |
378 | 0 | } |
379 | | |
380 | | /** |
381 | | * Find a lua function by name and execute it. Used for body-less |
382 | | * UDFs, which may not yet be defined when a function definition |
383 | | * is loaded from _func table, or dynamically re-defined at any |
384 | | * time. We don't cache references to such functions. |
385 | | */ |
386 | | static int |
387 | | execute_lua_call(lua_State *L) |
388 | 0 | { |
389 | 0 | struct execute_lua_ctx *ctx = |
390 | 0 | (struct execute_lua_ctx *) lua_topointer(L, 1); |
391 | 0 | lua_settop(L, 0); /* clear the stack to simplify the logic below */ |
392 | |
|
393 | 0 | const char *name = ctx->name; |
394 | 0 | uint32_t name_len = ctx->name_len; |
395 | | |
396 | | /* How many objects are on stack after box_lua_find. */ |
397 | 0 | int oc = box_lua_find(L, name, name + name_len); |
398 | 0 | if (oc < 0) |
399 | 0 | return luaT_error(L); |
400 | | |
401 | | /* Push the rest of args (a tuple). */ |
402 | 0 | int top = lua_gettop(L); |
403 | 0 | push_lua_args(L, ctx); |
404 | 0 | int arg_count = lua_gettop(L) - top; |
405 | |
|
406 | 0 | lua_call(L, arg_count + oc - 1, LUA_MULTRET); |
407 | 0 | return lua_gettop(L); |
408 | 0 | } |
409 | | |
410 | | /** |
411 | | * Dereference a sandboxed function and execute it. Used for |
412 | | * persistent UDFs. |
413 | | */ |
414 | | static int |
415 | | execute_lua_call_by_ref(lua_State *L) |
416 | 0 | { |
417 | 0 | struct execute_lua_ctx *ctx = |
418 | 0 | (struct execute_lua_ctx *) lua_topointer(L, 1); |
419 | 0 | lua_settop(L, 0); /* clear the stack to simplify the logic below */ |
420 | |
|
421 | 0 | lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->lua_ref); |
422 | | |
423 | | /* Push the rest of args (a tuple). */ |
424 | 0 | int top = lua_gettop(L); |
425 | 0 | push_lua_args(L, ctx); |
426 | 0 | int arg_count = lua_gettop(L) - top; |
427 | |
|
428 | 0 | lua_call(L, arg_count, LUA_MULTRET); |
429 | 0 | return lua_gettop(L); |
430 | 0 | } |
431 | | |
432 | | static int |
433 | | execute_lua_eval(lua_State *L) |
434 | 0 | { |
435 | 0 | struct execute_lua_ctx *ctx = |
436 | 0 | (struct execute_lua_ctx *) lua_topointer(L, 1); |
437 | 0 | lua_settop(L, 0); /* clear the stack to simplify the logic below */ |
438 | | |
439 | | /* Compile expression */ |
440 | 0 | const char *expr = ctx->name; |
441 | 0 | uint32_t expr_len = ctx->name_len; |
442 | 0 | if (luaL_loadbuffer(L, expr, expr_len, "=eval")) { |
443 | 0 | diag_set(LuajitError, lua_tostring(L, -1)); |
444 | 0 | luaT_error_at(L, 0); |
445 | 0 | } |
446 | | |
447 | | /* Unpack arguments */ |
448 | 0 | int top = lua_gettop(L); |
449 | 0 | push_lua_args(L, ctx); |
450 | 0 | int arg_count = lua_gettop(L) - top; |
451 | | |
452 | | /* Call compiled code */ |
453 | 0 | lua_call(L, arg_count, LUA_MULTRET); |
454 | 0 | return lua_gettop(L); |
455 | 0 | } |
456 | | |
457 | | struct encode_lua_ctx { |
458 | | struct port_lua *port; |
459 | | struct mpstream *stream; |
460 | | /** MsgPack encoding context to save meta information to. */ |
461 | | struct mp_ctx *mp_ctx; |
462 | | }; |
463 | | |
464 | | /** |
465 | | * Encode call results to msgpack from Lua stack. |
466 | | * Lua stack has the following structure -- the last element is |
467 | | * lightuserdata pointer to encode_lua_ctx, all other values are |
468 | | * arguments to process. |
469 | | * The function encodes all given Lua objects to msgpack stream |
470 | | * from context, sets port's size and returns no value on the Lua |
471 | | * stack. |
472 | | * XXX: This function *MUST* be called under lua_pcall(), because |
473 | | * luamp_encode() may raise an error. |
474 | | */ |
475 | | static int |
476 | | encode_lua_call(lua_State *L) |
477 | 0 | { |
478 | 0 | assert(lua_islightuserdata(L, -1)); |
479 | 0 | struct encode_lua_ctx *encode_lua_ctx = |
480 | 0 | (struct encode_lua_ctx *) lua_topointer(L, -1); |
481 | 0 | assert(encode_lua_ctx->port->L == L); |
482 | | /* Delete ctx from the stack. */ |
483 | 0 | lua_pop(L, 1); |
484 | | /* |
485 | | * Add all elements from Lua stack to the buffer. |
486 | | * |
487 | | * TODO: forbid explicit yield from __serialize or __index here |
488 | | */ |
489 | 0 | struct luaL_serializer *cfg = get_call_serializer(); |
490 | 0 | const int size = lua_gettop(L); |
491 | 0 | for (int i = 1; i <= size; ++i) { |
492 | 0 | if (luamp_encode_with_ctx(L, cfg, encode_lua_ctx->stream, i, |
493 | 0 | encode_lua_ctx->mp_ctx, NULL) != 0) |
494 | 0 | return luaT_error(L); |
495 | 0 | } |
496 | 0 | encode_lua_ctx->port->size = size; |
497 | 0 | mpstream_flush(encode_lua_ctx->stream); |
498 | 0 | return 0; |
499 | 0 | } |
500 | | |
501 | | /** |
502 | | * Encode call_16 results to msgpack from Lua stack. |
503 | | * Lua stack has the following structure -- the last element is |
504 | | * lightuserdata pointer to encode_lua_ctx, all other values are |
505 | | * arguments to process. |
506 | | * The function encodes all given Lua objects to msgpack stream |
507 | | * from context, sets port's size and returns no value on the Lua |
508 | | * stack. |
509 | | * XXX: This function *MUST* be called under lua_pcall(), because |
510 | | * luamp_encode() may raise an error. |
511 | | */ |
512 | | static int |
513 | | encode_lua_call_16(lua_State *L) |
514 | 0 | { |
515 | 0 | assert(lua_islightuserdata(L, -1)); |
516 | 0 | struct encode_lua_ctx *ctx = |
517 | 0 | (struct encode_lua_ctx *) lua_topointer(L, -1); |
518 | 0 | assert(ctx->port->L == L); |
519 | | /* Delete ctx from the stack. */ |
520 | 0 | lua_pop(L, 1); |
521 | | /* |
522 | | * Add all elements from Lua stack to the buffer. |
523 | | * |
524 | | * TODO: forbid explicit yield from __serialize or __index here |
525 | | */ |
526 | 0 | struct luaL_serializer *cfg = get_call_serializer(); |
527 | 0 | ctx->port->size = luamp_encode_call_16(L, cfg, ctx->stream); |
528 | 0 | mpstream_flush(ctx->stream); |
529 | 0 | return 0; |
530 | 0 | } |
531 | | |
532 | | /** |
533 | | * Get port contents as raw MsgPack. Encodes the port's Lua values on |
534 | | * the current fiber's region using a MsgPack stream. |
535 | | */ |
536 | | static const char * |
537 | | port_lua_get_msgpack(struct port *base, uint32_t *size); |
538 | | |
539 | | static inline int |
540 | | port_lua_do_dump_with_ctx(struct port *base, struct mpstream *stream, |
541 | | enum handlers handler, struct mp_ctx *mp_ctx) |
542 | 0 | { |
543 | 0 | struct port_lua *port = (struct port_lua *) base; |
544 | 0 | assert(port->vtab == &port_lua_vtab); |
545 | | /* |
546 | | * Use the same global state, assuming the encoder doesn't |
547 | | * yield. |
548 | | */ |
549 | 0 | struct encode_lua_ctx encode_lua_ctx = { |
550 | 0 | .port = port, |
551 | 0 | .stream = stream, |
552 | 0 | .mp_ctx = mp_ctx, |
553 | 0 | }; |
554 | 0 | lua_State *L = port->L; |
555 | | /* |
556 | | * At the moment Lua stack holds only values to encode. |
557 | | * Push corresponding encoder, push duplicates of values |
558 | | * so that the port can be dumped multiple times and push |
559 | | * encode context as lightuserdata to the top. |
560 | | */ |
561 | 0 | const int size = lua_gettop(L) - port->bottom + 1; |
562 | 0 | lua_rawgeti(L, LUA_REGISTRYINDEX, execute_lua_refs[handler]); |
563 | 0 | assert(lua_isfunction(L, -1) && lua_iscfunction(L, -1)); |
564 | 0 | for (int i = 0; i < size; i++) |
565 | 0 | lua_pushvalue(L, port->bottom + i); |
566 | 0 | lua_pushlightuserdata(L, &encode_lua_ctx); |
567 | | /* nargs -- all arguments + lightuserdata. */ |
568 | 0 | if (luaT_call(L, size + 1, 0) != 0) |
569 | 0 | return -1; |
570 | 0 | return port->size; |
571 | 0 | } |
572 | | |
573 | | static inline int |
574 | | port_lua_do_dump(struct port *base, struct mpstream *stream, |
575 | | enum handlers handler) |
576 | 0 | { |
577 | 0 | return port_lua_do_dump_with_ctx(base, stream, handler, NULL); |
578 | 0 | } |
579 | | |
580 | | /** |
581 | | * Dump Lua port contents to output buffer in MsgPack format. |
582 | | */ |
583 | | static int |
584 | | port_lua_dump(struct port *base, struct obuf *out, struct mp_ctx *ctx) |
585 | 0 | { |
586 | 0 | struct port_lua *port = (struct port_lua *) base; |
587 | 0 | struct mpstream stream; |
588 | 0 | mpstream_init(&stream, out, obuf_reserve_cb, obuf_alloc_cb, |
589 | 0 | luamp_error, port->L); |
590 | 0 | return port_lua_do_dump_with_ctx(base, &stream, HANDLER_ENCODE_CALL, |
591 | 0 | ctx); |
592 | 0 | } |
593 | | |
594 | | /** |
595 | | * Dump Lua port contents to output buffer in MsgPack format. |
596 | | */ |
597 | | static int |
598 | | port_lua_dump_16(struct port *base, struct obuf *out, struct mp_ctx *ctx) |
599 | 0 | { |
600 | 0 | struct port_lua *port = (struct port_lua *)base; |
601 | 0 | struct mpstream stream; |
602 | 0 | mpstream_init(&stream, out, obuf_reserve_cb, obuf_alloc_cb, |
603 | 0 | luamp_error, port->L); |
604 | 0 | return port_lua_do_dump_with_ctx(base, &stream, HANDLER_ENCODE_CALL_16, |
605 | 0 | ctx); |
606 | 0 | } |
607 | | |
608 | | /** |
609 | | * Dump port contents to Lua. Simply moves values from the Lua stack owned by |
610 | | * the port to the provided Lua stack. |
611 | | */ |
612 | | static void |
613 | | port_lua_dump_lua(struct port *base, struct lua_State *L, |
614 | | enum port_dump_lua_mode mode) |
615 | 0 | { |
616 | 0 | assert(mode == PORT_DUMP_LUA_MODE_FLAT || |
617 | 0 | mode == PORT_DUMP_LUA_MODE_MP_OBJECT); |
618 | 0 | if (mode == PORT_DUMP_LUA_MODE_FLAT) { |
619 | 0 | struct port_lua *port = (struct port_lua *)base; |
620 | 0 | uint32_t size = lua_gettop(port->L) - port->bottom + 1; |
621 | | /* |
622 | | * Duplicate values so that the port can be dumped multiple |
623 | | * times. |
624 | | */ |
625 | 0 | for (size_t i = 0; i < size; i++) |
626 | 0 | lua_pushvalue(port->L, port->bottom + i); |
627 | 0 | lua_xmove(port->L, L, size); |
628 | 0 | port->size = size; |
629 | 0 | } else { |
630 | 0 | port_dump_lua_mp_object_mode_slow(base, L, &fiber()->gc, |
631 | 0 | port_lua_get_msgpack); |
632 | 0 | } |
633 | 0 | } |
634 | | |
635 | | static const char * |
636 | | port_lua_get_msgpack(struct port *base, uint32_t *size) |
637 | 0 | { |
638 | 0 | struct port_lua *port = (struct port_lua *) base; |
639 | 0 | struct region *region = &fiber()->gc; |
640 | 0 | uint32_t region_svp = region_used(region); |
641 | 0 | struct mpstream stream; |
642 | 0 | int port_size = lua_gettop(port->L) - port->bottom + 1; |
643 | 0 | mpstream_init(&stream, region, region_reserve_cb, region_alloc_cb, |
644 | 0 | luamp_error, port->L); |
645 | 0 | mpstream_encode_array(&stream, port_size); |
646 | 0 | int rc = port_lua_do_dump(base, &stream, HANDLER_ENCODE_CALL); |
647 | 0 | if (rc < 0) { |
648 | 0 | region_truncate(region, region_svp); |
649 | 0 | return NULL; |
650 | 0 | } |
651 | 0 | *size = region_used(region) - region_svp; |
652 | 0 | const char *data = region_join(region, *size); |
653 | 0 | if (data == NULL) { |
654 | 0 | diag_set(OutOfMemory, *size, "region", "data"); |
655 | 0 | region_truncate(region, region_svp); |
656 | 0 | return NULL; |
657 | 0 | } |
658 | 0 | return data; |
659 | 0 | } |
660 | | |
661 | | static void |
662 | | port_lua_destroy(struct port *base) |
663 | 0 | { |
664 | 0 | struct port_lua *port = (struct port_lua *)base; |
665 | 0 | assert(port->vtab == &port_lua_vtab); |
666 | 0 | lua_settop(port->L, port->bottom - 1); |
667 | 0 | luaL_unref(tarantool_L, LUA_REGISTRYINDEX, port->ref); |
668 | 0 | } |
669 | | |
670 | | /** |
671 | | * Dump port lua as a YAML document. It is extern since depends on |
672 | | * lyaml module. |
673 | | */ |
674 | | extern const char * |
675 | | port_lua_dump_plain(struct port *port, uint32_t *size); |
676 | | |
677 | | extern struct Mem * |
678 | | port_lua_get_vdbemem(struct port *base, uint32_t *size); |
679 | | |
680 | | const struct port_c_entry * |
681 | | port_lua_get_c_entries(struct port *base) |
682 | 0 | { |
683 | 0 | struct port_lua *port = (struct port_lua *)base; |
684 | 0 | struct lua_State *L = port->L; |
685 | 0 | size_t size = lua_gettop(L) - port->bottom + 1; |
686 | 0 | if (size == 0) |
687 | 0 | return NULL; |
688 | | |
689 | 0 | struct port_c_entry *arr = |
690 | 0 | xregion_alloc_array(&fiber()->gc, struct port_c_entry, size); |
691 | | |
692 | | /* Link the list. */ |
693 | 0 | for (size_t i = 0; i < size - 1; i++) |
694 | 0 | arr[i].next = &arr[i + 1]; |
695 | 0 | arr[size - 1].next = NULL; |
696 | | |
697 | | /* Put values. */ |
698 | 0 | for (size_t arr_idx = 0; arr_idx < size; arr_idx++) { |
699 | 0 | int lua_idx = arr_idx + port->bottom; |
700 | 0 | struct port_c_entry *e = &arr[arr_idx]; |
701 | 0 | switch (lua_type(L, lua_idx)) { |
702 | 0 | case LUA_TNIL: |
703 | 0 | e->type = PORT_C_ENTRY_NULL; |
704 | 0 | break; |
705 | 0 | case LUA_TBOOLEAN: |
706 | 0 | e->type = PORT_C_ENTRY_BOOL; |
707 | 0 | e->boolean = lua_toboolean(L, lua_idx); |
708 | 0 | break; |
709 | 0 | case LUA_TNUMBER: |
710 | 0 | e->type = PORT_C_ENTRY_NUMBER; |
711 | 0 | e->number = lua_tonumber(L, lua_idx); |
712 | 0 | break; |
713 | 0 | case LUA_TSTRING: { |
714 | 0 | e->type = PORT_C_ENTRY_STR; |
715 | 0 | size_t len; |
716 | 0 | const char *data = lua_tolstring(L, lua_idx, &len); |
717 | 0 | e->str.data = data; |
718 | 0 | e->str.size = len; |
719 | 0 | break; |
720 | 0 | } |
721 | 0 | default: { |
722 | 0 | struct tuple *tuple = NULL; |
723 | 0 | tuple = luaT_istuple(L, lua_idx); |
724 | 0 | if (tuple != NULL) { |
725 | 0 | e->type = PORT_C_ENTRY_TUPLE; |
726 | 0 | e->tuple = tuple; |
727 | | /* |
728 | | * Do not reference the tuple: |
729 | | * this entry does not own it. |
730 | | */ |
731 | 0 | break; |
732 | 0 | } |
733 | | |
734 | 0 | size_t len; |
735 | 0 | const char *data = NULL; |
736 | 0 | data = luamp_get(L, lua_idx, &len); |
737 | 0 | if (data != NULL) { |
738 | 0 | e->type = PORT_C_ENTRY_MP_OBJECT; |
739 | 0 | e->mp.data = data; |
740 | 0 | e->mp.size = len; |
741 | 0 | e->mp.ctx = NULL; |
742 | 0 | break; |
743 | 0 | } |
744 | | |
745 | 0 | if (luaL_isnull(L, lua_idx)) { |
746 | 0 | e->type = PORT_C_ENTRY_NULL; |
747 | 0 | break; |
748 | 0 | } |
749 | | |
750 | | /* Unsupported value. */ |
751 | 0 | e->type = PORT_C_ENTRY_UNKNOWN; |
752 | 0 | } |
753 | 0 | } |
754 | 0 | } |
755 | 0 | return arr; |
756 | 0 | } |
757 | | |
758 | | static const struct port_vtab port_lua_vtab = { |
759 | | .dump_msgpack = port_lua_dump, |
760 | | .dump_msgpack_16 = port_lua_dump_16, |
761 | | .dump_lua = port_lua_dump_lua, |
762 | | .dump_plain = port_lua_dump_plain, |
763 | | .get_msgpack = port_lua_get_msgpack, |
764 | | .get_vdbemem = port_lua_get_vdbemem, |
765 | | .get_c_entries = port_lua_get_c_entries, |
766 | | .destroy = port_lua_destroy, |
767 | | }; |
768 | | |
769 | | static inline int |
770 | | box_process_lua(enum handlers handler, struct execute_lua_ctx *ctx, |
771 | | struct port *ret) |
772 | 0 | { |
773 | 0 | lua_State *L = luaT_newthread(tarantool_L); |
774 | 0 | if (L == NULL) |
775 | 0 | return -1; |
776 | 0 | int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); |
777 | 0 | port_lua_create(ret, L); |
778 | 0 | ((struct port_lua *) ret)->ref = coro_ref; |
779 | | |
780 | | /* |
781 | | * A code that need a temporary fiber-local Lua state may |
782 | | * save some time and resources for creating a new state |
783 | | * and use this one. |
784 | | */ |
785 | 0 | bool has_lua_stack = fiber()->storage.lua.stack != NULL; |
786 | 0 | if (!has_lua_stack) |
787 | 0 | fiber()->storage.lua.stack = L; |
788 | |
|
789 | 0 | lua_rawgeti(L, LUA_REGISTRYINDEX, execute_lua_refs[handler]); |
790 | 0 | assert(lua_isfunction(L, -1)); |
791 | 0 | lua_pushlightuserdata(L, ctx); |
792 | 0 | if (luaT_call(L, 1, LUA_MULTRET) != 0) { |
793 | 0 | if (!has_lua_stack) |
794 | 0 | fiber()->storage.lua.stack = NULL; |
795 | 0 | port_lua_destroy(ret); |
796 | 0 | return -1; |
797 | 0 | } |
798 | | |
799 | | /* |
800 | | * Since this field is optional we're not obligated to |
801 | | * keep it until the Lua state will be unreferenced in |
802 | | * port_lua_destroy(). |
803 | | * |
804 | | * There is no much sense to keep it beyond the Lua call, |
805 | | * so let's zap now. |
806 | | * |
807 | | * But: keep the stack if it was present before the call, |
808 | | * because it would be counter-intuitive if the existing |
809 | | * state pointer would be zapped after this function call. |
810 | | */ |
811 | 0 | if (!has_lua_stack) |
812 | 0 | fiber()->storage.lua.stack = NULL; |
813 | |
|
814 | 0 | return 0; |
815 | 0 | } |
816 | | |
817 | | int |
818 | | box_lua_call(const char *name, uint32_t name_len, |
819 | | struct port *args, struct port *ret) |
820 | 0 | { |
821 | 0 | struct execute_lua_ctx ctx; |
822 | 0 | ctx.name = name; |
823 | 0 | ctx.name_len = name_len; |
824 | 0 | ctx.args = args; |
825 | 0 | ctx.takes_raw_args = false; |
826 | 0 | return box_process_lua(HANDLER_CALL, &ctx, ret); |
827 | 0 | } |
828 | | |
829 | | int |
830 | | box_lua_eval(const char *expr, uint32_t expr_len, |
831 | | struct port *args, struct port *ret) |
832 | 0 | { |
833 | 0 | struct execute_lua_ctx ctx; |
834 | 0 | ctx.name = expr; |
835 | 0 | ctx.name_len = expr_len; |
836 | 0 | ctx.args = args; |
837 | 0 | ctx.takes_raw_args = false; |
838 | 0 | return box_process_lua(HANDLER_EVAL, &ctx, ret); |
839 | 0 | } |
840 | | |
841 | | struct func_lua { |
842 | | /** Function object base class. */ |
843 | | struct func base; |
844 | | /** |
845 | | * For a persistent function: a reference to the |
846 | | * function body. Otherwise LUA_REFNIL. |
847 | | */ |
848 | | int lua_ref; |
849 | | }; |
850 | | |
851 | | static struct func_vtab func_lua_vtab; |
852 | | static struct func_vtab func_persistent_lua_vtab; |
853 | | |
854 | | static const char *default_sandbox_exports[] = { |
855 | | "assert", "error", "ipairs", "math", "next", "pairs", "pcall", "print", |
856 | | "select", "string", "table", "tonumber", "tostring", "type", "unpack", |
857 | | "xpcall", "utf8", |
858 | | }; |
859 | | |
860 | | /** |
861 | | * Assemble a new sandbox with given exports table on the top of |
862 | | * a given Lua stack. All modules in exports list are copied |
863 | | * deeply to ensure the immutability of this system object. |
864 | | */ |
865 | | static int |
866 | | prepare_lua_sandbox(struct lua_State *L, const char *exports[], |
867 | | int export_count) |
868 | 0 | { |
869 | 0 | lua_createtable(L, export_count, 0); |
870 | 0 | if (export_count == 0) |
871 | 0 | return 0; |
872 | 0 | int rc = -1; |
873 | 0 | const char *deepcopy = "table.deepcopy"; |
874 | 0 | int luaL_deepcopy_func_ref = LUA_REFNIL; |
875 | 0 | int ret = box_lua_find(L, deepcopy, deepcopy + strlen(deepcopy)); |
876 | 0 | if (ret < 0) |
877 | 0 | goto end; |
878 | 0 | luaL_deepcopy_func_ref = luaL_ref(L, LUA_REGISTRYINDEX); |
879 | 0 | assert(luaL_deepcopy_func_ref != LUA_REFNIL); |
880 | 0 | for (int i = 0; i < export_count; i++) { |
881 | 0 | uint32_t name_len = strlen(exports[i]); |
882 | 0 | ret = box_lua_find(L, exports[i], exports[i] + name_len); |
883 | 0 | if (ret < 0) |
884 | 0 | goto end; |
885 | 0 | switch (lua_type(L, -1)) { |
886 | 0 | case LUA_TTABLE: |
887 | 0 | lua_rawgeti(L, LUA_REGISTRYINDEX, |
888 | 0 | luaL_deepcopy_func_ref); |
889 | 0 | lua_insert(L, -2); |
890 | 0 | lua_call(L, 1, 1); |
891 | 0 | break; |
892 | 0 | case LUA_TFUNCTION: |
893 | 0 | break; |
894 | 0 | default: |
895 | 0 | unreachable(); |
896 | 0 | } |
897 | 0 | lua_setfield(L, -2, exports[i]); |
898 | 0 | } |
899 | 0 | rc = 0; |
900 | 0 | end: |
901 | 0 | luaL_unref(tarantool_L, LUA_REGISTRYINDEX, luaL_deepcopy_func_ref); |
902 | 0 | return rc; |
903 | 0 | } |
904 | | |
905 | | /** |
906 | | * Assemble a Lua function object by user-defined function body. |
907 | | * On success, returns a Lua reference to the loaded function. |
908 | | * On error, returns LUA_NOREF and sets diag. |
909 | | */ |
910 | | static int |
911 | | func_persistent_lua_load(const struct func_def *def) |
912 | 0 | { |
913 | 0 | assert(def->body != NULL); |
914 | 0 | int func_ref = LUA_NOREF; |
915 | 0 | int top = lua_gettop(tarantool_L); |
916 | 0 | struct region *region = &fiber()->gc; |
917 | 0 | size_t region_svp = region_used(region); |
918 | 0 | const char *load_pref = "return "; |
919 | 0 | uint32_t load_str_sz = |
920 | 0 | strlen(load_pref) + strlen(def->body) + 1; |
921 | 0 | char *load_str = region_alloc(region, load_str_sz); |
922 | 0 | if (load_str == NULL) { |
923 | 0 | diag_set(OutOfMemory, load_str_sz, "region", "load_str"); |
924 | 0 | return LUA_NOREF; |
925 | 0 | } |
926 | 0 | snprintf(load_str, load_str_sz, "%s%s", load_pref, def->body); |
927 | | |
928 | | /* |
929 | | * Perform loading of the persistent Lua function |
930 | | * in a new sandboxed Lua thread. The sandbox is |
931 | | * required to guarantee the safety of executing |
932 | | * an arbitrary user-defined code |
933 | | * (e.g. body = 'fiber.yield()'). |
934 | | */ |
935 | 0 | lua_State *coro_L = luaT_newthread(tarantool_L); |
936 | 0 | if (coro_L == NULL) |
937 | 0 | return LUA_NOREF; |
938 | 0 | if (!def->is_sandboxed) { |
939 | | /* |
940 | | * Keep the original env to apply to a non-sandboxed |
941 | | * persistent function. It is necessary since |
942 | | * the created object inherits its parent env. |
943 | | */ |
944 | 0 | lua_getfenv(tarantool_L, -1); |
945 | 0 | lua_insert(tarantool_L, -2); |
946 | 0 | } |
947 | 0 | if (prepare_lua_sandbox(tarantool_L, NULL, 0) != 0) |
948 | 0 | unreachable(); |
949 | 0 | lua_setfenv(tarantool_L, -2); |
950 | 0 | int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); |
951 | 0 | if (luaL_loadstring(coro_L, load_str) != 0 || |
952 | 0 | lua_pcall(coro_L, 0, 1, 0) != 0) { |
953 | 0 | diag_set(ClientError, ER_LOAD_FUNCTION, def->name, |
954 | 0 | luaT_tolstring(coro_L, -1, NULL)); |
955 | 0 | goto end; |
956 | 0 | } |
957 | 0 | if (!lua_isfunction(coro_L, -1)) { |
958 | 0 | diag_set(ClientError, ER_LOAD_FUNCTION, def->name, |
959 | 0 | "given body doesn't define a function"); |
960 | 0 | goto end; |
961 | 0 | } |
962 | 0 | lua_xmove(coro_L, tarantool_L, 1); |
963 | 0 | if (def->is_sandboxed) { |
964 | 0 | if (prepare_lua_sandbox(tarantool_L, default_sandbox_exports, |
965 | 0 | nelem(default_sandbox_exports)) != 0) { |
966 | 0 | diag_add(ClientError, ER_LOAD_FUNCTION, |
967 | 0 | def->name, "can't prepare a Lua sandbox"); |
968 | 0 | goto end; |
969 | 0 | } |
970 | 0 | } else { |
971 | 0 | lua_insert(tarantool_L, -2); |
972 | 0 | } |
973 | 0 | lua_setfenv(tarantool_L, -2); |
974 | 0 | func_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); |
975 | 0 | end: |
976 | 0 | lua_settop(tarantool_L, top); |
977 | 0 | region_truncate(region, region_svp); |
978 | 0 | luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref); |
979 | 0 | return func_ref; |
980 | 0 | } |
981 | | |
982 | | struct func * |
983 | | func_lua_new(const struct func_def *def) |
984 | 0 | { |
985 | 0 | assert(def->language == FUNC_LANGUAGE_LUA); |
986 | 0 | struct func_lua *func = |
987 | 0 | (struct func_lua *) malloc(sizeof(struct func_lua)); |
988 | 0 | if (func == NULL) { |
989 | 0 | diag_set(OutOfMemory, sizeof(*func), "malloc", "func"); |
990 | 0 | return NULL; |
991 | 0 | } |
992 | 0 | if (def->body != NULL) { |
993 | 0 | func->lua_ref = func_persistent_lua_load(def); |
994 | 0 | if (func->lua_ref == LUA_NOREF) { |
995 | 0 | free(func); |
996 | 0 | return NULL; |
997 | 0 | } |
998 | 0 | func->base.vtab = &func_persistent_lua_vtab; |
999 | 0 | } else { |
1000 | 0 | func->lua_ref = LUA_REFNIL; |
1001 | 0 | func->base.vtab = &func_lua_vtab; |
1002 | 0 | } |
1003 | 0 | return &func->base; |
1004 | 0 | } |
1005 | | |
1006 | | static void |
1007 | | func_lua_destroy(struct func *func) |
1008 | 0 | { |
1009 | 0 | assert(func != NULL && func->def->language == FUNC_LANGUAGE_LUA); |
1010 | 0 | assert(func->vtab == &func_lua_vtab); |
1011 | 0 | TRASH(func); |
1012 | 0 | free(func); |
1013 | 0 | } |
1014 | | |
1015 | | static inline int |
1016 | | func_lua_call(struct func *func, struct port *args, struct port *ret) |
1017 | 0 | { |
1018 | 0 | assert(func != NULL && func->def->language == FUNC_LANGUAGE_LUA); |
1019 | 0 | assert(func->vtab == &func_lua_vtab); |
1020 | 0 | struct execute_lua_ctx ctx; |
1021 | 0 | ctx.name = func->def->name; |
1022 | 0 | ctx.name_len = func->def->name_len; |
1023 | 0 | ctx.args = args; |
1024 | 0 | ctx.takes_raw_args = func->def->opts.takes_raw_args; |
1025 | 0 | return box_process_lua(HANDLER_CALL, &ctx, ret); |
1026 | 0 | } |
1027 | | |
1028 | | static struct func_vtab func_lua_vtab = { |
1029 | | .call = func_lua_call, |
1030 | | .destroy = func_lua_destroy, |
1031 | | }; |
1032 | | |
1033 | | static void |
1034 | | func_persistent_lua_unload(struct func_lua *func) |
1035 | 0 | { |
1036 | 0 | luaL_unref(tarantool_L, LUA_REGISTRYINDEX, func->lua_ref); |
1037 | 0 | } |
1038 | | |
1039 | | static void |
1040 | | func_persistent_lua_destroy(struct func *base) |
1041 | 0 | { |
1042 | 0 | assert(base != NULL && base->def->language == FUNC_LANGUAGE_LUA && |
1043 | 0 | base->def->body != NULL); |
1044 | 0 | assert(base->vtab == &func_persistent_lua_vtab); |
1045 | 0 | struct func_lua *func = (struct func_lua *) base; |
1046 | 0 | func_persistent_lua_unload(func); |
1047 | 0 | free(func); |
1048 | 0 | } |
1049 | | |
1050 | | static inline int |
1051 | | func_persistent_lua_call(struct func *base, struct port *args, struct port *ret) |
1052 | 0 | { |
1053 | 0 | assert(base != NULL && base->def->language == FUNC_LANGUAGE_LUA && |
1054 | 0 | base->def->body != NULL); |
1055 | 0 | assert(base->vtab == &func_persistent_lua_vtab); |
1056 | 0 | struct func_lua *func = (struct func_lua *)base; |
1057 | 0 | struct execute_lua_ctx ctx; |
1058 | 0 | ctx.lua_ref = func->lua_ref; |
1059 | 0 | ctx.args = args; |
1060 | 0 | ctx.takes_raw_args = base->def->opts.takes_raw_args; |
1061 | 0 | return box_process_lua(HANDLER_CALL_BY_REF, &ctx, ret); |
1062 | |
|
1063 | 0 | } |
1064 | | |
1065 | | static struct func_vtab func_persistent_lua_vtab = { |
1066 | | .call = func_persistent_lua_call, |
1067 | | .destroy = func_persistent_lua_destroy, |
1068 | | }; |
1069 | | |
1070 | | static int |
1071 | | lbox_module_reload(lua_State *L) |
1072 | 0 | { |
1073 | 0 | if (box_check_configured() != 0) |
1074 | 0 | return luaT_error(L); |
1075 | 0 | const char *name = luaT_checkstring(L, 1); |
1076 | 0 | if (box_module_reload(name) != 0) |
1077 | 0 | return luaT_error(L); |
1078 | 0 | return 0; |
1079 | 0 | } |
1080 | | |
1081 | | int |
1082 | | lbox_func_call(struct lua_State *L) |
1083 | 0 | { |
1084 | 0 | if (box_check_configured() != 0) |
1085 | 0 | return luaT_error(L); |
1086 | 0 | if (lua_gettop(L) < 1 || !lua_isstring(L, 1)) { |
1087 | 0 | diag_set(IllegalParams, "Use func:call(...)"); |
1088 | 0 | return luaT_error(L); |
1089 | 0 | } |
1090 | | |
1091 | 0 | size_t name_len; |
1092 | 0 | const char *name = lua_tolstring(L, 1, &name_len); |
1093 | 0 | struct func *func = func_by_name(name, name_len); |
1094 | 0 | if (func == NULL) { |
1095 | 0 | diag_set(ClientError, ER_NO_SUCH_FUNCTION, |
1096 | 0 | tt_cstr(name, name_len)); |
1097 | 0 | return luaT_error(L); |
1098 | 0 | } |
1099 | | |
1100 | | /* |
1101 | | * Prepare a new Lua stack for input arguments |
1102 | | * before the function call to pass it into the |
1103 | | * pcall-sandboxed tarantool_L handler. |
1104 | | */ |
1105 | 0 | lua_State *args_L = luaT_newthread(tarantool_L); |
1106 | 0 | if (args_L == NULL) |
1107 | 0 | return luaT_error(L); |
1108 | 0 | int coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX); |
1109 | 0 | lua_xmove(L, args_L, lua_gettop(L) - 1); |
1110 | 0 | struct port args; |
1111 | 0 | port_lua_create(&args, args_L); |
1112 | 0 | ((struct port_lua *) &args)->ref = coro_ref; |
1113 | |
|
1114 | 0 | struct port ret; |
1115 | 0 | if (func_call(func, &args, &ret) != 0) { |
1116 | 0 | port_destroy(&args); |
1117 | 0 | return luaT_error(L); |
1118 | 0 | } |
1119 | | |
1120 | 0 | int top = lua_gettop(L); |
1121 | 0 | port_dump_lua(&ret, L, PORT_DUMP_LUA_MODE_FLAT); |
1122 | 0 | int cnt = lua_gettop(L) - top; |
1123 | |
|
1124 | 0 | port_destroy(&ret); |
1125 | 0 | port_destroy(&args); |
1126 | 0 | return cnt; |
1127 | 0 | } |
1128 | | |
1129 | | static void |
1130 | | lbox_func_new(struct lua_State *L, struct func *func) |
1131 | 0 | { |
1132 | 0 | lua_getfield(L, LUA_GLOBALSINDEX, "box"); |
1133 | 0 | lua_getfield(L, -1, "func"); |
1134 | 0 | if (!lua_istable(L, -1)) { |
1135 | 0 | lua_pop(L, 1); /* pop nil */ |
1136 | 0 | lua_newtable(L); |
1137 | 0 | lua_setfield(L, -2, "func"); |
1138 | 0 | lua_getfield(L, -1, "func"); |
1139 | 0 | } |
1140 | 0 | lua_rawgeti(L, -1, func->def->fid); |
1141 | 0 | if (lua_isnil(L, -1)) { |
1142 | | /* |
1143 | | * If the function already exists, modify it, |
1144 | | * rather than create a new one -- to not |
1145 | | * invalidate Lua variable references to old func |
1146 | | * outside the box.schema.func[]. |
1147 | | */ |
1148 | 0 | lua_pop(L, 1); |
1149 | 0 | lua_newtable(L); |
1150 | 0 | lua_rawseti(L, -2, func->def->fid); |
1151 | 0 | lua_rawgeti(L, -1, func->def->fid); |
1152 | 0 | } else { |
1153 | | /* Clear the reference to old func by old name. */ |
1154 | 0 | lua_getfield(L, -1, "name"); |
1155 | 0 | lua_pushnil(L); |
1156 | 0 | lua_settable(L, -4); |
1157 | 0 | } |
1158 | 0 | int top = lua_gettop(L); |
1159 | 0 | lua_pushstring(L, "id"); |
1160 | 0 | lua_pushnumber(L, func->def->fid); |
1161 | 0 | lua_settable(L, top); |
1162 | 0 | lua_pushstring(L, "name"); |
1163 | 0 | lua_pushstring(L, func->def->name); |
1164 | 0 | lua_settable(L, top); |
1165 | 0 | lua_pushstring(L, "setuid"); |
1166 | 0 | lua_pushboolean(L, func->def->setuid); |
1167 | 0 | lua_settable(L, top); |
1168 | 0 | lua_pushstring(L, "language"); |
1169 | 0 | lua_pushstring(L, func_language_strs[func->def->language]); |
1170 | 0 | lua_settable(L, top); |
1171 | 0 | lua_pushstring(L, "returns"); |
1172 | 0 | lua_pushstring(L, field_type_strs[func->def->returns]); |
1173 | 0 | lua_settable(L, top); |
1174 | 0 | lua_pushstring(L, "aggregate"); |
1175 | 0 | lua_pushstring(L, func_aggregate_strs[func->def->aggregate]); |
1176 | 0 | lua_settable(L, top); |
1177 | 0 | lua_pushstring(L, "body"); |
1178 | 0 | if (func->def->body != NULL) |
1179 | 0 | lua_pushstring(L, func->def->body); |
1180 | 0 | else |
1181 | 0 | lua_pushnil(L); |
1182 | 0 | lua_settable(L, top); |
1183 | 0 | lua_pushstring(L, "comment"); |
1184 | 0 | if (func->def->comment != NULL) |
1185 | 0 | lua_pushstring(L, func->def->comment); |
1186 | 0 | else |
1187 | 0 | lua_pushnil(L); |
1188 | 0 | lua_settable(L, top); |
1189 | 0 | lua_pushstring(L, "exports"); |
1190 | 0 | lua_newtable(L); |
1191 | 0 | lua_pushboolean(L, func->def->exports.lua); |
1192 | 0 | lua_setfield(L, -2, "lua"); |
1193 | 0 | lua_pushboolean(L, func->def->exports.sql); |
1194 | 0 | lua_setfield(L, -2, "sql"); |
1195 | 0 | lua_settable(L, -3); |
1196 | 0 | lua_pushstring(L, "is_deterministic"); |
1197 | 0 | lua_pushboolean(L, func->def->is_deterministic); |
1198 | 0 | lua_settable(L, top); |
1199 | 0 | lua_pushstring(L, "is_multikey"); |
1200 | 0 | lua_pushboolean(L, func->def->opts.is_multikey); |
1201 | 0 | lua_settable(L, top); |
1202 | 0 | lua_pushstring(L, "takes_raw_args"); |
1203 | 0 | lua_pushboolean(L, func->def->opts.takes_raw_args); |
1204 | 0 | lua_settable(L, top); |
1205 | 0 | lua_pushstring(L, "is_sandboxed"); |
1206 | 0 | if (func->def->body != NULL) |
1207 | 0 | lua_pushboolean(L, func->def->is_sandboxed); |
1208 | 0 | else |
1209 | 0 | lua_pushnil(L); |
1210 | 0 | lua_settable(L, top); |
1211 | | |
1212 | | /* Bless func object. */ |
1213 | 0 | lua_getfield(L, LUA_GLOBALSINDEX, "box"); |
1214 | 0 | lua_pushstring(L, "schema"); |
1215 | 0 | lua_gettable(L, -2); |
1216 | 0 | lua_pushstring(L, "func"); |
1217 | 0 | lua_gettable(L, -2); |
1218 | 0 | lua_pushstring(L, "bless"); |
1219 | 0 | lua_gettable(L, -2); |
1220 | |
|
1221 | 0 | lua_pushvalue(L, top); |
1222 | 0 | lua_call(L, 1, 0); |
1223 | 0 | lua_pop(L, 3); |
1224 | |
|
1225 | 0 | lua_setfield(L, -2, func->def->name); |
1226 | |
|
1227 | 0 | lua_pop(L, 2); |
1228 | 0 | } |
1229 | | |
1230 | | static void |
1231 | | lbox_func_delete(struct lua_State *L, struct func *func) |
1232 | 0 | { |
1233 | 0 | uint32_t fid = func->def->fid; |
1234 | 0 | lua_getfield(L, LUA_GLOBALSINDEX, "box"); |
1235 | 0 | lua_getfield(L, -1, "func"); |
1236 | 0 | assert(!lua_isnil(L, -1)); |
1237 | 0 | lua_rawgeti(L, -1, fid); |
1238 | 0 | if (!lua_isnil(L, -1)) { |
1239 | 0 | lua_getfield(L, -1, "name"); |
1240 | 0 | lua_pushnil(L); |
1241 | 0 | lua_rawset(L, -4); |
1242 | 0 | lua_pop(L, 1); /* pop func */ |
1243 | 0 | lua_pushnil(L); |
1244 | 0 | lua_rawseti(L, -2, fid); |
1245 | 0 | } else { |
1246 | 0 | lua_pop(L, 1); |
1247 | 0 | } |
1248 | 0 | lua_pop(L, 2); /* box, func */ |
1249 | 0 | } |
1250 | | |
1251 | | static int |
1252 | | lbox_func_new_or_delete(struct trigger *trigger, void *event) |
1253 | 0 | { |
1254 | 0 | struct lua_State *L = (struct lua_State *) trigger->data; |
1255 | 0 | struct func *func = (struct func *)event; |
1256 | 0 | if (!func->def->exports.lua) |
1257 | 0 | return 0; |
1258 | 0 | if (func_by_id(func->def->fid) != NULL) |
1259 | 0 | lbox_func_new(L, func); |
1260 | 0 | else |
1261 | 0 | lbox_func_delete(L, func); |
1262 | 0 | return 0; |
1263 | 0 | } |
1264 | | |
1265 | | static int |
1266 | | lbox_box_lua_call_runtime_priv_reset(struct lua_State *L) |
1267 | 0 | { |
1268 | 0 | if (lua_gettop(L) != 0) { |
1269 | 0 | diag_set(IllegalParams, |
1270 | 0 | "Usage: box.internal.lua_call_runtime_priv_reset()"); |
1271 | 0 | return luaT_error(L); |
1272 | 0 | } |
1273 | | |
1274 | 0 | box_lua_call_runtime_priv_reset(); |
1275 | 0 | return 0; |
1276 | 0 | } |
1277 | | |
1278 | | static int |
1279 | | lbox_box_lua_call_runtime_priv_grant(struct lua_State *L) |
1280 | 0 | { |
1281 | 0 | if (lua_gettop(L) != 2 || lua_type(L, 1) != LUA_TSTRING || |
1282 | 0 | lua_type(L, 2) != LUA_TSTRING) { |
1283 | 0 | diag_set(IllegalParams, |
1284 | 0 | "Usage: box.internal.lua_call_runtime_priv_grant(user, func)"); |
1285 | 0 | return luaT_error(L); |
1286 | 0 | } |
1287 | | |
1288 | 0 | size_t grantee_name_len; |
1289 | 0 | const char *grantee_name = luaL_checklstring(L, 1, &grantee_name_len); |
1290 | |
|
1291 | 0 | size_t func_name_len; |
1292 | 0 | const char *func_name = luaL_checklstring(L, 2, &func_name_len); |
1293 | |
|
1294 | 0 | box_lua_call_runtime_priv_grant(grantee_name, |
1295 | 0 | (uint32_t)grantee_name_len, |
1296 | 0 | func_name, (uint32_t)func_name_len); |
1297 | 0 | return 0; |
1298 | 0 | } |
1299 | | |
1300 | | static void |
1301 | | call_serializer_update_options(void) |
1302 | 0 | { |
1303 | 0 | luaL_serializer_copy_options(&call_serializer_no_error_ext, |
1304 | 0 | luaL_msgpack_default); |
1305 | 0 | call_serializer_no_error_ext.encode_error_as_ext = 0; |
1306 | 0 | } |
1307 | | |
1308 | | static int |
1309 | | on_msgpack_serializer_update(struct trigger *trigger, void *event) |
1310 | 0 | { |
1311 | 0 | (void)trigger; |
1312 | 0 | (void)event; |
1313 | 0 | call_serializer_update_options(); |
1314 | 0 | return 0; |
1315 | 0 | } |
1316 | | |
1317 | | static TRIGGER(on_alter_func_in_lua, lbox_func_new_or_delete); |
1318 | | |
1319 | | static const struct luaL_Reg boxlib_internal[] = { |
1320 | | {"call_loadproc", lbox_call_loadproc}, |
1321 | | {"module_reload", lbox_module_reload}, |
1322 | | {"func_call", lbox_func_call}, |
1323 | | {"lua_call_runtime_priv_grant", lbox_box_lua_call_runtime_priv_grant}, |
1324 | | {"lua_call_runtime_priv_reset", lbox_box_lua_call_runtime_priv_reset}, |
1325 | | {NULL, NULL} |
1326 | | }; |
1327 | | |
1328 | | void |
1329 | | box_lua_call_init(struct lua_State *L) |
1330 | 0 | { |
1331 | 0 | call_serializer_update_options(); |
1332 | 0 | trigger_create(&call_serializer_no_error_ext.update_trigger, |
1333 | 0 | on_msgpack_serializer_update, NULL, NULL); |
1334 | 0 | trigger_add(&luaL_msgpack_default->on_update, |
1335 | 0 | &call_serializer_no_error_ext.update_trigger); |
1336 | |
|
1337 | 0 | luaL_findtable(L, LUA_GLOBALSINDEX, "box.internal", 0); |
1338 | 0 | luaL_setfuncs(L, boxlib_internal, 0); |
1339 | 0 | lua_pop(L, 1); |
1340 | | /* |
1341 | | * Register the trigger that will push persistent |
1342 | | * Lua functions objects to Lua. |
1343 | | */ |
1344 | 0 | on_alter_func_in_lua.data = L; |
1345 | 0 | trigger_add(&on_alter_func, &on_alter_func_in_lua); |
1346 | |
|
1347 | 0 | lua_CFunction handles[] = { |
1348 | 0 | [HANDLER_CALL] = execute_lua_call, |
1349 | 0 | [HANDLER_CALL_BY_REF] = execute_lua_call_by_ref, |
1350 | 0 | [HANDLER_ENCODE_CALL] = encode_lua_call, |
1351 | 0 | [HANDLER_ENCODE_CALL_16] = encode_lua_call_16, |
1352 | 0 | [HANDLER_EVAL] = execute_lua_eval, |
1353 | 0 | }; |
1354 | |
|
1355 | 0 | for (int i = 0; i < HANDLER_MAX; i++) { |
1356 | 0 | lua_pushcfunction(L, handles[i]); |
1357 | 0 | execute_lua_refs[i] = luaL_ref(L, LUA_REGISTRYINDEX); |
1358 | 0 | } |
1359 | |
|
1360 | | #if 0 |
1361 | | /* Get CTypeID for `struct port *' */ |
1362 | | int rc = luaL_cdef(L, "struct port;"); |
1363 | | assert(rc == 0); |
1364 | | (void) rc; |
1365 | | CTID_STRUCT_PORT_PTR = luaL_ctypeid(L, "struct port *"); |
1366 | | assert(CTID_STRUCT_TUPLE_REF != 0); |
1367 | | #endif |
1368 | 0 | } |