• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 6340880138

28 Sep 2023 03:15PM UTC coverage: 88.298% (+0.06%) from 88.241%
6340880138

push

github

fckxorg
Restore cur_L for specific Lua/C API use case.

Thanks to Peter Cawley.

(cherry-picked from commit e86990f7f)

Consider the following Lua C API function:

```
static int error_after_coroutine_return(lua_State *L)
{
	lua_State *innerL = lua_newthread(L);
	luaL_loadstring(innerL, "print('inner coro')");
	lua_pcall(innerL, 0, 0, 0);
	luaL_error(L, "my fancy error");
	return 0;
}
```

And the following Lua script:
```
local libcur_L = require('libcur_L')

local function onesnap_f(var)
  if var then
    return 1
  else
    return 0
  end
end

-- Compile function to trace with snapshot.
if jit then jit.opt.start('hotloop=1') end
onesnap_f(true)
onesnap_f(true)

local r, s = pcall(libcur_L.error_after_coroutine_return)
onesnap_f(false)
```

This is the only case when `cur_L` is not restored, according to
the analysis done in https://github.com/LuaJIT/LuaJIT/issues/1066.

This patch changes the error-catching routine, so now the patch
sets the actual cur_L there.
Now it is possible to throw errors on non-executing coroutines,
which is a violation of the Lua C API. So, even though it is now
possible, that behavior should be avoided anyway.

Maxim Kokryashkin:
* added the description for the problem

Resolves tarantool/tarantool#6323

