aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2026-05-25 01:23:26 +0200
committerMike Pall <mike>2026-05-25 01:23:26 +0200
commit75abb0d934fef3e3d5aab46e60e34059ac8a1c08 (patch)
tree136333fa8c3628e7e99e3b58d23efd0263bd9b99
parent64b1f10835acc18bf8923adf248dce4894867882 (diff)
downloadluajit-75abb0d934fef3e3d5aab46e60e34059ac8a1c08.tar.gz
luajit-75abb0d934fef3e3d5aab46e60e34059ac8a1c08.tar.bz2
luajit-75abb0d934fef3e3d5aab46e60e34059ac8a1c08.zip
Avoid race condition with profiler thread during dispatch table update.
Reported by artemking4. #1460
-rw-r--r--src/lib_jit.c2
-rw-r--r--src/lj_dispatch.c14
-rw-r--r--src/lj_dispatch.h2
-rw-r--r--src/lj_gc.c4
-rw-r--r--src/lj_profile.c25
-rw-r--r--src/lj_profile.h2
-rw-r--r--src/lj_state.c2
-rw-r--r--src/lj_trace.c8
8 files changed, 43 insertions, 16 deletions
diff --git a/src/lib_jit.c b/src/lib_jit.c
index a7c553ab4..af3e0a6ff 100644
--- a/src/lib_jit.c
+++ b/src/lib_jit.c
@@ -726,7 +726,7 @@ static void jit_init(lua_State *L)
726#if LJ_TARGET_UNALIGNED 726#if LJ_TARGET_UNALIGNED
727 G(L)->tmptv.u64 = U64x(0000504d,4d500000); 727 G(L)->tmptv.u64 = U64x(0000504d,4d500000);
728#endif 728#endif
729 lj_dispatch_update(G(L)); 729 lj_dispatch_update(G(L), 0);
730#if LJ_TARGET_UNALIGNED 730#if LJ_TARGET_UNALIGNED
731 /* If you get a crash below then your toolchain indicates unaligned 731 /* If you get a crash below then your toolchain indicates unaligned
732 ** accesses are OK, but your kernel disagrees. I.e. fix your toolchain. 732 ** accesses are OK, but your kernel disagrees. I.e. fix your toolchain.
diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c
index 636fb0338..9879a95b9 100644
--- a/src/lj_dispatch.c
+++ b/src/lj_dispatch.c
@@ -103,8 +103,11 @@ void lj_dispatch_init_hotcount(global_State *g)
103#define DISPMODE_PROF 0x40 /* Profiling active. */ 103#define DISPMODE_PROF 0x40 /* Profiling active. */
104 104
105/* Update dispatch table depending on various flags. */ 105/* Update dispatch table depending on various flags. */
106void lj_dispatch_update(global_State *g) 106void LJ_FASTCALL lj_dispatch_update(global_State *g, int nolock)
107{ 107{
108#if LJ_HASPROFILE && !LJ_PROFILE_SIGPROF
109 int profile_locked = nolock ? 0 : lj_profile_lock();
110#endif
108 uint8_t oldmode = g->dispatchmode; 111 uint8_t oldmode = g->dispatchmode;
109 uint8_t mode = 0; 112 uint8_t mode = 0;
110#if LJ_HASJIT 113#if LJ_HASJIT
@@ -208,6 +211,11 @@ void lj_dispatch_update(global_State *g)
208 lj_dispatch_init_hotcount(g); 211 lj_dispatch_init_hotcount(g);
209#endif 212#endif
210 } 213 }
214#if LJ_HASPROFILE && !LJ_PROFILE_SIGPROF
215 if (profile_locked) lj_profile_unlock();
216#else
217 UNUSED(nolock);
218#endif
211} 219}
212 220
213/* -- JIT mode setting ---------------------------------------------------- */ 221/* -- JIT mode setting ---------------------------------------------------- */
@@ -260,7 +268,7 @@ int luaJIT_setmode(lua_State *L, int idx, int mode)
260 G2J(g)->flags &= ~(uint32_t)JIT_F_ON; 268 G2J(g)->flags &= ~(uint32_t)JIT_F_ON;
261 else 269 else
262 G2J(g)->flags |= (uint32_t)JIT_F_ON; 270 G2J(g)->flags |= (uint32_t)JIT_F_ON;
263 lj_dispatch_update(g); 271 lj_dispatch_update(g, 0);
264 } 272 }
265 break; 273 break;
266 case LUAJIT_MODE_FUNC: 274 case LUAJIT_MODE_FUNC:
@@ -335,7 +343,7 @@ LUA_API int lua_sethook(lua_State *L, lua_Hook func, int mask, int count)
335 g->hookcount = g->hookcstart = (int32_t)count; 343 g->hookcount = g->hookcstart = (int32_t)count;
336 g->hookmask = (uint8_t)((g->hookmask & ~HOOK_EVENTMASK) | mask); 344 g->hookmask = (uint8_t)((g->hookmask & ~HOOK_EVENTMASK) | mask);
337 lj_trace_abort(g); /* Abort recording on any hook change. */ 345 lj_trace_abort(g); /* Abort recording on any hook change. */
338 lj_dispatch_update(g); 346 lj_dispatch_update(g, 0);
339 return 1; 347 return 1;
340} 348}
341 349
diff --git a/src/lj_dispatch.h b/src/lj_dispatch.h
index 8492f7930..9baf762b2 100644
--- a/src/lj_dispatch.h
+++ b/src/lj_dispatch.h
@@ -132,7 +132,7 @@ LJ_FUNC void lj_dispatch_init(GG_State *GG);
132#if LJ_HASJIT 132#if LJ_HASJIT
133LJ_FUNC void lj_dispatch_init_hotcount(global_State *g); 133LJ_FUNC void lj_dispatch_init_hotcount(global_State *g);
134#endif 134#endif
135LJ_FUNC void lj_dispatch_update(global_State *g); 135LJ_FUNC void LJ_FASTCALL lj_dispatch_update(global_State *g, int nolock);
136 136
137/* Instruction dispatch callback for hooks or when recording. */ 137/* Instruction dispatch callback for hooks or when recording. */
138LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc); 138LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc);
diff --git a/src/lj_gc.c b/src/lj_gc.c
index 1fed0b54f..3ca6cf1bf 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -512,7 +512,7 @@ static void gc_call_finalizer(global_State *g, lua_State *L,
512 TValue *top; 512 TValue *top;
513 lj_trace_abort(g); 513 lj_trace_abort(g);
514 hook_entergc(g); /* Disable hooks and new traces during __gc. */ 514 hook_entergc(g); /* Disable hooks and new traces during __gc. */
515 if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g); 515 if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g, 0);
516 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */ 516 g->gc.threshold = LJ_MAX_MEM; /* Prevent GC steps. */
517 top = VL->top; 517 top = VL->top;
518 copyTV(VL, top++, mo); 518 copyTV(VL, top++, mo);
@@ -522,7 +522,7 @@ static void gc_call_finalizer(global_State *g, lua_State *L,
522 errcode = lj_vm_pcall(VL, top, 1+0, -1); /* Stack: |mo|o| -> | */ 522 errcode = lj_vm_pcall(VL, top, 1+0, -1); /* Stack: |mo|o| -> | */
523 setgcref(g->cur_L, obj2gco(L)); 523 setgcref(g->cur_L, obj2gco(L));
524 hook_restore(g, oldh); 524 hook_restore(g, oldh);
525 if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g); 525 if (LJ_HASPROFILE && (oldh & HOOK_PROFILE)) lj_dispatch_update(g, 0);
526 g->gc.threshold = oldt; /* Restore GC threshold. */ 526 g->gc.threshold = oldt; /* Restore GC threshold. */
527 if (errcode) { 527 if (errcode) {
528 TValue tmp; 528 TValue tmp;
diff --git a/src/lj_profile.c b/src/lj_profile.c
index fcab1105b..5b2a2b6c7 100644
--- a/src/lj_profile.c
+++ b/src/lj_profile.c
@@ -118,6 +118,23 @@ void LJ_FASTCALL lj_profile_hook_leave(global_State *g)
118 hook_leave(g); 118 hook_leave(g);
119 } 119 }
120} 120}
121
122int lj_profile_lock(void)
123{
124 ProfileState *ps = &profile_state;
125 if (ps->g) {
126 profile_lock(ps);
127 return 1;
128 } else {
129 return 0;
130 }
131}
132
133void lj_profile_unlock(void)
134{
135 ProfileState *ps = &profile_state;
136 profile_unlock(ps);
137}
121#endif 138#endif
122 139
123/* -- Profile callbacks --------------------------------------------------- */ 140/* -- Profile callbacks --------------------------------------------------- */
@@ -134,14 +151,14 @@ void LJ_FASTCALL lj_profile_interpreter(lua_State *L)
134 int samples = ps->samples; 151 int samples = ps->samples;
135 ps->samples = 0; 152 ps->samples = 0;
136 g->hookmask = HOOK_VMEVENT; 153 g->hookmask = HOOK_VMEVENT;
137 lj_dispatch_update(g); 154 lj_dispatch_update(g, 1);
138 profile_unlock(ps); 155 profile_unlock(ps);
139 ps->cb(ps->data, L, samples, ps->vmstate); /* Invoke user callback. */ 156 ps->cb(ps->data, L, samples, ps->vmstate); /* Invoke user callback. */
140 profile_lock(ps); 157 profile_lock(ps);
141 mask |= (g->hookmask & HOOK_PROFILE); 158 mask |= (g->hookmask & HOOK_PROFILE);
142 } 159 }
143 g->hookmask = mask; 160 g->hookmask = mask;
144 lj_dispatch_update(g); 161 lj_dispatch_update(g, 1);
145 profile_unlock(ps); 162 profile_unlock(ps);
146} 163}
147 164
@@ -160,7 +177,7 @@ static void profile_trigger(ProfileState *ps)
160 st == ~LJ_VMST_C ? 'C' : 177 st == ~LJ_VMST_C ? 'C' :
161 st == ~LJ_VMST_GC ? 'G' : 'J'; 178 st == ~LJ_VMST_GC ? 'G' : 'J';
162 g->hookmask = (mask | HOOK_PROFILE); 179 g->hookmask = (mask | HOOK_PROFILE);
163 lj_dispatch_update(g); 180 lj_dispatch_update(g, 1);
164 } 181 }
165 profile_unlock(ps); 182 profile_unlock(ps);
166} 183}
@@ -344,7 +361,7 @@ LUA_API void luaJIT_profile_stop(lua_State *L)
344 if (G(L) == g) { /* Only stop profiler if started by this VM. */ 361 if (G(L) == g) { /* Only stop profiler if started by this VM. */
345 profile_timer_stop(ps); 362 profile_timer_stop(ps);
346 g->hookmask &= ~HOOK_PROFILE; 363 g->hookmask &= ~HOOK_PROFILE;
347 lj_dispatch_update(g); 364 lj_dispatch_update(g, 0);
348#if LJ_HASJIT 365#if LJ_HASJIT
349 G2J(g)->prof_mode = 0; 366 G2J(g)->prof_mode = 0;
350 lj_trace_flushall(L); 367 lj_trace_flushall(L);
diff --git a/src/lj_profile.h b/src/lj_profile.h
index 8b12437dd..43a36b6b1 100644
--- a/src/lj_profile.h
+++ b/src/lj_profile.h
@@ -14,6 +14,8 @@ LJ_FUNC void LJ_FASTCALL lj_profile_interpreter(lua_State *L);
14#if !LJ_PROFILE_SIGPROF 14#if !LJ_PROFILE_SIGPROF
15LJ_FUNC void LJ_FASTCALL lj_profile_hook_enter(global_State *g); 15LJ_FUNC void LJ_FASTCALL lj_profile_hook_enter(global_State *g);
16LJ_FUNC void LJ_FASTCALL lj_profile_hook_leave(global_State *g); 16LJ_FUNC void LJ_FASTCALL lj_profile_hook_leave(global_State *g);
17LJ_FUNC int lj_profile_lock(void);
18LJ_FUNC void lj_profile_unlock(void);
17#endif 19#endif
18 20
19#endif 21#endif
diff --git a/src/lj_state.c b/src/lj_state.c
index 0c2c07505..0b997c6e8 100644
--- a/src/lj_state.c
+++ b/src/lj_state.c
@@ -337,7 +337,7 @@ LUA_API void lua_close(lua_State *L)
337#if LJ_HASJIT 337#if LJ_HASJIT
338 G2J(g)->flags &= ~JIT_F_ON; 338 G2J(g)->flags &= ~JIT_F_ON;
339 G2J(g)->state = LJ_TRACE_IDLE; 339 G2J(g)->state = LJ_TRACE_IDLE;
340 lj_dispatch_update(g); 340 lj_dispatch_update(g, 0);
341#endif 341#endif
342 for (i = 0;;) { 342 for (i = 0;;) {
343 hook_enter(g); 343 hook_enter(g);
diff --git a/src/lj_trace.c b/src/lj_trace.c
index e55045f4e..24a1f7e45 100644
--- a/src/lj_trace.c
+++ b/src/lj_trace.c
@@ -656,7 +656,7 @@ static int trace_abort(jit_State *J)
656 } else if (e == LJ_TRERR_MCODEAL) { 656 } else if (e == LJ_TRERR_MCODEAL) {
657 if (!J->mcarea) { /* Disable JIT compiler if first mcode alloc fails. */ 657 if (!J->mcarea) { /* Disable JIT compiler if first mcode alloc fails. */
658 J->flags &= ~JIT_F_ON; 658 J->flags &= ~JIT_F_ON;
659 lj_dispatch_update(J2G(J)); 659 lj_dispatch_update(J2G(J), 0);
660 } 660 }
661 lj_trace_flushall(L); 661 lj_trace_flushall(L);
662 } 662 }
@@ -687,7 +687,7 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud)
687 case LJ_TRACE_START: 687 case LJ_TRACE_START:
688 J->state = LJ_TRACE_RECORD; /* trace_start() may change state. */ 688 J->state = LJ_TRACE_RECORD; /* trace_start() may change state. */
689 trace_start(J); 689 trace_start(J);
690 lj_dispatch_update(J2G(J)); 690 lj_dispatch_update(J2G(J), 0);
691 if (J->state != LJ_TRACE_RECORD_1ST) 691 if (J->state != LJ_TRACE_RECORD_1ST)
692 break; 692 break;
693 /* fallthrough */ 693 /* fallthrough */
@@ -745,7 +745,7 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud)
745 trace_stop(J); 745 trace_stop(J);
746 setvmstate(J2G(J), INTERP); 746 setvmstate(J2G(J), INTERP);
747 J->state = LJ_TRACE_IDLE; 747 J->state = LJ_TRACE_IDLE;
748 lj_dispatch_update(J2G(J)); 748 lj_dispatch_update(J2G(J), 0);
749 return NULL; 749 return NULL;
750 750
751 default: /* Trace aborted asynchronously. */ 751 default: /* Trace aborted asynchronously. */
@@ -757,7 +757,7 @@ static TValue *trace_state(lua_State *L, lua_CFunction dummy, void *ud)
757 goto retry; 757 goto retry;
758 setvmstate(J2G(J), INTERP); 758 setvmstate(J2G(J), INTERP);
759 J->state = LJ_TRACE_IDLE; 759 J->state = LJ_TRACE_IDLE;
760 lj_dispatch_update(J2G(J)); 760 lj_dispatch_update(J2G(J), 0);
761 return NULL; 761 return NULL;
762 } 762 }
763 } while (J->state > LJ_TRACE_RECORD); 763 } while (J->state > LJ_TRACE_RECORD);