aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2012-06-08 12:14:04 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2012-06-08 12:14:04 -0300
commitcc2a60ecb7e4c57ed31e5c5c3f49d8dc7447acc5 (patch)
treebd702ddf14ba4e1b57959bf978ec062f03ad861f
parent43bfb60ac8add40a6099b933bc8454c11471c386 (diff)
downloadlua-cc2a60ecb7e4c57ed31e5c5c3f49d8dc7447acc5.tar.gz
lua-cc2a60ecb7e4c57ed31e5c5c3f49d8dc7447acc5.tar.bz2
lua-cc2a60ecb7e4c57ed31e5c5c3f49d8dc7447acc5.zip
bugs in yields inside debug hooks
-rw-r--r--lapi.c4
-rw-r--r--ldo.c8
-rw-r--r--lstate.h5
-rw-r--r--lvm.c19
4 files changed, 23 insertions, 13 deletions
diff --git a/lapi.c b/lapi.c
index 9201aac4..b82706fd 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lapi.c,v 2.162 2012/05/22 17:50:39 roberto Exp roberto $ 2** $Id: lapi.c,v 2.163 2012/05/23 15:42:27 roberto Exp roberto $
3** Lua API 3** Lua API
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -950,7 +950,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
950 ci->u.c.k = k; /* save continuation */ 950 ci->u.c.k = k; /* save continuation */
951 ci->u.c.ctx = ctx; /* save context */ 951 ci->u.c.ctx = ctx; /* save context */
952 /* save information for error recovery */ 952 /* save information for error recovery */
953 ci->u.c.extra = savestack(L, c.func); 953 ci->extra = savestack(L, c.func);
954 ci->u.c.old_allowhook = L->allowhook; 954 ci->u.c.old_allowhook = L->allowhook;
955 ci->u.c.old_errfunc = L->errfunc; 955 ci->u.c.old_errfunc = L->errfunc;
956 L->errfunc = func; 956 L->errfunc = func;
diff --git a/ldo.c b/ldo.c
index f3121fd0..9e1a5b00 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ldo.c,v 2.103 2012/04/26 20:41:18 roberto Exp roberto $ 2** $Id: ldo.c,v 2.104 2012/05/08 13:53:33 roberto Exp roberto $
3** Stack and Call structure of Lua 3** Stack and Call structure of Lua
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -451,7 +451,7 @@ static int recover (lua_State *L, int status) {
451 CallInfo *ci = findpcall(L); 451 CallInfo *ci = findpcall(L);
452 if (ci == NULL) return 0; /* no recovery point */ 452 if (ci == NULL) return 0; /* no recovery point */
453 /* "finish" luaD_pcall */ 453 /* "finish" luaD_pcall */
454 oldtop = restorestack(L, ci->u.c.extra); 454 oldtop = restorestack(L, ci->extra);
455 luaF_close(L, oldtop); 455 luaF_close(L, oldtop);
456 seterrorobj(L, status, oldtop); 456 seterrorobj(L, status, oldtop);
457 L->ci = ci; 457 L->ci = ci;
@@ -498,10 +498,10 @@ static void resume (lua_State *L, void *ud) {
498 resume_error(L, "cannot resume dead coroutine", firstArg); 498 resume_error(L, "cannot resume dead coroutine", firstArg);
499 else { /* resuming from previous yield */ 499 else { /* resuming from previous yield */
500 L->status = LUA_OK; 500 L->status = LUA_OK;
501 ci->func = restorestack(L, ci->extra);
501 if (isLua(ci)) /* yielded inside a hook? */ 502 if (isLua(ci)) /* yielded inside a hook? */
502 luaV_execute(L); /* just continue running Lua code */ 503 luaV_execute(L); /* just continue running Lua code */
503 else { /* 'common' yield */ 504 else { /* 'common' yield */
504 ci->func = restorestack(L, ci->u.c.extra);
505 if (ci->u.c.k != NULL) { /* does it have a continuation? */ 505 if (ci->u.c.k != NULL) { /* does it have a continuation? */
506 int n; 506 int n;
507 ci->u.c.status = LUA_YIELD; /* 'default' status */ 507 ci->u.c.status = LUA_YIELD; /* 'default' status */
@@ -563,13 +563,13 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
563 luaG_runerror(L, "attempt to yield from outside a coroutine"); 563 luaG_runerror(L, "attempt to yield from outside a coroutine");
564 } 564 }
565 L->status = LUA_YIELD; 565 L->status = LUA_YIELD;
566 ci->extra = savestack(L, ci->func); /* save current 'func' */
566 if (isLua(ci)) { /* inside a hook? */ 567 if (isLua(ci)) { /* inside a hook? */
567 api_check(L, k == NULL, "hooks cannot continue after yielding"); 568 api_check(L, k == NULL, "hooks cannot continue after yielding");
568 } 569 }
569 else { 570 else {
570 if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ 571 if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
571 ci->u.c.ctx = ctx; /* save context */ 572 ci->u.c.ctx = ctx; /* save context */
572 ci->u.c.extra = savestack(L, ci->func); /* save current 'func' */
573 ci->func = L->top - nresults - 1; /* protect stack below results */ 573 ci->func = L->top - nresults - 1; /* protect stack below results */
574 luaD_throw(L, LUA_YIELD); 574 luaD_throw(L, LUA_YIELD);
575 } 575 }
diff --git a/lstate.h b/lstate.h
index 665cf160..5c6bd67b 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.79 2012/05/22 17:32:25 roberto Exp roberto $ 2** $Id: lstate.h,v 2.80 2012/05/22 17:50:39 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -72,6 +72,7 @@ typedef struct CallInfo {
72 struct CallInfo *previous, *next; /* dynamic call link */ 72 struct CallInfo *previous, *next; /* dynamic call link */
73 short nresults; /* expected number of results from this function */ 73 short nresults; /* expected number of results from this function */
74 lu_byte callstatus; 74 lu_byte callstatus;
75 ptrdiff_t extra;
75 union { 76 union {
76 struct { /* only for Lua functions */ 77 struct { /* only for Lua functions */
77 StkId base; /* base for this function */ 78 StkId base; /* base for this function */
@@ -81,7 +82,6 @@ typedef struct CallInfo {
81 int ctx; /* context info. in case of yields */ 82 int ctx; /* context info. in case of yields */
82 lua_CFunction k; /* continuation in case of yields */ 83 lua_CFunction k; /* continuation in case of yields */
83 ptrdiff_t old_errfunc; 84 ptrdiff_t old_errfunc;
84 ptrdiff_t extra;
85 lu_byte old_allowhook; 85 lu_byte old_allowhook;
86 lu_byte status; 86 lu_byte status;
87 } c; 87 } c;
@@ -100,6 +100,7 @@ typedef struct CallInfo {
100#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ 100#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
101#define CIST_STAT (1<<5) /* call has an error status (pcall) */ 101#define CIST_STAT (1<<5) /* call has an error status (pcall) */
102#define CIST_TAIL (1<<6) /* call was tail called */ 102#define CIST_TAIL (1<<6) /* call was tail called */
103#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */
103 104
104 105
105#define isLua(ci) ((ci)->callstatus & CIST_LUA) 106#define isLua(ci) ((ci)->callstatus & CIST_LUA)
diff --git a/lvm.c b/lvm.c
index cd7642eb..2d27d512 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lvm.c,v 2.150 2012/05/08 13:53:33 roberto Exp roberto $ 2** $Id: lvm.c,v 2.151 2012/05/14 17:50:49 roberto Exp roberto $
3** Lua virtual machine 3** Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -60,10 +60,15 @@ int luaV_tostring (lua_State *L, StkId obj) {
60static void traceexec (lua_State *L) { 60static void traceexec (lua_State *L) {
61 CallInfo *ci = L->ci; 61 CallInfo *ci = L->ci;
62 lu_byte mask = L->hookmask; 62 lu_byte mask = L->hookmask;
63 if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { 63 int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
64 resethookcount(L); 64 if (counthook)
65 luaD_hook(L, LUA_HOOKCOUNT, -1); 65 resethookcount(L); /* reset count */
66 if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
67 ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
68 return; /* do not call hook again (VM yielded, so it did not move) */
66 } 69 }
70 if (counthook)
71 luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */
67 if (mask & LUA_MASKLINE) { 72 if (mask & LUA_MASKLINE) {
68 Proto *p = ci_func(ci)->p; 73 Proto *p = ci_func(ci)->p;
69 int npc = pcRel(ci->u.l.savedpc, p); 74 int npc = pcRel(ci->u.l.savedpc, p);
@@ -71,11 +76,15 @@ static void traceexec (lua_State *L) {
71 if (npc == 0 || /* call linehook when enter a new function, */ 76 if (npc == 0 || /* call linehook when enter a new function, */
72 ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ 77 ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */
73 newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ 78 newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */
74 luaD_hook(L, LUA_HOOKLINE, newline); 79 luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */
75 } 80 }
76 L->oldpc = ci->u.l.savedpc; 81 L->oldpc = ci->u.l.savedpc;
77 if (L->status == LUA_YIELD) { /* did hook yield? */ 82 if (L->status == LUA_YIELD) { /* did hook yield? */
83 if (counthook)
84 L->hookcount = 1; /* undo decrement to zero */
78 ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ 85 ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
86 ci->callstatus |= CIST_HOOKYIELD; /* mark that it yieled */
87 ci->func = L->top - 1; /* protect stack below results */
79 luaD_throw(L, LUA_YIELD); 88 luaD_throw(L, LUA_YIELD);
80 } 89 }
81} 90}