5344 of 5972 branches covered (0.0%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 1 file covered. (100.0%)

20499 of 23296 relevant lines covered (87.99%)

2744986.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.69
/src/lj_state.c
1
/*
2
** State and stack handling.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
**
5
** Portions taken verbatim or adapted from the Lua interpreter.
6
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
7
*/
8

9
#define lj_state_c
10
#define LUA_CORE
11

12
#include "lj_obj.h"
13
#include "lj_gc.h"
14
#include "lj_err.h"
15
#include "lj_buf.h"
16
#include "lj_str.h"
17
#include "lj_tab.h"
18
#include "lj_func.h"
19
#include "lj_meta.h"
20
#include "lj_state.h"
21
#include "lj_frame.h"
22
#if LJ_HASFFI
23
#include "lj_ctype.h"
24
#endif
25
#include "lj_trace.h"
26
#include "lj_dispatch.h"
27
#include "lj_vm.h"
28
#include "lj_lex.h"
29
#include "lj_alloc.h"
30
#include "luajit.h"
31

32
#if LJ_HASMEMPROF
33
#include "lj_memprof.h"
34
#endif
35

36
#if LJ_HASSYSPROF
37
#include "lj_sysprof.h"
38
#endif
39

40
/* -- Stack handling ------------------------------------------------------ */
41

42
/* Stack sizes. */
43
#define LJ_STACK_MIN        LUA_MINSTACK        /* Min. stack size. */
44
#define LJ_STACK_MAX        LUAI_MAXSTACK        /* Max. stack size. */
45
#define LJ_STACK_START        (2*LJ_STACK_MIN)        /* Starting stack size. */
46
#define LJ_STACK_MAXEX        (LJ_STACK_MAX + 1 + LJ_STACK_EXTRA)
47

48
/* Explanation of LJ_STACK_EXTRA:
49
**
50
** Calls to metamethods store their arguments beyond the current top
51
** without checking for the stack limit. This avoids stack resizes which
52
** would invalidate passed TValue pointers. The stack check is performed
53
** later by the function header. This can safely resize the stack or raise
54
** an error. Thus we need some extra slots beyond the current stack limit.
55
**
56
** Most metamethods need 4 slots above top (cont, mobj, arg1, arg2) plus
57
** one extra slot if mobj is not a function. Only lj_meta_tset needs 5
58
** slots above top, but then mobj is always a function. So we can get by
59
** with 5 extra slots.
60
** LJ_FR2: We need 2 more slots for the frame PC and the continuation PC.
61
*/
62

63
/* Resize stack slots and adjust pointers in state. */
64
static void resizestack(lua_State *L, MSize n)
321✔
65
{
66
  TValue *st, *oldst = tvref(L->stack);
321✔
67
  ptrdiff_t delta;
321✔
68
  MSize oldsize = L->stacksize;
321✔
69
  MSize realsize = n + 1 + LJ_STACK_EXTRA;
321✔
70
  GCobj *up;
321✔
71
  int32_t oldvmstate = G(L)->vmstate;
321✔
72

73
  lj_assertL((MSize)(tvref(L->maxstack)-oldst) == L->stacksize-LJ_STACK_EXTRA-1,
321✔
74
             "inconsistent stack size");
75

76
  /*
77
  ** Lua stack is inconsistent while reallocation, profilers
78
  ** depend on vmstate during reports, so set vmstate to INTERP
79
  ** to avoid inconsistent behaviour.
80
  */
81
  setvmstate(G(L), INTERP);
321✔
82
  st = (TValue *)lj_mem_realloc(L, tvref(L->stack),
642✔
83
                                (MSize)(oldsize*sizeof(TValue)),
321✔
84
                                (MSize)(realsize*sizeof(TValue)));
321✔
85
  setmref(L->stack, st);
321✔
86
  delta = (char *)st - (char *)oldst;
321✔
87
  setmref(L->maxstack, st + n);
321✔
88
  while (oldsize < realsize)  /* Clear new slots. */
157,405✔
89
    setnilV(st + oldsize++);
157,084✔
90
  L->stacksize = realsize;
321✔
91
  if ((size_t)(mref(G(L)->jit_base, char) - (char *)oldst) < oldsize)
321✔
92
    setmref(G(L)->jit_base, mref(G(L)->jit_base, char) + delta);
×
93
  L->base = (TValue *)((char *)L->base + delta);
321✔
94
  L->top = (TValue *)((char *)L->top + delta);
321✔
95
  for (up = gcref(L->openupval); up != NULL; up = gcnext(up))
2,362✔
96
    setmref(gco2uv(up)->v, (TValue *)((char *)uvval(gco2uv(up)) + delta));
2,041✔
97

98
  G(L)->vmstate = oldvmstate;
321✔
99
}
321✔
100

101
/* Relimit stack after error, in case the limit was overdrawn. */
102
void lj_state_relimitstack(lua_State *L)
26,974✔
103
{
104
  if (L->stacksize > LJ_STACK_MAXEX && L->top-tvref(L->stack) < LJ_STACK_MAX-1)
26,974✔
105
    resizestack(L, LJ_STACK_MAX);
6✔
106
}
26,974✔
107

108
/* Try to shrink the stack (called from GC). */
109
void lj_state_shrinkstack(lua_State *L, MSize used)
1,570,107✔
110
{
111
  if (L->stacksize > LJ_STACK_MAXEX)
1,570,107✔
112
    return;  /* Avoid stack shrinking while handling stack overflow. */
113
  if (4*used < L->stacksize &&
1,570,107✔
114
      2*(LJ_STACK_START+LJ_STACK_EXTRA) < L->stacksize &&
54✔
115
      /* Don't shrink stack of live trace. */
116
      (tvref(G(L)->jit_base) == NULL || obj2gco(L) != gcref(G(L)->cur_L)))
54✔
117
    resizestack(L, L->stacksize >> 1);
51✔
118
}
119

120
/* Try to grow stack. */
121
void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need)
264✔
122
{
123
  MSize n;
264✔
124
  if (L->stacksize > LJ_STACK_MAXEX)  /* Overflow while handling overflow? */
264✔
125
    lj_err_throw(L, LUA_ERRERR);
×
126
  n = L->stacksize + need;
264✔
127
  if (n > LJ_STACK_MAX) {
264✔
128
    n += 2*LUA_MINSTACK;
6✔
129
  } else if (n < 2*L->stacksize) {
258✔
130
    n = 2*L->stacksize;
250✔
131
    if (n >= LJ_STACK_MAX)
250✔
132
      n = LJ_STACK_MAX;
133
  }
134
  resizestack(L, n);
264✔
135
  if (L->stacksize > LJ_STACK_MAXEX)
264✔
136
    lj_err_msg(L, LJ_ERR_STKOV);
6✔
137
}
258✔
138

139
void LJ_FASTCALL lj_state_growstack1(lua_State *L)
×
140
{
141
  lj_state_growstack(L, 1);
×
142
}
×
143

144
/* Allocate basic stack for new state. */
145
static void stack_init(lua_State *L1, lua_State *L)
1,337✔
146
{
147
  TValue *stend, *st = lj_mem_newvec(L, LJ_STACK_START+LJ_STACK_EXTRA, TValue);
1,337✔
148
  setmref(L1->stack, st);
1,337✔
149
  L1->stacksize = LJ_STACK_START + LJ_STACK_EXTRA;
1,337✔
150
  stend = st + L1->stacksize;
1,337✔
151
  setmref(L1->maxstack, stend - LJ_STACK_EXTRA - 1);
1,337✔
152
  setthreadV(L1, st++, L1);  /* Needed for curr_funcisL() on empty stack. */
1,337✔
153
  if (LJ_FR2) setnilV(st++);
1,337✔
154
  L1->base = L1->top = st;
1,337✔
155
  while (st < stend)  /* Clear new slots. */
61,502✔
156
    setnilV(st++);
60,165✔
157
}
1,337✔
158

159
/* -- State handling ------------------------------------------------------ */
160

