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

tarantool / luajit / 16004999645

01 Jul 2025 03:07PM UTC coverage: 93.081% (+0.02%) from 93.06%
16004999645

push

github

Buristan
Fix error generation in load*.

Reported by Sergey Kaplun.

(cherry picked from commit e76bb50d4)

The chunkname pointer to the "@filename" is put on the Lua stack
before the `lua_loadx()` and is removed right before the next
`lua_pushfstring()` in case of the error. If the GC takes the step
right at this moment inside `lua_pushfstring()` the string may be
collected, and the next read from this `chunkname + 1` is from the
deallocated memory.

This patch fixes this by using the source string (or the constant one)
instead.

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

Part of tarantool/tarantool#11278

Reviewed-by: Sergey Bronnikov <sergeyb@tarantool.org>
Signed-off-by: Sergey Kaplun <skaplun@tarantool.org>
(cherry picked from commit 046e9b3a0)

5711 of 6047 branches covered (94.44%)

Branch coverage included in aggregate %.

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

14 existing lines in 4 files now uncovered.

21800 of 23509 relevant lines covered (92.73%)

3874382.81 hits per line

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

85.59
/src/lj_sysprof.c
1
/*
2
** Implementation of sysprof - platform and Lua profiler.
3
*/
4

5
#define lj_sysprof_c
6
#define LUA_CORE
7

8
#include "lj_arch.h"
9
#include "lj_sysprof.h"
10

11
#if LJ_HASSYSPROF
12

13
#include "lj_obj.h"
14
#include "lj_debug.h"
15
#include "lj_dispatch.h"
16
#include "lj_frame.h"
17

18
#if LJ_HASJIT
19
#include "lj_jit.h"
20
#include "lj_trace.h"
21
#endif
22

23
#include "lj_wbuf.h"
24
#include "lj_profile_timer.h"
25
#include "lj_symtab.h"
26

27
#include <pthread.h>
28
#include <errno.h>
29
#include <execinfo.h>
30

31
/*
32
** Number of profiler frames we need to omit during stack
33
** unwinding.
34
**   +------------------------+
35
** 0 | default_backtrace_host |
36
**   +------------------------+
37
** 1 | stream_backtrace_host  |
38
**   +------------------------+
39
** 2 |  stream_{guest/host}   |
40
**   +------------------------+
41
** 3 |      stream_event      |
42
**   +------------------------+
43
** 4 | sysprof_record_sample  |
44
**   +------------------------+
45
** 5 | sysprof_signal_handler |
46
**   +------------------------+
47
*/
48
#define SYSPROF_HANDLER_STACK_DEPTH 6
49
#define SYSPROF_BACKTRACE_FRAME_MAX 512
50

51
/* Check that vmstate fits in 4 bits (see streaming format) */
52
#define vmstfit4(st) ((st & ~(uint32_t)((1 << 4) - 1)) == 0)
53

54
enum sysprof_state {
55
  /* Profiler is not running. */
56
  SPS_IDLE,
57
  /* Profiler is running. */
58
  SPS_PROFILE,
59
  /*
60
  ** Stopped in case of stopped or failed stream.
61
  ** Saved errno is set at luaM_sysprof_stop.
62
  */
63
  SPS_HALT
64
};
65

66
struct sysprof {
67
  global_State *g; /* Profiled VM. */
68
  pthread_t thread; /* Profiled thread. */
69
  volatile sig_atomic_t state; /* Internal state. */
70
  struct lj_wbuf out; /* Output accumulator. */
71
  struct luam_Sysprof_Counters counters; /* Profiling counters. */
72
  struct luam_Sysprof_Options opt; /* Profiling options. */
73
  luam_Sysprof_writer writer; /* Writer function for profile events. */
74
  luam_Sysprof_on_stop on_stop; /* Callback on profiling stopping. */
75
  luam_Sysprof_backtracer backtracer; /* Backtracing function for the host stack. */
76
  lj_profile_timer timer; /* Profiling timer. */
77
  int saved_errno; /* Saved errno when profiler failed. */
78
};
79
/*
80
** XXX: Only one VM can be profiled at a time.
81
*/
82

83
static struct sysprof sysprof = {0};
84

85
/* --- Stream ------------------------------------------------------------- */
86

87
static const uint8_t ljp_header[] = {'l', 'j', 'p', LJP_FORMAT_VERSION,
88
                                      0x0, 0x0, 0x0};
89

90
static int stream_is_needed(struct sysprof *sp)
28✔
91
{
92
  return sp->opt.mode != LUAM_SYSPROF_DEFAULT;
28✔
93
}
94

95
static int is_unconfigured(struct sysprof *sp)
1,181✔
96
{
97
  return sp->backtracer == NULL || sp->on_stop == NULL || sp->writer == NULL;
399✔
98
}
99

100
static void stream_prologue(struct sysprof *sp)
6✔
101
{
102
  /*
103
  ** XXX: Must be zero for the symtab module to dump all loaded libraries.
104
  */
105
  uint32_t unused_lib_adds = 0;
6✔
106
  lj_symtab_dump(&sp->out, sp->g, &unused_lib_adds);
6✔
107
  lj_wbuf_addn(&sp->out, ljp_header, sizeof(ljp_header));
6✔
108
}
6✔
109

110
static void stream_epilogue(struct sysprof *sp)
6✔
111
{
112
  lj_wbuf_addbyte(&sp->out, LJP_EPILOGUE_BYTE);
6✔
113
}
114

115
static void stream_ffunc_impl(struct lj_wbuf *buf, uint8_t ffid)
1✔
116
{
117
  lj_wbuf_addbyte(buf, LJP_FRAME_FFUNC);
1✔
118
  lj_wbuf_addu64(buf, ffid);
1✔
119
}
1✔
120

121
static void stream_lfunc(struct lj_wbuf *buf, const GCfunc *func)
122
{
123
  lj_assertX(isluafunc(func), "bad lua function in sysprof stream");
124
  const GCproto *pt = funcproto(func);
125
  lj_assertX(pt != NULL, "bad lua function prototype in sysprof stream");
126
  lj_wbuf_addbyte(buf, LJP_FRAME_LFUNC);
127
  lj_wbuf_addu64(buf, (uintptr_t)pt);
128
  lj_wbuf_addu64(buf, (uint64_t)pt->firstline);
129
}
130

131
static void stream_cfunc(struct lj_wbuf *buf, const GCfunc *func)
10✔
132
{
133
  lj_assertX(iscfunc(func), "bad C function in sysprof stream");
10✔
134
  lj_wbuf_addbyte(buf, LJP_FRAME_CFUNC);
10✔
135
  lj_wbuf_addu64(buf, (uintptr_t)func->c.f);
10✔
136
}
10✔
137

UNCOV
138
static void stream_ffunc(struct lj_wbuf *buf, const GCfunc *func)
×
139
{
UNCOV
140
  lj_assertX(isffunc(func), "bad fast function in sysprof stream");
×
UNCOV
141
  stream_ffunc_impl(buf, func->c.ffid);
×
UNCOV
142
}
×
143

144
static void stream_frame_lua(struct lj_wbuf *buf, const cTValue *frame)
260✔
145
{
146
  const GCfunc *func = frame_func(frame);
260✔
147
  lj_assertX(func != NULL, "bad function in sysprof stream");
260✔
148
  if (isluafunc(func))
260✔
149
    stream_lfunc(buf, func);
250✔
150
  else if (isffunc(func))
10✔
UNCOV
151
    stream_ffunc(buf, func);
×
152
  else if (iscfunc(func))
10✔
153
    stream_cfunc(buf, func);
10✔
154
  else
155
    /* Unreachable. */
156
    lj_assertX(0, "bad function type in sysprof stream");
260✔
157
}
260✔
158

159
static void stream_backtrace_lua(struct sysprof *sp, uint32_t vmstate)
11✔
160
{
161
  global_State *g = sp->g;
11✔
162
  struct lj_wbuf *buf = &sp->out;
11✔
163
  cTValue *top_frame = NULL, *frame = NULL, *bot = NULL;
11✔
164
  lua_State *L = NULL;
11✔
165

166
  lj_assertX(g != NULL, "uninitialized global state in sysprof state");
11✔
167
  L = gco2th(gcref(g->cur_L));
11✔
168
  lj_assertG(L != NULL, "uninitialized Lua state in sysprof state");
11✔
169
  /*
170
  ** Lua stack may be inconsistent during the execution of a
171
  ** fast-function, so instead of updating the `top_frame` for
172
  ** it, its `ffid` is set instead. The first frame on the
173
  ** result stack is streamed manually, and the rest of the
174
  ** stack is streamed based on the previous `top_frame` value.
175
  */
176
  if (vmstate == LJ_VMST_FFUNC) {
11✔
177
    uint8_t ffid = g->top_frame_info.ffid;
1✔
178
    stream_ffunc_impl(buf, ffid);
1✔
179
  }
180

181
  top_frame = g->top_frame_info.top_frame - 1;
11✔
182

183
  bot = tvref(L->stack) + LJ_FR2;
11✔
184
  /* Traverse frames backwards */
185
  for (frame = top_frame; frame > bot; frame = frame_prev(frame)) {
551✔
186
    if (frame_gc(frame) == obj2gco(L) || frame_isvarg(frame))
270✔
187
      continue;  /* Skip dummy frames. See lj_err_optype_call(). */
10✔
188
    stream_frame_lua(buf, frame);
260✔
189
  }
190

191
  lj_wbuf_addbyte(buf, LJP_FRAME_LUA_LAST);
11✔
192
}
11✔
193

194
static void *stream_frame_host(int frame_no, void *addr)
131✔
195
{
196
  struct sysprof *sp = &sysprof;
131✔
197
  /*
198
  ** We don't want the profiler stack to be streamed, as it will
199
  ** burden the profile with unnecessary information.
200
  */
201
  if (LJ_UNLIKELY(frame_no <= SYSPROF_HANDLER_STACK_DEPTH))
131✔
202
    return addr;
203
  else if (LJ_UNLIKELY(sp->opt.mode == LUAM_SYSPROF_LEAF &&
17✔
204
                         frame_no > SYSPROF_HANDLER_STACK_DEPTH))
205
    return NULL;
206

207
  lj_wbuf_addu64(&sp->out, (uintptr_t)addr);
17✔
208
  return addr;
17✔
209
}
210

211
static void default_backtrace_host(void *(writer)(int frame_no, void *addr))
20✔
212
{
213
  static void *backtrace_buf[SYSPROF_BACKTRACE_FRAME_MAX] = {};
20✔
214

215
  struct sysprof *sp = &sysprof;
20✔
216
  int max_depth = sp->opt.mode == LUAM_SYSPROF_LEAF
40✔
217
                  ? SYSPROF_HANDLER_STACK_DEPTH + 1
218
                  : SYSPROF_BACKTRACE_FRAME_MAX;
20✔
219
  const int depth = backtrace(backtrace_buf, max_depth);
20✔
220
  int level;
20✔
221

222
  lj_assertX(depth <= max_depth, "depth of C stack is too big");
20✔
223
  for (level = SYSPROF_HANDLER_STACK_DEPTH; level < depth; ++level) {
171✔
224
    if (!writer(level - SYSPROF_HANDLER_STACK_DEPTH + 1, backtrace_buf[level]))
131✔
225
      return;
226
  }
227
}
228

229
static void stream_backtrace_host(struct sysprof *sp)
20✔
230
{
231
  lj_assertX(sp->backtracer != NULL, "uninitialized sysprof backtracer");
20✔
232
  sp->backtracer(stream_frame_host);
20✔
233
  lj_wbuf_addu64(&sp->out, (uintptr_t)LJP_FRAME_HOST_LAST);
20✔
234
}
235

236
#if LJ_HASJIT
237
static void stream_trace(struct sysprof *sp, uint32_t vmstate)
×
238
{
239
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
×
240
  struct lj_wbuf *out = &sp->out;
×
241
  uint32_t traceno = sp->g->vmstate;
×
242
  jit_State *J = G2J(sp->g);
×
243
  GCtrace *trace = traceref(J, traceno);
×
244

245
  GCproto *startpt = gco2pt(gcref(trace->startpt));
×
246

247
  lj_wbuf_addu64(out, traceno);
×
248
  lj_wbuf_addu64(out, (uintptr_t)startpt);
×
249
  lj_wbuf_addu64(out, startpt->firstline);
×
250
}
×
251
#endif
252

253
static void stream_guest(struct sysprof *sp, uint32_t vmstate)
11✔
254
{
255
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
11✔
256
  stream_backtrace_lua(sp, vmstate);
11✔
257
  stream_backtrace_host(sp);
11✔
258
}
11✔
259

260
static void stream_host(struct sysprof *sp, uint32_t vmstate)
9✔
261
{
262
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
9✔
263
  stream_backtrace_host(sp);
9✔
264
}
9✔
265

266
typedef void (*event_streamer)(struct sysprof *sp, uint32_t vmstate);
267

268
static event_streamer event_streamers[] = {
269
  /* XXX: order is important */
270
  stream_host,  /* LJ_VMST_INTERP */
271
  stream_guest, /* LJ_VMST_LFUNC */
272
  stream_guest, /* LJ_VMST_FFUNC */
273
  stream_guest, /* LJ_VMST_CFUNC */
274
  stream_host,  /* LJ_VMST_GC */
275
  stream_host,  /* LJ_VMST_EXIT */
276
  stream_host,  /* LJ_VMST_RECORD */
277
  stream_host,  /* LJ_VMST_OPT */
278
  stream_host,  /* LJ_VMST_ASM */
279
#if LJ_HASJIT
280
  stream_trace  /* LJ_VMST_TRACE */
281
#endif
282
};
283

284
static void stream_event(struct sysprof *sp, uint32_t vmstate)
285
{
286
  event_streamer stream = NULL;
287

288
  lj_assertX(vmstfit4(vmstate), "vmstate don't fit in 4 bits");
289
  stream = event_streamers[vmstate];
290
  lj_assertX(stream != NULL, "uninitialized sysprof stream");
291
  stream(sp, vmstate);
292
}
293

294
/* -- Signal handler ------------------------------------------------------ */
295

296
static void sysprof_record_sample(struct sysprof *sp, siginfo_t *info)
297
{
298
  global_State *g = sp->g;
299
  uint32_t _vmstate = ~(uint32_t)(g->vmstate);
300
  uint32_t vmstate;
301

302
  /* `g->vmstate` is 0 outside the VM. Hence, dump only the host stack. */
303
  if (g->vmstate == 0)
304
    vmstate = LJ_VMST_INTERP;
305
  else if (_vmstate < LJ_VMST_TRACE)
306
    vmstate = _vmstate;
307
  else
308
    vmstate = LJ_VMST_TRACE;
309

310
  lj_assertX(pthread_self() == sp->thread,
311
             "bad thread during sysprof record sample");
312

313
  /* Caveat: order of counters must match vmstate order in <lj_obj.h>. */
314
  ((uint64_t *)&sp->counters)[vmstate]++;
315

316
  sp->counters.samples++;
317

318
  if (!stream_is_needed(sp))
319
    return;
320

321
  stream_event(sp, vmstate);
322
  if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
323
    sp->saved_errno = lj_wbuf_errno(&sp->out);
324
    lj_wbuf_terminate(&sp->out);
325
    sp->state = SPS_HALT;
326
  }
327
}
328

329
static void sysprof_signal_handler(int sig, siginfo_t *info, void *ctx)
57✔
330
{
331
  struct sysprof *sp = &sysprof;
57✔
332
  UNUSED(sig);
57✔
333
  UNUSED(ctx);
57✔
334

335
  switch (sp->state) {
57✔
336
    case SPS_PROFILE:
57✔
337
      sysprof_record_sample(sp, info);
57✔
338
      break;
57✔
339

340
    case SPS_IDLE:
341
    case SPS_HALT:
342
      /* noop */
343
      break;
344

345
    default:
346
      lj_assertX(0, "bad sysprof profiler state");
347
      break;
348
  }
349
}
57✔
350

351
/* -- Internal ------------------------------------------------------------ */
352

353
static int sysprof_validate(struct sysprof *sp,
19✔
354
                            const struct luam_Sysprof_Options *opt)
355
{
356
  switch (sp->state) {
19✔
357
    case SPS_IDLE:
17✔
358
      if (opt->mode > LUAM_SYSPROF_CALLGRAPH) {
17✔
359
        return PROFILE_ERRUSE;
360
      } else if (opt->mode != LUAM_SYSPROF_DEFAULT &&
16✔
361
                 (opt->buf == NULL || opt->len == 0 || is_unconfigured(sp))) {
7✔
362
        return PROFILE_ERRUSE;
363
      } else if (opt->interval == 0) {
15✔
364
        return PROFILE_ERRUSE;
1✔
365
      }
366
      break;
367

368
    case SPS_PROFILE:
369
    case SPS_HALT:
370
      return PROFILE_ERRRUN;
371

372
    default:
373
      lj_assertX(0, "bad sysprof profiler state");
374
      break;
375
  }
376

377
  return PROFILE_SUCCESS;
378
}
379

380
static int sysprof_init(struct sysprof *sp, lua_State *L,
381
                        const struct luam_Sysprof_Options *opt)
382
{
383
  const int status = sysprof_validate(sp, opt);
384
  if (PROFILE_SUCCESS != status)
385
    return status;
386

387
  /* Copy validated options to sysprof state. */
388
  memcpy(&sp->opt, opt, sizeof(sp->opt));
389

390
  /* Init general fields. */
391
  sp->g = G(L);
392
  sp->thread = pthread_self();
393

394
  /* Reset counters. */
395
  memset(&sp->counters, 0, sizeof(sp->counters));
396

397
  /* Reset saved errno. */
398
  sp->saved_errno = 0;
399

400
  if (stream_is_needed(sp))
401
    lj_wbuf_init(&sp->out, sp->writer, opt->ctx, opt->buf, opt->len);
402

403
  return PROFILE_SUCCESS;
404
}
405

406
/* -- Public profiling API ------------------------------------------------ */
407

408
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
392✔
409
  struct sysprof *sp = &sysprof;
392✔
410

411
  if (sp->state != SPS_IDLE || writer == NULL)
392✔
412
    return PROFILE_ERRUSE;
413

414
  sp->writer = writer;
392✔
415
  if (!is_unconfigured(sp)) {
392✔
416
    sp->state = SPS_IDLE;
1✔
417
  }
418
  return PROFILE_SUCCESS;
419
}
420

421
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
392✔
422
  struct sysprof *sp = &sysprof;
392✔
423

424
  if (sp->state != SPS_IDLE || on_stop == NULL)
392✔
425
    return PROFILE_ERRUSE;
426

427
  sp->on_stop = on_stop;
392✔
428
  if (!is_unconfigured(sp)) {
392✔
429
    sp->state = SPS_IDLE;
1✔
430
  }
431
  return PROFILE_SUCCESS;
432
}
433

434
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
391✔
435
  struct sysprof *sp = &sysprof;
391✔
436

437
  if (sp->state != SPS_IDLE)
391✔
438
    return PROFILE_ERRUSE;
439
  if (backtracer == NULL) {
391✔
440
    sp->backtracer = default_backtrace_host;
391✔
441
    /*
442
    ** XXX: `backtrace` is not signal-safe, according to man,
443
    ** because it is lazy loaded on the first call, which triggers
444
    ** allocations. We need to call `backtrace` before starting profiling
445
    ** to avoid lazy loading.
446
    */
447
    void *dummy = NULL;
391✔
448
    backtrace(&dummy, 1);
391✔
449
  }
450
  else {
451
    sp->backtracer = backtracer;
×
452
  }
453
  if (!is_unconfigured(sp)) {
391✔
454
    sp->state = SPS_IDLE;
391✔
455
  }
456
  return PROFILE_SUCCESS;
457
}
458

459
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
19✔
460
{
461
  struct sysprof *sp = &sysprof;
19✔
462

463
  int status = sysprof_init(sp, L, opt);
19✔
464
  if (PROFILE_SUCCESS != status) {
19✔
465
    if (NULL != sp->on_stop) {
5✔
466
      /*
467
      ** Initialization may fail in case of unconfigured sysprof,
468
      ** so we cannot guarantee cleaning up resources in this case.
469
      */
470
      sp->on_stop(opt->ctx, opt->buf);
5✔
471
    }
472
    return status;
5✔
473
  }
474

475
  sp->state = SPS_PROFILE;
14✔
476

477
  if (stream_is_needed(sp)) {
14✔
478
    stream_prologue(sp);
6✔
479
    if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
6✔
480
      /* on_stop call may change errno value. */
481
      const int saved_errno = lj_wbuf_errno(&sp->out);
×
482
      /* Ignore possible errors. mp->out.buf may be NULL here. */
483
      sp->on_stop(opt->ctx, sp->out.buf);
×
484
      lj_wbuf_terminate(&sp->out);
×
485
      sp->state = SPS_IDLE;
×
486
      errno = saved_errno;
×
487
      return PROFILE_ERRIO;
×
488
    }
489
  }
490

491
  sp->timer.opt.interval_msec = opt->interval;
14✔
492
  sp->timer.opt.handler = sysprof_signal_handler;
14✔
493
  lj_profile_timer_start(&sp->timer);
14✔
494

495
  return PROFILE_SUCCESS;
14✔
496
}
497

498
int lj_sysprof_stop(lua_State *L)
404✔
499
{
500
  struct sysprof *sp = &sysprof;
404✔
501
  global_State *g = sp->g;
404✔
502
  struct lj_wbuf *out = &sp->out;
404✔
503

504
  if (SPS_IDLE == sp->state)
404✔
505
    return PROFILE_ERRRUN;
506
  else if (G(L) != g)
14✔
507
    return PROFILE_ERRUSE;
508

509
  lj_profile_timer_stop(&sp->timer);
14✔
510

511
  if (SPS_HALT == sp->state) {
14✔
512
    errno = sp->saved_errno;
×
513
    sp->state = SPS_IDLE;
×
514
    /* wbuf was terminated when error occurred. */
515
    return PROFILE_ERRIO;
×
516
  }
517

518
  sp->state = SPS_IDLE;
14✔
519

520
  if (stream_is_needed(sp)) {
14✔
521
    int cb_status = 0;
6✔
522

523
    stream_epilogue(sp);
6✔
524
    lj_wbuf_flush(out);
6✔
525

526
    cb_status = sp->on_stop(sp->opt.ctx, out->buf);
6✔
527
    if (LJ_UNLIKELY(lj_wbuf_test_flag(out, STREAM_ERRIO | STREAM_STOP)) ||
6✔
528
        cb_status != 0) {
529
      errno = lj_wbuf_errno(out);
×
530
      lj_wbuf_terminate(out);
×
531
      return PROFILE_ERRIO;
×
532
    }
533

534
    lj_wbuf_terminate(out);
6✔
535
  }
536

537
  return PROFILE_SUCCESS;
538
}
539

540
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
5✔
541
{
542
  const struct sysprof *sp = &sysprof;
5✔
543
  memcpy(counters, &sp->counters, sizeof(sp->counters));
5✔
544
  return PROFILE_SUCCESS;
5✔
545
}
546

547
void lj_sysprof_add_proto(const struct GCproto *pt)
79,243✔
548
{
549
  struct sysprof *sp = &sysprof;
79,243✔
550

551
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
79,243✔
552
    return;
553

554
  /*
555
  ** XXX: Avoid sampling during the symtab extension. That shouldn't have any
556
  ** significant effect on profile precision, but if it does, it's better to
557
  ** implement an async-safe queue for the symtab events.
558
  */
559
  sp->state = SPS_IDLE;
2✔
560
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_LFUNC_EVENT);
2✔
561
  lj_symtab_dump_proto(&sp->out, pt);
2✔
562
  sp->state = SPS_PROFILE;
2✔
563
}
564

565
#if LJ_HASJIT
566
void lj_sysprof_add_trace(const struct GCtrace *tr)
18,291✔
567
{
568
  struct sysprof *sp = &sysprof;
18,291✔
569

570
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
18,291✔
571
    return;
572

573
  /* See the comment about the sysprof state above. */
574
  sp->state = SPS_IDLE;
×
575
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_TRACE_EVENT);
×
576
  lj_symtab_dump_trace(&sp->out, tr);
×
577
  sp->state = SPS_PROFILE;
×
578
}
579
#endif /* LJ_HASJIT */
580

581
#else /* LJ_HASSYSPROF */
582

583
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
584
  UNUSED(writer);
585
  return PROFILE_ERRUSE;
586
}
587

588
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
589
  UNUSED(on_stop);
590
  return PROFILE_ERRUSE;
591
}
592

593
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
594
  UNUSED(backtracer);
595
  return PROFILE_ERRUSE;
596
}
597

598
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
599
{
600
  UNUSED(L);
601
  return PROFILE_ERRUSE;
602
}
603

604
int lj_sysprof_stop(lua_State *L)
605
{
606
  UNUSED(L);
607
  return PROFILE_ERRUSE;
608
}
609

610
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
611
{
612
  UNUSED(counters);
613
  return PROFILE_ERRUSE;
614
}
615

616
void lj_sysprof_add_proto(const struct GCproto *pt)
617
{
618
  UNUSED(pt);
619
}
620

621
#if LJ_HASJIT
622
void lj_sysprof_add_trace(const struct GCtrace *tr)
623
{
624
  UNUSED(tr);
625
}
626
#endif /* LJ_HASJIT */
627

628
#endif /* LJ_HASSYSPROF */
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