2

I use Lua for arrays manipulating; arrays are simple binary data:

local ram_ctx = {0,0,0,0,0,0,0,0,0}

I want to pass it to GUI written in C. The problem is if I pass it directly like func(ram_ctx), Lua function seems to stop executing after a call. Corresponding C function are not executed (it can be empty). But if I make global array in Lua and access it with lua_getglobal - everything seems to be OK. What I'm doing wrong or is it possible at all? It is not OK to pass array name as argument in order to call it as global array

Lua code:

function device_init()
--set_callback(1000000000000, 0)
local array = {0xFF,0,0,0,0,0,0}
--create_memory_popup("Test")
set_memory_popup(array)
end

Here is C code I try to use:

static int32_t lua_set_popup_memory (lua_State *L) 
{  
  int32_t argnum = lua_gettop(L);
  if (1 != argnum)
  {
    out_error("Function %s expects 1 argument got %d\n", __PRETTY_FUNCTION__, argnum);
    return 0;
  }  
if (0 == lua_istable(L, -1))
{
    out_log("No array found");
    return 0;
}
int32_t a_size = lua_rawlen(L, -1);
uint8_t *buf = calloc(1, a_size);
for (int i=1;;i++)
{    
    lua_rawgeti(L,-1, i);
    if (lua_isnil(L,-1)) 
        break;
    buf[i] = lua_tonumber(L,-1);
    lua_pop(L, 1);
}
set_popup_memory(memory_popup, 0, buf, a_size);
free(buf);
  return 0;  
}
pugnator
  • 665
  • 10
  • 27
  • 1
    Please include the C code in question. And ideally the lua code calling it as well. – Etan Reisner Sep 19 '14 at 18:40
  • Sorry, fixed the description – pugnator Sep 19 '14 at 18:49
  • 1
    And what happens exactly when you run that? (Also, you have a_size so why are you looping until `nil`?) (And, unless you have a reason to care, ignoring arguments beyond the ones you expect/require is often a lua design pattern.) Also what is `luactx` in that `lua_pop` call? (I'm assuming a typo?) – Etan Reisner Sep 19 '14 at 19:16
  • I just learning how to use arrays with Lua/C. luactx is just lua_State*, but a global one. L passing to function is in real the same variable. But it is a typo, yes. If there are any other function calls after set_memory_popup(array), the won't be executed. At the same moment, Lua is not crashed - I can call another functions using the same lua_State* – pugnator Sep 20 '14 at 04:53
  • Other C functions called after `set_memory_popup` in that function will not execute? But control returns to lua anyway? Are you sharing lua states between C threads? – Etan Reisner Sep 21 '14 at 01:31
  • Yes, control returns to Lua. I do not use threading, lua_State is a global variable – pugnator Sep 21 '14 at 09:07
  • I don't really see how that's possible unless `set_popup_memory` is doing odd things or jumping or something. Can you return values from that lua function if you try? – Etan Reisner Sep 21 '14 at 19:57
  • I will rewrite that part completely and hope it will help. Seems like issue is really of "magic" type – pugnator Sep 22 '14 at 06:12

1 Answers1

2

I doubt that someone can actually diagnose the problem in question without full example, but here is idiomatic way to handle Lua-to-C calls and some comments on the code itself:

static int // not int32_t
lua_set_popup_memory(lua_State *L)
{
    luaL_checktype(L, 1, LUA_TTABLE);
    // let alone excessive arguments (idiomatic), or do:
    lua_settop(L, 1);

    int a_size = lua_rawlen(L, 1); // absolute indexing for arguments
    uint8_t *buf = malloc((size_t)a_size);

    for (int i = 1; i <= a_size; i++) {
        lua_pushinteger(L, i);
        lua_gettable(L, 1); // always give a chance to metamethods
        // OTOH, metamethods are already broken here with lua_rawlen()
        // if you are on 5.2, use lua_len()

        if (lua_isnil(L, -1)) { // relative indexing for "locals"
            a_size = i-1; // fix actual size (e.g. 4th nil means a_size==3)
            break;
        }

        if (!lua_isnumber(L, -1)) // optional check
            return luaL_error(L, "item %d invalid (number required, got %s)",
                              i, luaL_typename(L, -1));

        lua_Integer b = lua_tointeger(L, -1);

        if (b < 0 || b > UINT8_MAX) // optional
            return luaL_error(L, "item %d out of range", i);

        buf[i-1] = b; // Lua is 1-based, C is 0-based
        lua_pop(L, 1);
    }

    set_popup_memory(memory_popup, 0, buf, a_size);
    free(buf);

    return 0;
}

Please note that lua_CFunction is defined as int (*)(lua_State *), so return type of int32_t may (and most likely will) cause problems on non-32-bit platforms. Also, original code is probably overflowing buf[i], because C indexes start with zero, not 1. And there is one more obvious issue: lua_rawlen() may return the index greater than loop counts to (e.g. array with nil-holes), causing unneeded zeroes being passed to set_popup_memory (assuming priority of first-nil method over table length).

Not sure about out_error, the use of Lua errors may give cleaner diagnostics, especially when entry point was called with lua_pcall's traceback argument.

This code snippet was not actually tested.

user3125367
  • 2,920
  • 1
  • 17
  • 17