161
/* Open parts that may cause memory-allocation errors. */
162
static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud)
241✔
163
{
164
  global_State *g = G(L);
241✔
165
  UNUSED(dummy);
241✔
166
  UNUSED(ud);
241✔
167
  stack_init(L, L);
241✔
168
  /* NOBARRIER: State initialization, all objects are white. */
169
  setgcref(L->env, obj2gco(lj_tab_new(L, 0, LJ_MIN_GLOBAL)));
241✔
170
  settabV(L, registry(L), lj_tab_new(L, 0, LJ_MIN_REGISTRY));
241✔
171
  lj_str_resize(L, LJ_MIN_STRTAB-1);
241✔
172
  lj_meta_init(L);
241✔
173
  lj_lex_init(L);
241✔
174
  fixstring(lj_err_str(L, LJ_ERR_ERRMEM));  /* Preallocate memory error msg. */
241✔
175
  g->gc.threshold = 4*g->gc.total;
241✔
176
  lj_trace_initstate(g);
241✔
177
  lj_err_verify();
241✔
178
  return NULL;
241✔
179
}
180

181
static void close_state(lua_State *L)
233✔
182
{
183
  global_State *g = G(L);
233✔
184
  lj_func_closeuv(L, tvref(L->stack));
233✔
185
  lj_gc_freeall(g);
233✔
186
  lj_assertG(gcref(g->gc.root) == obj2gco(L),
233✔
187
             "main thread is not first GC object");
188
  lj_assertG(g->strnum == 0, "leaked %d strings", g->strnum);
233✔
189
  lj_trace_freestate(g);
233✔
190
#if LJ_HASFFI
191
  lj_ctype_freestate(g);
233✔
192
#endif
193
  lj_mem_freevec(g, g->strhash, g->strmask+1, GCRef);
233✔
194
  lj_buf_free(g, &g->tmpbuf);
233✔
195
  lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue);
233✔
196
#if LJ_64
197
  if (mref(g->gc.lightudseg, uint32_t)) {
233✔
198
    MSize segnum = g->gc.lightudnum ? (2 << lj_fls(g->gc.lightudnum)) : 2;
230✔
199
    lj_mem_freevec(g, mref(g->gc.lightudseg, uint32_t), segnum, uint32_t);
230✔
200
  }
201
#endif
202
  lj_assertG(g->gc.total == sizeof(GG_State),
233✔
203
             "memory leak of %lld bytes",
204
             (long long)(g->gc.total - sizeof(GG_State)));
205
#ifndef LUAJIT_USE_SYSMALLOC
206
  if (g->allocf == lj_alloc_f)
233✔
207
    lj_alloc_destroy(g->allocd);
233✔
208
  else
209
#endif
210
    g->allocf(g->allocd, G2GG(g), sizeof(GG_State), 0);
×
211
}
233✔
212

213
#if LJ_64 && !LJ_GC64 && !(defined(LUAJIT_USE_VALGRIND) && defined(LUAJIT_USE_SYSMALLOC))
214
lua_State *lj_state_newstate(lua_Alloc f, void *ud)
215
#else
216
LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
241✔
217
#endif
218
{
219
  GG_State *GG = (GG_State *)f(ud, NULL, 0, sizeof(GG_State));
241✔
220
  lua_State *L = &GG->L;
241✔
221
  global_State *g = &GG->g;
241✔
222
  if (GG == NULL || !checkptrGC(GG)) return NULL;
241✔
223
  memset(GG, 0, sizeof(GG_State));
241✔
224
  L->gct = ~LJ_TTHREAD;
241✔
225
  L->marked = LJ_GC_WHITE0 | LJ_GC_FIXED | LJ_GC_SFIXED;  /* Prevent free. */
241✔
226
  L->dummy_ffid = FF_C;
241✔
227
  setmref(L->glref, g);
241✔
228
  g->gc.currentwhite = LJ_GC_WHITE0 | LJ_GC_FIXED;
241✔
229
  g->strempty.marked = LJ_GC_WHITE0;
241✔
230
  g->strempty.gct = ~LJ_TSTR;
241✔
231
  g->allocf = f;
241✔
232
  g->allocd = ud;
241✔
233
  setgcref(g->mainthref, obj2gco(L));
241✔
234
  setgcref(g->uvhead.prev, obj2gco(&g->uvhead));
241✔
235
  setgcref(g->uvhead.next, obj2gco(&g->uvhead));
241✔
236
  g->strmask = ~(MSize)0;
241✔
237
  setnilV(registry(L));
241✔
238
  setnilV(&g->nilnode.val);
241✔
239
  setnilV(&g->nilnode.key);
241✔
240
#if !LJ_GC64
241
  setmref(g->nilnode.freetop, &g->nilnode);
242
#endif
243
  lj_buf_init(NULL, &g->tmpbuf);
241✔
244
  g->gc.state = GCSpause;
241✔
245
  setgcref(g->gc.root, obj2gco(L));
241✔
246
  setmref(g->gc.sweep, &g->gc.root);
241✔
247
  g->gc.allocated = g->gc.total = sizeof(GG_State);
241✔
248
  g->gc.pause = LUAI_GCPAUSE;
241✔
249
  g->gc.stepmul = LUAI_GCMUL;
241✔
250
  lj_dispatch_init((GG_State *)L);
241✔
251
  L->status = LUA_ERRERR+1;  /* Avoid touching the stack upon memory error. */
241✔
252
  if (lj_vm_cpcall(L, NULL, NULL, cpluaopen) != 0) {
241✔
253
    /* Memory allocation error: free partial state. */
254
    close_state(L);
×
255
    return NULL;
×
256
  }
257
  L->status = LUA_OK;
241✔
258
  return L;
241✔
259
}
260

