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

tarantool / luajit / 5973601545

25 Aug 2023 08:22AM UTC coverage: 88.113% (+0.2%) from 87.9%
5973601545

push

github

igormunkin
Revert to trival pow() optimizations to prevent inaccuracies.

(cherry-picked from commit 96d6d5032)

This patch fixes different misbehaviours between JIT-compiled code and
the interpreter for power operator in the following ways:
* Drop folding optimizations for base ^ n => base * base ..., as far as
  pow(base, n) isn't interchangeable with just multiplicity of numbers
  and depends on the <math.h> implementation.
* Since the internal power function is inaccurate for very big or small
  powers, it is dropped, and `pow()` from the standard library is used
  instead. To save consistency between JIT behaviour and the VM,
  narrowing optimization is dropped, and only trivial folding
  optimizations are used. Also, `math_extern2` version with two
  parameters is dropped, since it's no longer used.

Also, this fixes failures of the [220/502] lib/string/format/num.lua
test [1] from the LuaJIT-test suite.

[1]: https://www.exploringbinary.com/incorrect-floating-point-to-decimal-conversions/

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#8825

Reviewed-by: Maxim Kokryashkin <m.kokryashkin@tarantool.org>
Reviewed-by: Sergey Bronnikov <sergeyb@tarantool.org>
Signed-off-by: Igor Munkin <imun@tarantool.org>

5322 of 5963 branches covered (0.0%)

Branch coverage included in aggregate %.

11 of 11 new or added lines in 5 files covered. (100.0%)

20443 of 23278 relevant lines covered (87.82%)

1292502.03 hits per line

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

89.45
/src/lj_debug.c
1
/*
2
** Debugging and introspection.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
*/
5

6
#define lj_debug_c
7
#define LUA_CORE
8

9
#include "lj_obj.h"
10
#include "lj_err.h"
11
#include "lj_debug.h"
12
#include "lj_buf.h"
13
#include "lj_tab.h"
14
#include "lj_state.h"
15
#include "lj_frame.h"
16
#include "lj_bc.h"
17
#include "lj_strfmt.h"
18
#if LJ_HASJIT
19
#include "lj_jit.h"
20
#endif
21

22
/* -- Frames -------------------------------------------------------------- */
23

24
/* Get frame corresponding to a level. */
25
cTValue *lj_debug_frame(lua_State *L, int level, int *size)
71,487✔
26
{
27
  cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2;
71,487✔
28
  /* Traverse frames backwards. */
29
  for (nextframe = frame = L->base-1; frame > bot; ) {
535,932✔
30
    if (frame_gc(frame) == obj2gco(L))
535,902✔
31
      level++;  /* Skip dummy frames. See lj_err_optype_call(). */
×
32
    if (level-- == 0) {
535,902✔
33
      *size = (int)(nextframe - frame);
71,457✔
34
      return frame;  /* Level found. */
71,457✔
35
    }
36
    nextframe = frame;
464,445✔
37
    if (frame_islua(frame)) {
464,445✔
38
      frame = frame_prevl(frame);
464,135✔
39
    } else {
40
      if (frame_isvarg(frame))
310✔
41
        level++;  /* Skip vararg pseudo-frame. */
54✔
42
      frame = frame_prevd(frame);
310✔
43
    }
44
  }
45
  *size = level;
30✔
46
  return NULL;  /* Level not found. */
30✔
47
}
48

49
/* Invalid bytecode position. */
50
#define NO_BCPOS        (~(BCPos)0)
51

52
/* Return bytecode position for function/frame or NO_BCPOS. */
53
static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
54
{
55
  const BCIns *ins;
56
  GCproto *pt;
57
  BCPos pos;
58
  lj_assertL(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD,
59
             "function or frame expected");
60
  if (!isluafunc(fn)) {  /* Cannot derive a PC for non-Lua functions. */
61
    return NO_BCPOS;
62
  } else if (nextframe == NULL) {  /* Lua function on top. */
63
    void *cf = cframe_raw(L->cframe);
64
    if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
65
      return NO_BCPOS;
66
    ins = cframe_pc(cf);  /* Only happens during error/hook handling. */
67
  } else {
68
    if (frame_islua(nextframe)) {
69
      ins = frame_pc(nextframe);
70
    } else if (frame_iscont(nextframe)) {
71
      ins = frame_contpc(nextframe);
72
    } else {
73
      /* Lua function below errfunc/gc/hook: find cframe to get the PC. */
74
      void *cf = cframe_raw(L->cframe);
75
      TValue *f = L->base-1;
76
      for (;;) {
77
        if (cf == NULL)
78
          return NO_BCPOS;
79
        while (cframe_nres(cf) < 0) {
80
          if (f >= restorestack(L, -cframe_nres(cf)))
81
            break;
82
          cf = cframe_raw(cframe_prev(cf));
83
          if (cf == NULL)
84
            return NO_BCPOS;
85
        }
86
        if (f < nextframe)
87
          break;
88
        if (frame_islua(f)) {
89
          f = frame_prevl(f);
90
        } else {
91
          if (frame_isc(f) || (frame_iscont(f) && frame_iscont_fficb(f)))
92
            cf = cframe_raw(cframe_prev(cf));
93
          f = frame_prevd(f);
94
        }
95
      }
96
      ins = cframe_pc(cf);
97
      if (!ins) return NO_BCPOS;
98
    }
99
  }
100
  pt = funcproto(fn);
101
  pos = proto_bcpos(pt, ins) - 1;
102
#if LJ_HASJIT
103
  if (pos > pt->sizebc) {  /* Undo the effects of lj_trace_exit for JLOOP. */
104
    GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins));
105
    lj_assertL(bc_isret(bc_op(ins[-1])), "return bytecode expected");
106
    pos = proto_bcpos(pt, mref(T->startpc, const BCIns));
107
  }
108
#endif
109
  return pos;
110
}
111

112
/* -- Line numbers -------------------------------------------------------- */
113

114
/* Get line number for a bytecode position. */
115
BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
32,321,730✔
116
{
117
  const void *lineinfo = proto_lineinfo(pt);
32,321,730✔
118
  if (pc <= pt->sizebc && lineinfo) {
32,321,730✔
119
    BCLine first = pt->firstline;
32,319,499✔
120
    if (pc == pt->sizebc) return first + pt->numline;
32,319,499✔
121
    if (pc-- == 0) return first;
32,319,499✔
122
    if (pt->numline < 256)
32,319,467✔
123
      return first + (BCLine)((const uint8_t *)lineinfo)[pc];
30,121,978✔
124
    else if (pt->numline < 65536)
2,197,489✔
125
      return first + (BCLine)((const uint16_t *)lineinfo)[pc];
1,287,278✔
126
    else
127
      return first + (BCLine)((const uint32_t *)lineinfo)[pc];
910,211✔
128
  }
129
  return 0;
130
}
131

132
/* Get line number for function/frame. */
133
BCLine lj_debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
2,132✔
134
{
135
  BCPos pc = debug_framepc(L, fn, nextframe);
2,132✔
136
  if (pc != NO_BCPOS) {
2,132✔
137
    GCproto *pt = funcproto(fn);
2,096✔
138
    lj_assertL(pc <= pt->sizebc, "PC out of range");
2,096✔
139
    return lj_debug_line(pt, pc);
2,096✔
140
  }
141
  return -1;
142
}
143

144
/* -- Variable names ------------------------------------------------------ */
145

146
/* Get name of a local variable from slot number and PC. */
147
static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
148
{
149
  const char *p = (const char *)proto_varinfo(pt);
150
  if (p) {
151
    BCPos lastpc = 0;
152
    for (;;) {
153
      const char *name = p;
154
      uint32_t vn = *(const uint8_t *)p;
155
      BCPos startpc, endpc;
156
      if (vn < VARNAME__MAX) {
157
        if (vn == VARNAME_END) break;  /* End of varinfo. */
158
      } else {
159
        do { p++; } while (*(const uint8_t *)p);  /* Skip over variable name. */
160
      }
161
      p++;
162
      lastpc = startpc = lastpc + lj_buf_ruleb128(&p);
163
      if (startpc > pc) break;
164
      endpc = startpc + lj_buf_ruleb128(&p);
165
      if (pc < endpc && slot-- == 0) {
166
        if (vn < VARNAME__MAX) {
167
#define VARNAMESTR(name, str)        str "\0"
168
          name = VARNAMEDEF(VARNAMESTR);
169
#undef VARNAMESTR
170
          if (--vn) while (*name++ || --vn) ;
171
        }
172
        return name;
173
      }
174
    }
175
  }
176
  return NULL;
177
}
178

179
/* Get name of local variable from 1-based slot number and function/frame. */
180
static TValue *debug_localname(lua_State *L, const lua_Debug *ar,
181
                               const char **name, BCReg slot1)
182
{
183
  uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
184
  uint32_t size = (uint32_t)ar->i_ci >> 16;
185
  TValue *frame = tvref(L->stack) + offset;
186
  TValue *nextframe = size ? frame + size : NULL;
187
  GCfunc *fn = frame_func(frame);
188
  BCPos pc = debug_framepc(L, fn, nextframe);
189
  if (!nextframe) nextframe = L->top+LJ_FR2;
190
  if ((int)slot1 < 0) {  /* Negative slot number is for varargs. */
191
    if (pc != NO_BCPOS) {
192
      GCproto *pt = funcproto(fn);
193
      if ((pt->flags & PROTO_VARARG)) {
194
        slot1 = pt->numparams + (BCReg)(-(int)slot1);
195
        if (frame_isvarg(frame)) {  /* Vararg frame has been set up? (pc!=0) */
196
          nextframe = frame;
197
          frame = frame_prevd(frame);
198
        }
199
        if (frame + slot1+LJ_FR2 < nextframe) {
200
          *name = "(*vararg)";
201
          return frame+slot1;
202
        }
203
      }
204
    }
205
    return NULL;
206
  }
207
  if (pc != NO_BCPOS &&
208
      (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL)
209
    ;
210
  else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe)
211
    *name = "(*temporary)";
212
  return frame+slot1;
213
}
214

215
/* Get name of upvalue. */
216
const char *lj_debug_uvname(GCproto *pt, uint32_t idx)
124✔
217
{
218
  const uint8_t *p = proto_uvinfo(pt);
124✔
219
  lj_assertX(idx < pt->sizeuv, "bad upvalue index");
124✔
220
  if (!p) return "";
44✔
221
  if (idx) while (*p++ || --idx) ;
563✔
222
  return (const char *)p;
223
}
224

225
/* Get name and value of upvalue. */
226
const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp, GCobj **op)
21✔
227
{
228
  if (tvisfunc(o)) {
21✔
229
    GCfunc *fn = funcV(o);
21✔
230
    if (isluafunc(fn)) {
21✔
231
      GCproto *pt = funcproto(fn);
19✔
232
      if (idx < pt->sizeuv) {
19✔
233
        GCobj *uvo = gcref(fn->l.uvptr[idx]);
12✔
234
        *tvp = uvval(&uvo->uv);
12✔
235
        *op = uvo;
12✔
236
        return lj_debug_uvname(pt, idx);
24✔
237
      }
238
    } else {
239
      if (idx < fn->c.nupvalues) {
2✔
240
        *tvp = &fn->c.upvalue[idx];
×
241
        *op = obj2gco(fn);
×
242
        return "";
×
243
      }
244
    }
245
  }
246
  return NULL;
247
}
248

249
/* Deduce name of an object from slot number and PC. */
250
const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot,
72,665✔
251
                              const char **name)
252
{
253
  const char *lname;
72,698✔
254
restart:
72,698✔
255
  lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
72,698✔
256
  if (lname != NULL) { *name = lname; return "local"; }
72,698✔
257
  while (--ip > proto_bc(pt)) {
73,133✔
258
    BCIns ins = *ip;
73,131✔
259
    BCOp op = bc_op(ins);
73,131✔
260
    BCReg ra = bc_a(ins);
73,131✔
261
    if (bcmode_a(op) == BCMbase) {
73,131✔
262
      if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
5✔
263
        return NULL;
264
    } else if (bcmode_a(op) == BCMdst && ra == slot) {
73,126✔
265
      switch (bc_op(ins)) {
72,640✔
266
      case BC_MOV:
267
        if (ra == slot) { slot = bc_d(ins); goto restart; }
33✔
268
        break;
269
      case BC_GGET:
71,440✔
270
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
71,440✔
271
        return "global";
71,440✔
272
      case BC_TGETS:
39✔
273
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
39✔
274
        if (ip > proto_bc(pt)) {
39✔
275
          BCIns insp = ip[-1];
39✔
276
          if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 &&
39✔
277
              bc_d(insp) == bc_b(ins))
5✔
278
            return "method";
279
        }
280
        return "field";
34✔
281
      case BC_UGET:
68✔
282
        *name = lj_debug_uvname(pt, bc_d(ins));
68✔
283
        return "upvalue";
68✔
284
      default:
285
        return NULL;
286
      }
287
    }
486✔
288
  }
289
  return NULL;
290
}
291

292
/* Deduce function name from caller of a frame. */
293
const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name)
71,304✔
294
{
295
  cTValue *pframe;
71,304✔
296
  GCfunc *fn;
71,304✔
297
  BCPos pc;
71,304✔
298
  if (frame <= tvref(L->stack)+LJ_FR2)
71,304✔
299
    return NULL;
300
  if (frame_isvarg(frame))
71,304✔
301
    frame = frame_prevd(frame);
24✔
302
  pframe = frame_prev(frame);
71,304✔
303
  fn = frame_func(pframe);
71,304✔
304
  pc = debug_framepc(L, fn, frame);
71,304✔
305
  if (pc != NO_BCPOS) {
71,304✔
306
    GCproto *pt = funcproto(fn);
71,216✔
307
    const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
71,216✔
308
    MMS mm = bcmode_mm(bc_op(*ip));
71,216✔
309
    if (mm == MM_call) {
71,216✔
310
      BCReg slot = bc_a(*ip);
71,180✔
311
      if (bc_op(*ip) == BC_ITERC) slot -= 3;
71,180✔
312
      return lj_debug_slotname(pt, ip, slot, name);
71,180✔
313
    } else if (mm != MM__MAX) {
36✔
314
      *name = strdata(mmname_str(G(L), mm));
36✔
315
      return "metamethod";
36✔
316
    }
317
  }
318
  return NULL;
319
}
320

321
/* -- Source code locations ----------------------------------------------- */
322

323
/* Generate shortened source name. */
324
void lj_debug_shortname(char *out, GCstr *str, BCLine line)
14,554✔
325
{
326
  const char *src = strdata(str);
14,554✔
327
  if (*src == '=') {
14,554✔
328
    strncpy(out, src+1, LUA_IDSIZE);  /* Remove first char. */
424✔
329
    out[LUA_IDSIZE-1] = '\0';  /* Ensures null termination. */
424✔
330
  } else if (*src == '@') {  /* Output "source", or "...source". */
14,130✔
331
    size_t len = str->len-1;
463✔
332
    src++;  /* Skip the `@' */
463✔
333
    if (len >= LUA_IDSIZE) {
463✔
334
      src += len-(LUA_IDSIZE-4);  /* Get last part of file name. */
459✔
335
      *out++ = '.'; *out++ = '.'; *out++ = '.';
459✔
336
    }
337
    strcpy(out, src);
463✔
338
  } else {  /* Output [string "string"] or [builtin:name]. */
339
    size_t len;  /* Length, up to first control char. */
340
    for (len = 0; len < LUA_IDSIZE-12; len++)
176,519✔
341
      if (((const unsigned char *)src)[len] < ' ') break;
176,503✔
342
    strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
13,667✔
343
    if (src[len] != '\0') {  /* Must truncate? */
13,667✔
344
      if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
9,481✔
345
      strncpy(out, src, len); out += len;
9,481✔
346
      strcpy(out, "..."); out += 3;
9,481✔
347
    } else {
348
      strcpy(out, src); out += len;
4,186✔
349
    }
350
    strcpy(out, line == ~(BCLine)0 ? "]" : "\"]");
27,334✔
351
  }
352
}
14,554✔
353

354
/* Add current location of a frame to error message. */
355
void lj_debug_addloc(lua_State *L, const char *msg,
13,347✔
356
                     cTValue *frame, cTValue *nextframe)
357
{
358
  if (frame) {
13,347✔
359
    GCfunc *fn = frame_func(frame);
13,219✔
360
    if (isluafunc(fn)) {
13,219✔
361
      BCLine line = lj_debug_frameline(L, fn, nextframe);
1,705✔
362
      if (line >= 0) {
1,705✔
363
        GCproto *pt = funcproto(fn);
1,704✔
364
        char buf[LUA_IDSIZE];
1,704✔
365
        lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline);
1,704✔
366
        lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg);
1,704✔
367
        return;
1,704✔
368
      }
369
    }
370
  }
371
  lj_strfmt_pushf(L, "%s", msg);
11,643✔
372
}
373

374
/* Push location string for a bytecode position to Lua stack. */
375
void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
19✔
376
{
377
  GCstr *name = proto_chunkname(pt);
19✔
378
  const char *s = strdata(name);
19✔
379
  MSize i, len = name->len;
19✔
380
  BCLine line = lj_debug_line(pt, pc);
19✔
381
  if (pt->firstline == ~(BCLine)0) {
19✔
382
    lj_strfmt_pushf(L, "builtin:%s", s);
1✔
383
  } else if (*s == '@') {
18✔
384
    s++; len--;
18✔
385
    for (i = len; i > 0; i--)
368✔
386
      if (s[i] == '/' || s[i] == '\\') {
366✔
387
        s += i+1;
16✔
388
        break;
16✔
389
      }
390
    lj_strfmt_pushf(L, "%s:%d", s, line);
18✔
391
  } else if (len > 40) {
×
392
    lj_strfmt_pushf(L, "%p:%d", pt, line);
×
393
  } else if (*s == '=') {
×
394
    lj_strfmt_pushf(L, "%s:%d", s+1, line);
×
395
  } else {
396
    lj_strfmt_pushf(L, "\"%s\":%d", s, line);
×
397
  }
398
}
19✔
399

400
/* -- Public debug API ---------------------------------------------------- */
401

402
/* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
403

404
LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n)
19✔
405
{
406
  const char *name = NULL;
19✔
407
  if (ar) {
19✔
408
    TValue *o = debug_localname(L, ar, &name, (BCReg)n);
19✔
409
    if (name) {
19✔
410
      copyTV(L, L->top, o);
15✔
411
      incr_top(L);
15✔
412
    }
413
  } else if (tvisfunc(L->top-1) && isluafunc(funcV(L->top-1))) {
×
414
    name = debug_varname(funcproto(funcV(L->top-1)), 0, (BCReg)n-1);
×
415
  }
416
  return name;
19✔
417
}
418

419
LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n)
6✔
420
{
421
  const char *name = NULL;
6✔
422
  TValue *o = debug_localname(L, ar, &name, (BCReg)n);
6✔
423
  if (name)
6✔
424
    copyTV(L, o, L->top-1);
5✔
425
  L->top--;
6✔
426
  return name;
6✔
427
}
428

429
int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
71,292✔
430
{
431
  int opt_f = 0, opt_L = 0;
71,292✔
432
  TValue *frame = NULL;
71,292✔
433
  TValue *nextframe = NULL;
71,292✔
434
  GCfunc *fn;
71,292✔
435
  if (*what == '>') {
71,292✔
436
    TValue *func = L->top - 1;
22✔
437
    if (!tvisfunc(func)) return 0;
22✔
438
    fn = funcV(func);
21✔
439
    L->top--;
21✔
440
    what++;
21✔
441
  } else {
442
    uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
71,270✔
443
    uint32_t size = (uint32_t)ar->i_ci >> 16;
71,270✔
444
    lj_assertL(offset != 0, "bad frame offset");
71,270✔
445
    frame = tvref(L->stack) + offset;
71,270✔
446
    if (size) nextframe = frame + size;
71,270✔
447
    lj_assertL(frame <= tvref(L->maxstack) &&
71,270✔
448
               (!nextframe || nextframe <= tvref(L->maxstack)),
449
               "broken frame chain");
450
    fn = frame_func(frame);
71,270✔
451
    lj_assertL(fn->c.gct == ~LJ_TFUNC, "bad frame function");
452
  }
453
  for (; *what; what++) {
143,182✔
454
    if (*what == 'S') {
71,892✔
455
      if (isluafunc(fn)) {
179✔
456
        GCproto *pt = funcproto(fn);
148✔
457
        BCLine firstline = pt->firstline;
148✔
458
        GCstr *name = proto_chunkname(pt);
148✔
459
        ar->source = strdata(name);
148✔
460
        lj_debug_shortname(ar->short_src, name, pt->firstline);
148✔
461
        ar->linedefined = (int)firstline;
148✔
462
        ar->lastlinedefined = (int)(firstline + pt->numline);
148✔
463
        ar->what = (firstline || !pt->numline) ? "Lua" : "main";
176✔
464
      } else {
465
        ar->source = "=[C]";
31✔
466
        ar->short_src[0] = '[';
31✔
467
        ar->short_src[1] = 'C';
31✔
468
        ar->short_src[2] = ']';
31✔
469
        ar->short_src[3] = '\0';
31✔
470
        ar->linedefined = -1;
31✔
471
        ar->lastlinedefined = -1;
31✔
472
        ar->what = "C";
31✔
473
      }
474
    } else if (*what == 'l') {
71,713✔
475
      ar->currentline = frame ? lj_debug_frameline(L, fn, nextframe) : -1;
184✔
476
    } else if (*what == 'u') {
71,529✔
477
      ar->nups = fn->c.nupvalues;
80✔
478
      if (ext) {
80✔
479
        if (isluafunc(fn)) {
80✔
480
          GCproto *pt = funcproto(fn);
79✔
481
          ar->nparams = pt->numparams;
79✔
482
          ar->isvararg = !!(pt->flags & PROTO_VARARG);
79✔
483
        } else {
484
          ar->nparams = 0;
1✔
485
          ar->isvararg = 1;
1✔
486
        }
487
      }
488
    } else if (*what == 'n') {
71,449✔
489
      ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
71,214✔
490
      if (ar->namewhat == NULL) {
71,214✔
491
        ar->namewhat = "";
60✔
492
        ar->name = NULL;
60✔
493
      }
494
    } else if (*what == 'f') {
235✔
495
      opt_f = 1;
496
    } else if (*what == 'L') {
4✔
497
      opt_L = 1;
498
    } else {
499
      return 0;  /* Bad option. */
500
    }
501
  }
502
  if (opt_f) {
71,290✔
503
    setfuncV(L, L->top, fn);
231✔
504
    incr_top(L);
231✔
505
  }
506
  if (opt_L) {
71,290✔
507
    if (isluafunc(fn)) {
3✔
508
      GCtab *t = lj_tab_new(L, 0, 0);
3✔
509
      GCproto *pt = funcproto(fn);
3✔
510
      const void *lineinfo = proto_lineinfo(pt);
3✔
511
      if (lineinfo) {
3✔
512
        BCLine first = pt->firstline;
3✔
513
        int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4;
3✔
514
        MSize i, szl = pt->sizebc-1;
3✔
515
        for (i = 0; i < szl; i++) {
87✔
516
          BCLine line = first +
168✔
517
            (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] :
84✔
518
             sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] :
×
519
             (BCLine)((const uint32_t *)lineinfo)[i]);
×
520
          setboolV(lj_tab_setint(L, t, line), 1);
84✔
521
        }
522
      }
523
      settabV(L, L->top, t);
3✔
524
    } else {
525
      setnilV(L->top);
×
526
    }
527
    incr_top(L);
3✔
528
  }
529
  return 1;  /* Ok. */
530
}
531

532
LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
104✔
533
{
534
  return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0);
12✔
535
}
536

537
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
71,324✔
538
{
539
  int size;
71,324✔
540
  cTValue *frame = lj_debug_frame(L, level, &size);
71,324✔
541
  if (frame) {
71,324✔
542
    ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
71,298✔
543
    return 1;
71,298✔
544
  } else {
545
    ar->i_ci = level - size;
26✔
546
    return 0;
26✔
547
  }
548
}
549

550
#if LJ_HASPROFILE
551
/* Put the chunkname into a buffer. */
552
static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip)
553
{
554
  GCstr *name = proto_chunkname(pt);
555
  const char *p = strdata(name);
556
  if (pt->firstline == ~(BCLine)0) {
557
    lj_buf_putmem(sb, "[builtin:", 9);
558
    lj_buf_putstr(sb, name);
559
    lj_buf_putb(sb, ']');
560
    return 0;
561
  }
562
  if (*p == '=' || *p == '@') {
563
    MSize len = name->len-1;
564
    p++;
565
    if (pathstrip) {
566
      int i;
567
      for (i = len-1; i >= 0; i--)
568
        if (p[i] == '/' || p[i] == '\\') {
569
          len -= i+1;
570
          p = p+i+1;
571
          break;
572
        }
573
    }
574
    lj_buf_putmem(sb, p, len);
575
  } else {
576
    lj_buf_putmem(sb, "[string]", 8);
577
  }
578
  return 1;
579
}
580

581
/* Put a compact stack dump into a buffer. */
582
void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth)
1✔
583
{
584
  int level = 0, dir = 1, pathstrip = 1;
1✔
585
  MSize lastlen = 0;
1✔
586
  if (depth < 0) { level = ~depth; depth = dir = -1; }  /* Reverse frames. */
1✔
587
  while (level != depth) {  /* Loop through all frame. */
2✔
588
    int size;
1✔
589
    cTValue *frame = lj_debug_frame(L, level, &size);
1✔
590
    if (frame) {
1✔
591
      cTValue *nextframe = size ? frame+size : NULL;
1✔
592
      GCfunc *fn = frame_func(frame);
1✔
593
      const uint8_t *p = (const uint8_t *)fmt;
1✔
594
      int c;
1✔
595
      while ((c = *p++)) {
1✔
596
        switch (c) {
5✔
597
        case 'p':  /* Preserve full path. */
598
          pathstrip = 0;
599
          break;
600
        case 'F': case 'f': {  /* Dump function name. */
1✔
601
          const char *name;
1✔
602
          const char *what = lj_debug_funcname(L, frame, &name);
1✔
603
          if (what) {
1✔
604
            if (c == 'F' && isluafunc(fn)) {  /* Dump module:name for 'F'. */
1✔
605
              GCproto *pt = funcproto(fn);
×
606
              if (pt->firstline != ~(BCLine)0) {  /* Not a bytecode builtin. */
×
607
                debug_putchunkname(sb, pt, pathstrip);
×
608
                lj_buf_putb(sb, ':');
×
609
              }
610
            }
611
            lj_buf_putmem(sb, name, (MSize)strlen(name));
1✔
612
            break;
1✔
613
          }  /* else: can't derive a name, dump module:line. */
614
          }
615
          /* fallthrough */
616
        case 'l':  /* Dump module:line. */
617
          if (isluafunc(fn)) {
×
618
            GCproto *pt = funcproto(fn);
×
619
            if (debug_putchunkname(sb, pt, pathstrip)) {
×
620
              /* Regular Lua function. */
621
              BCLine line = c == 'l' ? lj_debug_frameline(L, fn, nextframe) :
×
622
                                       pt->firstline;
623
              lj_buf_putb(sb, ':');
×
624
              lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline);
×
625
            }
626
          } else if (isffunc(fn)) {  /* Dump numbered builtins. */
×
627
            lj_buf_putmem(sb, "[builtin#", 9);
×
628
            lj_strfmt_putint(sb, fn->c.ffid);
×
629
            lj_buf_putb(sb, ']');
×
630
          } else {  /* Dump C function address. */
631
            lj_buf_putb(sb, '@');
×
632
            lj_strfmt_putptr(sb, fn->c.f);
×
633
          }
634
          break;
635
        case 'Z':  /* Zap trailing separator. */
1✔
636
          lastlen = sbuflen(sb);
1✔
637
          break;
1✔
638
        default:
639
          lj_buf_putb(sb, c);
9✔
640
          break;
641
        }
642
      }
643
    } else if (dir == 1) {
×
644
      break;
645
    } else {
646
      level -= size;  /* Reverse frame order: quickly skip missing level. */
×
647
    }
648
    level += dir;
1✔
649
  }
650
  if (lastlen)
1✔
651
    setsbufP(sb, sbufB(sb) + lastlen);  /* Zap trailing separator. */
1✔
652
}
1✔
653
#endif
654

655
/* Number of frames for the leading and trailing part of a traceback. */
656
#define TRACEBACK_LEVELS1        12
657
#define TRACEBACK_LEVELS2        10
658

659
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
21✔
660
                                int level)
661
{
662
  int top = (int)(L->top - L->base);
21✔
663
  int lim = TRACEBACK_LEVELS1;
21✔
664
  lua_Debug ar;
21✔
665
  if (msg) lua_pushfstring(L, "%s\n", msg);
21✔
666
  lua_pushliteral(L, "stack traceback:");
21✔
667
  while (lua_getstack(L1, level++, &ar)) {
114✔
668
    GCfunc *fn;
93✔
669
    if (level > lim) {
93✔
670
      if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) {
1✔
671
        level--;
672
      } else {
673
        lua_pushliteral(L, "\n\t...");
1✔
674
        lua_getstack(L1, -10, &ar);
1✔
675
        level = ar.i_ci - TRACEBACK_LEVELS2;
1✔
676
      }
677
      lim = 2147483647;
1✔
678
      continue;
1✔
679
    }
680
    lua_getinfo(L1, "Snlf", &ar);
92✔
681
    fn = funcV(L1->top-1); L1->top--;
92✔
682
    if (isffunc(fn) && !*ar.namewhat)
92✔
683
      lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid);
×
684
    else
685
      lua_pushfstring(L, "\n\t%s:", ar.short_src);
92✔
686
    if (ar.currentline > 0)
92✔
687
      lua_pushfstring(L, "%d:", ar.currentline);
61✔
688
    if (*ar.namewhat) {
92✔
689
      lua_pushfstring(L, " in function " LUA_QS, ar.name);
53✔
690
    } else {
691
      if (*ar.what == 'm') {
39✔
692
        lua_pushliteral(L, " in main chunk");
12✔
693
      } else if (*ar.what == 'C') {
27✔
694
        lua_pushfstring(L, " at %p", fn->c.f);
12✔
695
      } else {
696
        lua_pushfstring(L, " in function <%s:%d>",
15✔
697
                        ar.short_src, ar.linedefined);
698
      }
699
    }
700
    if ((int)(L->top - L->base) - top >= 15)
92✔
701
      lua_concat(L, (int)(L->top - L->base) - top);
10✔
702
  }
703
  lua_concat(L, (int)(L->top - L->base) - top);
21✔
704
}
21✔
705

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

© 2026 Coveralls, Inc