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

tarantool / luajit / 7119175127

06 Dec 2023 06:58PM UTC coverage: 88.591% (-0.03%) from 88.621%
7119175127

push

github

igormunkin
Fix HREFK forwarding vs. table.clear().

Reported by XmiliaH.

(cherry-picked from commit d5a237eae)

When performing HREFK (and also ALOAD, HLOAD) forwarding optimization,
the `table.clear()` function call may be performed on the table operand
from HREFK between table creation and IR, from which value is forwarded.
This call isn't taken in the account, so it may lead to too optimistic
value-forwarding from NEWREF (and also ASTORE, HSTORE), or the omitted
type guard for HREFK operation. Therefore, this leads to incorrect trace
behaviour (for example, taking a non-nil value from the cleared table).

This patch adds necessary checks for `table.clear()` calls.

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

Part of tarantool/tarantool#9145

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

5377 of 5987 branches covered (0.0%)

Branch coverage included in aggregate %.

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

24 existing lines in 5 files now uncovered.

20619 of 23357 relevant lines covered (88.28%)

2754697.77 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)
57,291✔
21
{
22
  lj_mem_free(g, pt, pt->sizept);
57,291✔
23
}
57,291✔
24

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

27
static void unlinkuv(global_State *g, GCupval *uv)
14,269✔
28
{
29
  UNUSED(g);
14,269✔
30
  lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv,
14,269✔
31
             "broken upvalue chain");
32
  setgcrefr(uvnext(uv)->prev, uv->prev);
14,269✔
33
  setgcrefr(uvprev(uv)->next, uv->next);
14,269✔
34
}
2,030✔
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)
20,854✔
38
{
39
  global_State *g = G(L);
20,854✔
40
  GCRef *pp = &L->openupval;
20,854✔
41
  GCupval *p;
20,854✔
42
  GCupval *uv;
20,854✔
43
  /* Search the sorted list of open upvalues. */
44
  while (gcref(*pp) != NULL && uvval((p = gco2uv(gcref(*pp)))) >= slot) {
58,294✔
45
    lj_assertG(!p->closed && uvval(p) != &p->tv, "closed upvalue in chain");
44,025✔
46
    if (uvval(p) == slot) {  /* Found open upvalue pointing to same slot? */
44,025✔
47
      if (isdead(g, obj2gco(p)))  /* Resurrect it, if it's dead. */
6,585✔
UNCOV
48
        flipwhite(obj2gco(p));
×
49
      return p;
6,585✔
50
    }
51
    pp = &p->nextgc;
37,440✔
52
  }
53
  /* No matching upvalue found. Create a new one. */
54
  uv = lj_mem_newt(L, sizeof(GCupval), GCupval);
14,269✔
55
  newwhite(g, uv);
14,269✔
56
  uv->gct = ~LJ_TUPVAL;
14,269✔
57
  uv->closed = 0;  /* Still open. */
14,269✔
58
  setmref(uv->v, slot);  /* Pointing to the stack slot. */
14,269✔
59
  /* NOBARRIER: The GCupval is new (marked white) and open. */
60
  setgcrefr(uv->nextgc, *pp);  /* Insert into sorted list of open upvalues. */
14,269✔
61
  setgcref(*pp, obj2gco(uv));
14,269✔
62
  setgcref(uv->prev, obj2gco(&g->uvhead));  /* Insert into GC list, too. */
14,269✔
63
  setgcrefr(uv->next, g->uvhead.next);
14,269✔
64
  setgcref(uvnext(uv)->prev, obj2gco(uv));
14,269✔
65
  setgcref(g->uvhead.next, obj2gco(uv));
14,269✔
66
  lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv,
14,269✔
67
             "broken upvalue chain");
68
  return uv;
14,269✔
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)
43,259✔
84
{
85
  GCupval *uv;
43,259✔
86
  global_State *g = G(L);
43,259✔
87
  while (gcref(L->openupval) != NULL &&
55,508✔
88
         uvval((uv = gco2uv(gcref(L->openupval)))) >= level) {
52,038✔
89
    GCobj *o = obj2gco(uv);
12,249✔
90
    lj_assertG(!isblack(o), "bad black upvalue");
12,249✔
91
    lj_assertG(!uv->closed && uvval(uv) != &uv->tv, "closed upvalue in chain");
12,249✔
92
    setgcrefr(L->openupval, uv->nextgc);  /* No longer in open list. */
12,249✔
93
    if (isdead(g, o)) {
12,249✔
94
      lj_func_freeuv(g, uv);
10✔
95
    } else {
96
      unlinkuv(g, uv);
12,239✔
97
      lj_gc_closeuv(g, uv);
12,239✔
98
    }
99
  }
100
}
43,259✔
101

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

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

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

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

139
/* Create a new Lua function with empty upvalues. */
140
GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env)
42,444✔
141
{
142
  GCfunc *fn = func_newL(L, pt, env);
42,444✔
143
  MSize i, nuv = pt->sizeuv;
42,444✔
144
  /* NOBARRIER: The GCfunc is new (marked white). */
145
  for (i = 0; i < nuv; i++) {
42,449✔
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;
42,444✔
153
  return fn;
42,444✔
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,046,965✔
158
{
159
  GCfunc *fn;
1,046,965✔
160
  GCRef *puv;
1,046,965✔
161
  MSize i, nuv;
1,046,965✔
162
  TValue *base;
1,046,965✔
163
  lj_gc_check_fixtop(L);
1,046,965✔
164
  fn = func_newL(L, pt, tabref(parent->env));
1,046,965✔
165
  /* NOBARRIER: The GCfunc is new (marked white). */
166
  puv = parent->uvptr;
1,046,965✔
167
  nuv = pt->sizeuv;
1,046,965✔
168
  base = L->base;
1,046,965✔
169
  for (i = 0; i < nuv; i++) {
1,071,471✔
170
    uint32_t v = proto_uv(pt)[i];
24,506✔
171
    GCupval *uv;
24,506✔
172
    if ((v & PROTO_UV_LOCAL)) {
24,506✔
173
      uv = func_finduv(L, base + (v & 0xff));
20,854✔
174
      uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1);
20,854✔
175
      uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24);
20,854✔
176
    } else {
177
      uv = &gcref(puv[v])->uv;
3,652✔
178
    }
179
    setgcref(fn->l.uvptr[i], obj2gco(uv));
24,506✔
180
  }
181
  fn->l.nupvalues = (uint8_t)nuv;
1,046,965✔
182
  return fn;
1,046,965✔
183
}
184

185
void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn)
1,142,067✔
186
{
187
  MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) :
1,142,067✔
188
                               sizeCfunc((MSize)fn->c.nupvalues);
52,944✔
189
  lj_mem_free(g, fn, size);
1,142,067✔
190
}
1,142,067✔
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

© 2025 Coveralls, Inc