261
static TValue *cpfinalize(lua_State *L, lua_CFunction dummy, void *ud)
253✔
262
{
263
  UNUSED(dummy);
253✔
264
  UNUSED(ud);
253✔
265
  lj_gc_finalize_cdata(L);
253✔
266
  lj_gc_finalize_udata(L);
253✔
267
  /* Frame pop omitted. */
268
  return NULL;
242✔
269
}
270

271
LUA_API void lua_close(lua_State *L)
233✔
272
{
273
  global_State *g = G(L);
233✔
274
  int i;
233✔
275
  L = mainthread(g);  /* Only the main thread can be closed. */
233✔
276
#if LJ_HASMEMPROF
277
  lj_memprof_stop(L);
233✔
278
#endif
279
#if LJ_HASSYSPROF
280
  lj_sysprof_stop(L);
233✔
281
#endif
282
#if LJ_HASPROFILE
283
  luaJIT_profile_stop(L);
233✔
284
#endif
285
  setgcrefnull(g->cur_L);
233✔
286
  lj_func_closeuv(L, tvref(L->stack));
233✔
287
  lj_gc_separateudata(g, 1);  /* Separate udata which have GC metamethods. */
233✔
288
#if LJ_HASJIT
289
  G2J(g)->flags &= ~JIT_F_ON;
233✔
290
  G2J(g)->state = LJ_TRACE_IDLE;
233✔
291
  lj_dispatch_update(g);
233✔
292
#endif
293
  for (i = 0;;) {
233✔
294
    hook_enter(g);
253✔
295
    L->status = LUA_OK;
253✔
296
    L->base = L->top = tvref(L->stack) + 1 + LJ_FR2;
253✔
297
    L->cframe = NULL;
253✔
298
    if (lj_vm_cpcall(L, NULL, NULL, cpfinalize) == LUA_OK) {
253✔
299
      if (++i >= 10) break;
242✔
300
      lj_gc_separateudata(g, 1);  /* Separate udata again. */
241✔
301
      if (gcref(g->gc.mmudata) == NULL)  /* Until nothing is left to do. */
241✔
302
        break;
303
    }
304
  }
305
  close_state(L);
233✔
306
}
233✔
307

308
lua_State *lj_state_new(lua_State *L)
1,096✔
309
{
310
  lua_State *L1 = lj_mem_newobj(L, lua_State);
1,096✔
311
  L1->gct = ~LJ_TTHREAD;
1,096✔
312
  L1->dummy_ffid = FF_C;
1,096✔
313
  L1->status = LUA_OK;
1,096✔
314
  L1->stacksize = 0;
1,096✔
315
  setmref(L1->stack, NULL);
1,096✔
316
  L1->cframe = NULL;
1,096✔
317
  /* NOBARRIER: The lua_State is new (marked white). */
318
  setgcrefnull(L1->openupval);
1,096✔
319
  setmrefr(L1->glref, L->glref);
1,096✔
320
  setgcrefr(L1->env, L->env);
1,096✔
321
  stack_init(L1, L);  /* init stack */
1,096✔
322
  lj_assertL(iswhite(obj2gco(L1)), "new thread object is not white");
1,096✔
323
  return L1;
1,096✔
324
}
325

326
void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L)
1,096✔
327
{
328
  lj_assertG(L != mainthread(g), "free of main thread");
1,096✔
329
  if (obj2gco(L) == gcref(g->cur_L))
1,096✔
330
    setgcrefnull(g->cur_L);
×
331
  lj_func_closeuv(L, tvref(L->stack));
1,096✔
332
  lj_assertG(gcref(L->openupval) == NULL, "stale open upvalues");
1,096✔
333
  lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue);
1,096✔
334
  lj_mem_freet(g, L);
1,096✔
335
}
1,096✔
336

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc