[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Adding another way to point to "levels" to debug.getinfo and friends
- From: Sean Conner <sean@...>
- Date: Sun, 12 May 2019 19:02:25 -0400
It was thus said that the Great Eduardo Ochs once stated:
> Hi list,
>
> Two questions:
>
> 1) Is there a standard header that I can put in my e-mails that means
> "this is _NOT GOING to be used in production code UNDER ANY
> CIRCUMSTANCES_, this is going to be a personal hack that I will
> only load into a Lua interpreter BY HAND for some VERY CONTROLLED
> tests, etc, etc"?
There is no such header. RFC-822 states that no field that is officially
defined will start with "X-" (or "x-" because header names are case
insensitive):
Any field which is defined in a document published as a formal
extension to this specification; none will have names beginning with
the string "X-"
but RFC-2822 (which obsoletes RFC-822) and RFC-5322 (which obsoletes
RFC-2822) have no such language, instead saying:
Fields may appear in messages that are otherwise unspecified in this
document. They MUST conform to the syntax of an optional-field.
This is a field name, made up of the printable US-ASCII characters
except SP and colon, followed by a colon, followed by any text that
conforms to the unstructured syntax.
The field names of any optional field MUST NOT be identical to any
field name specified elsewhere in this document.
In other RFC documents (too many to mention) private or experimental fields
are usually labeled with "X-" (or "x-") so your best bet is to create a
header name starting with "X-" to be safe. In fact, the email I'm replying
to has the following headers starting with "X-":
X-Google-DKIM-Signature
X-Gm-Message-State
X-Google-Smtp-Source
X-Received
X-Pepperfish-Transaction
X-Spam-Score
X-Spam-Score-int
X-Spam-Bar
X-Scanned-By
X-Spam-Report
X-ACL-Warn
X-Scan-Signature
X-BeenThere
X-Mailman-Version
> 2) Here is the idea; the question is below.
>
> The functions debug.getinfo, debug.getlocal and debug.setlocal are
> usually called with an integer argument that the manual refers to
> as "level", that is processed like this (I took the code from
> db_getinfo, in ldblib.c) to set the variable "ar" to an "activation
> record":
>
> if (lua_isnumber(L, arg+1)) {
> if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
> lua_pushnil(L); /* level out of range */
> return 1;
> }
> }
>
> I would like to have _variants_ of these functions, to be called
> debug.mygetinfo, debug.mygetlocal and debug.mysetlocal, that would
> accept an alternative to a numerical "level". Running
>
> ar = debug.mygetstack(2)
>
> would set ar to a string like
>
> "activation record: 0x125cf20"
>
> whose address part points to the "activation record" of a function
> in the call stack, like the pointer that
>
> lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)
>
> puts into ar, and if we are super-ultra-careful then we can call
> debug.mygetinfo, debug.mygetlocal and debug.mysetlocal in either of
> these ways, the second one being equivalent to the first one:
>
> debug.mygetinfo (2, "n")
> debug.mygetinfo (ar, "n")
> debug.mygetlocal(2, 3)
> debug.mygetlocal(ar, 3)
> debug.mysetlocal(2, 3, 42)
> debug.mysetlocal(ar, 3, 42)
>
> But OF COURSE if we set ar to a bad address, say,
>
> ar = "activation record: 0x12345678"
>
> then debug.mygetinfo, debug.mygetlocal and debug.mysetlocal WOULD
> NOT HESITATE to use that address and segfault (HAHAHA! DEAL WITH
> THIS, MODERN PROGRAMMERS!!!)...
Does debug.mysetlocal() (to pick one at random) *parse* the ar string? Or
do you mean to return the actual address of the ar structure? I don't think
this will work as you think it will work.
static int mydebug_mygetstack(lua_State *L)
{
lua_Debug ar;
lua_getstack(L,luaL_checkinteger(L,1),&ar);
lua_pushfstring(L,"activation record: %p",(void *)&ar);
return 1;
}
The problem here is how lua_getstack() works---it wants a pointer to a
lua_Debug structure. The C standard (C99, 6.2.4) says this:
4 An object whose identifier is declared with no linkage and without
the storage-class specifier static has automatic storage duration.
5 For such an object that does not have a variable length array
type, its lifetime extends from entry into the block with which it
is associated until execution of that block ends in any way.
(Entering an enclosed block or calling a function suspends, but does
not end, execution of the current block.) If the block is entered
recursively, a new instance of the object is created each time. The
initial value of the object is indeterminate. If an initialization
is specified for the object, it is performed each time the
declaration is reached in the execution of the block; otherwise, the
value becomes indeterminate each time the declaration is reached.
"ar" here has automatic storage duration---it only lives as long as we are
in the function mydebug_mygetstack(). Once the function returns, the
address of "ar" is no longer valid [1]. You can get around this by doing:
static int mydebug_mygetstack(lua_State *L)
{
lua_Debug *ar;
lua_settop(L,1);
ar = lua_newuserdata(L,sizeof(lua_Debug));
lua_getstack(L,luaL_checkinteger(L,1),ar);
lua_pushfstring(L,"activation record: %p",(void *)ar);
return 1;
}
That's a *little* better in that you are returning the address of a
heap-allocated block of memory, and as long as the return value isn't
garbaged collected by Lua, it will be a valid address to use (and when it
goes out of scope, "C undefined behavior" [2]. Of course, you could do:
static int mydebug_mygetstack(lua_State *L)
{
lua_Debug *ar;
ar = malloc(sizeof(lua_Debug));
if (ar != NULL)
{
lua_getstack(L,luaL_checkinteger(L,1),ar);
lua_pushfstring(L,"activation record: %p",(void *)ar);
}
else
lua_pushnil(L);
return 1;
}
This is better in that it avoids "C undefined behavior" [2], but you could
leak memory this way, unless you manually free it when it's no longer used
(which kind of defeats the purpose of garbage collection).
Parsing the address from the string is problematic, not only for the case
you stated, but in doing it "safely." About the best way to do it is to use
strtoull() to parse the number, and if it doesn't return an error [3], check
it against UINTPTR_MAX and if less, cast the result to uintptr_t, then 'void
*' then the type you want. Yes, it's exceedingly pedantic, but there are
those on this list that would say that even *that* is unsafe to do.
Anyway ... my guess is that you want a absolute reference to an
activation record, not a relative one. Is that the case?
-spc
[1] No longer valid for use as a lua_Debug object. On any modern system
(which is 99 44/100% likely to be an x86 based system) the address
will exist, but point into the process' stack space, but what the
contents are will *NOT* likely be what you expect. [2]
[2] This is what is called in C "undefined behavior". There's another
current thread on this mailing list about that.
[3] It returns ULLONG_MAX and sets errno to ERANGE.