Nmap Development mailing list archives

Re: [NSE] assertion failure in stdnse.sleep()


From: Patrick Donnelly <batrick () batbytes com>
Date: Wed, 17 Oct 2012 17:54:38 -0400

Hi David,

On Wed, Oct 17, 2012 at 4:59 PM, David Fifield <david () bamsoftware com> wrote:
One is that
calling sleep or another yielding function doesn't seem to work from an
exception handler:

local stdnse = require('stdnse')
prerule = function() return true end
action = function()
  local catch = function() stdnse.sleep(20) end
  local try = nmap.new_try(catch)
  try(false)
end

attempt to yield across metamethod/C-call boundary
stack traceback:
        [C]: in function 'sleep'
        a.nse:4: in function <a.nse:4>
        [C]: in function 'try'
        a.nse:6: in function <a.nse:3>
        (...tail calls...)

I'm confused by this error because I thought that "yield across
metamethod/C-call boundary" wasn't a thing anymore with Lua 5.2.

It still exists. A regular lua_call (in C [1]) does not allow
coroutine yields to cross the call boundary. We still use lua_call in
new_try_finalize.

To contrast, many call paths in Lua have been adapted so that you
never see this C boundary error anymore, e.g. pcall [2] or dofile [3].
These functions use lua_callk or lua_pcallk. Lua allows yields across
these functions because the caller passes a continuation function to
Lua. This enables Lua to restart the function when the coroutine is
resumed again. See for example, the continuation function for pcall
[4]. Continuations are explained in the manual [5].

I wrote a quick patch (untested) which should correct the problem, attached.

[1] http://www.lua.org/manual/5.2/manual.html#lua_call
[2] http://www.lua.org/source/5.2/lbaselib.c.html#luaB_pcall
[3] http://www.lua.org/source/5.2/lbaselib.c.html#luaB_dofile
[4] http://www.lua.org/source/5.2/lbaselib.c.html#pcallcont
[5] http://www.lua.org/manual/5.2/manual.html#4.7

I thought about using nse_destructor to have l_sleep register a
destructor that cancels the timer event; hopefully this happens before
the thread is freed.

Destructors are run before the thread is freed.

For socket functions, they are able to associate the thread with the
socket userdatum to ensure the thread is never collected before the
socket userdatum is collected. [This is why it's not necessary to
register a destructor for socket methods as, if the thread no longer
exists, the nse_restore function will silently fail. This could happen
if NSE throws out a timed out script and the nsock callback tries to
nse_restore the thread.] Unfortunately, we don't have that convenience
for the sleep function.

I guess the appropriate way to deal with this unique problem is both
making try/catch C continuation compatible (with the patch attached)
and
adding a destructor to sleep so this situation can't happen again.

-- 
- Patrick Donnelly

Attachment: finalize-callk.patch
Description:

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/

Current thread: