[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Easy "assign-protect" of global userdata
- From: Flyer31 Test <flyer31@...>
- Date: Sun, 14 Nov 2021 23:12:58 +0100
Hi List,
as I reported in my "Low RAM report" 1 week ago:
I am just working on a "string buffer" lib, which uses
"length-constrained strings" (maximum 250 bytes) for "heavy text work"
without any allocation of new string elements.
[Side remark: During this work last week I recognized quite a terrible
misunderstanding in my code. I had recognized that after 2 invokes of
garbagecollect the by 60kB heap RAM memory ran out... now I found a
possible error for this: By some stupid error I unfortunately used at
2 "regularly happening positions (during any yield/resume cycle)"
new/delete for tiny struct data in my own C code, this somehow "of
course" was NOT really intended... Like this in "competition to Lua
gc", also my own C code invoked malloc quite often ... and this then
of course made successful life for Lua gc nearly impossible with such
restricted RAM... I did not check this completely, I will need some
more days to clarify this and report then... Now I overwrote the new
and delete operators with assert(0) constructions, so that I will now
be sure that I do not use new/delete any more... . (I am generally
used to this - in Controller C code I usually NEVER use dynamic memory
- so no general problem to reserve all my heap for Lua)...]
But separately from this, when I work with my strbuf elements, I first
had the following problem, if I want to do the following lua code:
Buf=sb.setup( 100) -- defines new stringbuf "Buf" with
100 byte length
Buf='hallo'
Now of course I would like that by string buffer Buffer contains the
the text 'hallo'. But unfortunately after this, my buffer Buf will NOT
exist anymore, but instead will have been "converted" to a string by
Lua... . With the metafunctions __index / __newindex, I fixed this in
a FIRST approach like this:
Buf=sb.setup( 100) -- defines new stringbuf "Buf" with
100 byte length
Buf[1]='hallo' -- "...[1]" required, to keep Buf "alive"
... but is really rather dangerous. There is always some risk that the
user by some accident would use Buf='hallo' (or Buf=Buf1), I by
accident did this quite fast myself... ... and all this Buf should
survive, just then of course should have updated the contents of Buf.
Now I found a very nice solution for this problem - at least for
global string buffers (this restriction is fine for me, I do not want
them local...). After installing metatable for _G, with __index and
__newindex for _G (see my other post some days ago and hint of Sean),
I can quite easily replace any variable "SB..." by "__SB...", so that
SB... will NOT exist in _G, and thus then G__newindex will be invoked
EVERY time, write SBbuf=anything... . This is nice then and solves all
my problems with this:
static int G__index (lua_State *L) {
const char* pcName= lua_tostring( L, 2);
if( pcName && pcName[0]== 'S' && pcName[1]== 'B'){
// access to strbuf SB...: replace by __SB...
char ac__Name[20+3]= "__";
int iLen= strlen( pcName);
luaL_argexpected( L, iLen <= sizeof( ac__Name)-3, 2, "valid");
memcpy( ac__Name+2, pcName, iLen+1);
lua_pushstring( L, ac__Name);
int iTyp= lua_rawget( L, 1); // get __SB... data
assert( iTyp== LUA_TUSERDATA); // just for security
return 1; // and return this
}
// standard __index functionality otherwise:
lua_pushvalue( L, -1);
lua_rawget( L, 1);
return 1;
}
static int G__newindex (lua_State *L) {
LPCSTR pcName= lua_tostring( L, 2);
if( pcName && pcName[0]== 'S' && pcName[1]== 'B'){
// assign to strbuf SB...: either init __SB..., or invoke __SB[nil]
char ac__Name[20+3]= "__";
int iLen= strlen( pcName);
luaL_argexpected( L, iLen <= sizeof( ac__Name)-3, 2, "valid");
memcpy( ac__Name+2, pcName, iLen+1);
lua_pushstring( L, ac__Name);
int iTyp= lua_rawget( L, 1); // get __SB... from _G if available
if( iTyp<= LUA_TNIL){
//not yet available: __SB... init
lua_pop( L, 1);
lua_pushstring( L, ac__Name);
luaL_checkudata(L, 3, "strbuf"); // value must be valid strbuf
lua_pushvalue( L, 3);
lua_rawset( L, 1); // _G("__SB...")= value
assert( lua_gettop( L)== 3);
return 0;
}
// __SB... available: call sb__newindex(L) with correct stack pars
luaL_checkudata(L, -1, "strbuf"); // __SB... must be valid strbuf
lua_replace( L, 1);
lua_pushnil( L);
lua_replace( L, 2);
assertIfDebug( lua_gettop( L)== 3);
return sb__newindex(L); // __SB...[nil]=value (strbuf/nil/string)
}
// otherwise: Do standard action of G__newaction... :
lua_pushvalue( L, -2);
lua_pushvalue( L, -2);
lua_rawset( L, 1);
assertIfDebug( lua_gettop( L)== 3);
return 0;
}
Only two conditions remain:
- this works only for globals (not for locals), but this is fine for
me - I will allow my sb.setup
function to work only for globals.
- the string buffer names (and only them) now must start in some
"predefined way" SB..., but
this also fine for me - I do not see a problem here for my
application (and I check this in the
G__index / G__newindex, this only is some 3-4 lines more very easy code.
... I am very happy with this so far ... if anybody sees any problems,
please give me a note... . I hope some other people also might like
this / think this is useful for them.