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

tarantool / luajit / 13108700322

03 Feb 2025 07:46AM UTC coverage: 92.947% (-0.04%) from 92.983%
13108700322

push

github

Buristan
Reject negative getfenv()/setfenv() levels to prevent compiler warning.

Thanks to Sergey Kaplun.

(cherry picked from commit 9d777346b)

When the number represented the level value is given to the
`getfenv()`/`setfenv()`, it is cast to the `int`. Assume the given value
is `2^31`, i.e. the resulting value after the cast is `INT_MIN`. After
this, it will be decremented in `lj_debug_level()` and underflowed to
the `INT_MAX`. That produces the UBSan warning about signed integer
overflow.

This patch raises the error early in the aforementioned functions, since
a negative level value is meaningless.

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

Part of tarantool/tarantool#11055

5696 of 6035 branches covered (94.38%)

Branch coverage included in aggregate %.

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

16 existing lines in 5 files now uncovered.

21702 of 23442 relevant lines covered (92.58%)

2962933.74 hits per line

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

99.22
/src/lj_func.c
1
/*
2
** Function handling (prototypes, functions and upvalues).
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_func_c
10
#define LUA_CORE
11

12
#include "lj_obj.h"
13
#include "lj_gc.h"
14
#include "lj_func.h"
15
#include "lj_trace.h"
16
#include "lj_vm.h"
17

18
/* -- Prototypes ---------------------------------------------------------- */
19

20
void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt)
62,959✔
21
{
22
  lj_mem_free(g, pt, pt->sizept);
62,959✔
23
}
62,959✔
24

25
/* -- Upvalues ------------------------------------------------------------ */
26

27
static void unlinkuv(global_State *g, GCupval *uv)
17,462✔
28
{
29
  UNUSED(g);
17,462✔
30
  lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv,
17,462✔
31
             "broken upvalue chain");
32
  setgcrefr(uvnext(uv)->prev, uv->prev);
17,462✔
33
  setgcrefr(uvprev(uv)->next, uv->next);
17,462✔
34
}
2,034✔
35

36
/* Find existing open upvalue for a stack slot or create a new one. */
37
static GCupval *func_finduv(lua_State *L, TValue *slot)
27,456✔
38
{
39
  global_State *g = G(L);
27,456✔
40
  GCRef *pp = &L->openupval;
27,456✔
41
  GCupval *p;
27,456✔
42
  GCupval *uv;
27,456✔
43
  /* Search the sorted list of open upvalues. */
44
  while (gcref(*pp) != NULL && uvval((p = gco2uv(gcref(*pp)))) >= slot) {
96,712✔
45
    lj_assertG(!p->closed && uvval(p) != &p->tv, "closed upvalue in chain");
79,250✔
46
    if (uvval(p) == slot) {  /* Found open upvalue pointing to same slot? */
79,250✔
47
      if (isdead(g, obj2gco(p)))  /* Resurrect it, if it's dead. */
9,994✔
UNCOV
48
        flipwhite(obj2gco(p));
×
49
      return p;
9,994✔
50
    }
51
    pp = &p->nextgc;
69,256✔
52
  }
53
  /* No matching upvalue found. Create a new one. */
54
  uv = lj_mem_newt(L, sizeof(GCupval), GCupval);
17,462✔
55
  newwhite(g, uv);
17,462✔
56
  uv->gct = ~LJ_TUPVAL;
17,462✔
57
  uv->closed = 0;  /* Still open. */
17,462✔
58
  setmref(uv->v, slot);  /* Pointing to the stack slot. */
17,462✔
59
  /* NOBARRIER: The GCupval is new (marked white) and open. */
60
  setgcrefr(uv->nextgc, *pp);  /* Insert into sorted list of open upvalues. */
17,462✔
61
  setgcref(*pp, obj2gco(uv));
17,462✔
62
  setgcref(uv->prev, obj2gco(&g->uvhead));  /* Insert into GC list, too. */
17,462✔
63
  setgcrefr(uv->next, g->uvhead.next);
17,462✔
64
  setgcref(uvnext(uv)->prev, obj2gco(uv));
17,462✔
65
  setgcref(g->uvhead.next, obj2gco(uv));
17,462✔
66
  lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv,
17,462✔
67
             "broken upvalue chain");
68
  return uv;
17,462✔
69
}
70

71
/* Create an empty and closed upvalue. */
72
static GCupval *func_emptyuv(lua_State *L)
5✔
73
{
74
  GCupval *uv = (GCupval *)lj_mem_newgco(L, sizeof(GCupval));
10✔
75
  uv->gct = ~LJ_TUPVAL;
5✔
76
  uv->closed = 1;
5✔
77
  setnilV(&uv->tv);
5✔
78
  setmref(uv->v, &uv->tv);
5✔
79
  return uv;
5✔
80
}
81

82
/* Close all open upvalues pointing to some stack level or above. */
83
void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level)
59,030✔
84
{
85
  GCupval *uv;
59,030✔
86
  global_State *g = G(L);
59,030✔
87
  while (gcref(L->openupval) != NULL &&
74,466✔
88
         uvval((uv = gco2uv(gcref(L->openupval)))) >= level) {
67,783✔
89
    GCobj *o = obj2gco(uv);
15,436✔
90
    lj_assertG(!isblack(o), "bad black upvalue");
15,436✔
91
    lj_assertG(!uv->closed && uvval(uv) != &uv->tv, "closed upvalue in chain");
15,436✔
92
    setgcrefr(L->openupval, uv->nextgc);  /* No longer in open list. */
15,436✔
93
    if (isdead(g, o)) {
15,436✔
94
      lj_func_freeuv(g, uv);
8✔
95
    } else {
96
      unlinkuv(g, uv);
15,428✔
97
      lj_gc_closeuv(g, uv);
15,428✔
98
    }
99
  }
100
}
59,030✔
101

102
void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv)
17,285✔
103
{
104
  if (!uv->closed)
17,285✔
105
    unlinkuv(g, uv);
2,034✔
106
  lj_mem_freet(g, uv);
17,285✔
107
}
17,285✔
108

109
/* -- Functions (closures) ------------------------------------------------ */
110

111
GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
75,007✔
112
{
113
  GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeCfunc(nelems));
75,007✔
114
  fn->c.gct = ~LJ_TFUNC;
75,007✔
115
  fn->c.ffid = FF_C;
75,007✔
116
  fn->c.nupvalues = (uint8_t)nelems;
75,007✔
117
  /* NOBARRIER: The GCfunc is new (marked white). */
118
  setmref(fn->c.pc, &G(L)->bc_cfunc_ext);
75,007✔
119
  setgcref(fn->c.env, obj2gco(env));
75,007✔
120
  return fn;
75,007✔
121
}
122

123
static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env)
1,228,914✔
124
{
125
  uint32_t count;
1,228,914✔
126
  GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv));
1,228,914✔
127
  fn->l.gct = ~LJ_TFUNC;
1,228,914✔
128
  fn->l.ffid = FF_LUA;
1,228,914✔
129
  fn->l.nupvalues = 0;  /* Set to zero until upvalues are initialized. */
1,228,914✔
130
  /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */
131
  setmref(fn->l.pc, proto_bc(pt));
1,228,914✔
132
  setgcref(fn->l.env, obj2gco(env));
1,228,914✔
133
  /* Saturating 3 bit counter (0..7) for created closures. */
134
  count = (uint32_t)pt->flags + PROTO_CLCOUNT;
1,228,914✔
135
  pt->flags = (uint8_t)(count - ((count >> PROTO_CLC_BITS) & PROTO_CLCOUNT));
1,228,914✔
136
  return fn;
1,228,914✔
137
}
138

139
/* Create a new Lua function with empty upvalues. */
140
GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env)
43,869✔
141
{
142
  GCfunc *fn = func_newL(L, pt, env);
43,869✔
143
  MSize i, nuv = pt->sizeuv;
43,869✔
144
  /* NOBARRIER: The GCfunc is new (marked white). */
145
  for (i = 0; i < nuv; i++) {
43,874✔
146
    GCupval *uv = func_emptyuv(L);
5✔
147
    int32_t v = proto_uv(pt)[i];
5✔
148
    uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1);
5✔
149
    uv->dhash = (uint32_t)(uintptr_t)pt ^ (v << 24);
5✔
150
    setgcref(fn->l.uvptr[i], obj2gco(uv));
5✔
151
  }
152
  fn->l.nupvalues = (uint8_t)nuv;
43,869✔
153
  return fn;
43,869✔
154
}
155

156
/* Do a GC check and create a new Lua function with inherited upvalues. */
157
GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
1,185,045✔
158
{
159
  GCfunc *fn;
1,185,045✔
160
  GCRef *puv;
1,185,045✔
161
  MSize i, nuv;
1,185,045✔
162
  TValue *base;
1,185,045✔
163
  lj_gc_check_fixtop(L);
1,185,045✔
164
  fn = func_newL(L, pt, tabref(parent->env));
1,185,045✔
165
  /* NOBARRIER: The GCfunc is new (marked white). */
166
  puv = parent->uvptr;
1,185,045✔
167
  nuv = pt->sizeuv;
1,185,045✔
168
  base = L->base;
1,185,045✔
169
  for (i = 0; i < nuv; i++) {
1,216,255✔
170
    uint32_t v = proto_uv(pt)[i];
31,210✔
171
    GCupval *uv;
31,210✔
172
    if ((v & PROTO_UV_LOCAL)) {
31,210✔
173
      uv = func_finduv(L, base + (v & 0xff));
27,456✔
174
      uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1);
27,456✔
175
      uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24);
27,456✔
176
    } else {
177
      uv = &gcref(puv[v])->uv;
3,754✔
178
    }
179
    setgcref(fn->l.uvptr[i], obj2gco(uv));
31,210✔
180
  }
181
  fn->l.nupvalues = (uint8_t)nuv;
1,185,045✔
182
  return fn;
1,185,045✔
183
}
184

185
void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn)
1,301,709✔
186
{
187
  MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) :
1,301,709✔
188
                               sizeCfunc((MSize)fn->c.nupvalues);
73,092✔
189
  lj_mem_free(g, fn, size);
1,301,709✔
190
}
1,301,709✔
191

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