Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7741579
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 1, 20262026-06-01T09:03:51+00:00 2026-06-01T09:03:51+00:00

I am writing an iOS library to embed Lua in games and have encountered

  • 0

I am writing an iOS library to embed Lua in games and have encountered a problem regarding userdata. I want users to be able to treat my library objects as normal tables (in Lua scripts) to set attributes and for these attributes to be available to the base objects in the library. For instances a user script may have

line = display.newLine
line.width = 3

Then the width field should be accessible from within the library (Objective C/C) code.

I have this working, sort of, but after running for a few seconds I get an EXC_BAD_ACCESS error, so obviously I am accessing a freed object or have some other type of memory corruption, but I can’t seem to figure out why.

I have trimmed down my code to just one example to reproduce the error. First I have a base Objective C object that implements the library functionality. The header is shown below:

#import "lua.h"
#include "lualib.h"
#include "lauxlib.h"


@interface GeminiLine : NSObject {
    int selfRef;
    int propertyTableRef;
    lua_State *L;
}

@property (nonatomic) int propertyTableRef;

-(id)initWithLuaState:(lua_State *)luaStat;
-(double)getDoubleForKey:(const char*) key withDefault:(double)dflt;

@end

This class keeps a reference to the lua_State object and integer Lua references to it’s corresponding Lua userdata and uservalue (the tables associated with the userdata). The reference propertyTableRef is used to access the object attributes (uservalue table).

The implementation is given below:

#import "GeminiLine.h"

@implementation GeminiLine

@synthesize propertyTableRef;

-(id)initWithLuaState:(lua_State *)luaState {
    self = [super init];
    if (self) {
        L = luaState;
    }

    return self;

}

-(double)getDoubleForKey:(const char*) key withDefault:(double)dflt {

    lua_rawgeti(L, LUA_REGISTRYINDEX, propertyTableRef);
    //lua_pushstring(L, key);
    //lua_gettable(L, -2);
    lua_getfield(L, -1, key);
    if (lua_isnil(L, -1)) {
        return dflt;
    }
    return lua_tonumber(L, -1);
}

-(void)dealloc {
    luaL_unref(L, LUA_REGISTRYINDEX, propertyTableRef);
    [super dealloc];
}

@end

The only non-lifecycle method here is the getDoubleForKey method, which accesses the Lua uservalue associated with the userdata for the object.

The C code to bind the object to Lua is given here:

///////////// lines ///////////////////////////
static int newLine(lua_State *L){
    NSLog(@"Creating new line...");
    GeminiLine *line = [[GeminiLine alloc] initWithLuaState:L];
    GeminiLine **lLine = (GeminiLine **)lua_newuserdata(L, sizeof(GeminiLine *)); 
    *lLine = line;

    [Gemini shared].line = line;

    luaL_getmetatable(L, GEMINI_LINE_LUA_KEY);
    lua_setmetatable(L, -2);

    // append a lua table to this user data to allow the user to store values in it
    lua_newtable(L);
    lua_pushvalue(L, -1); // make a copy of the table becaue the next line pops the top value
    // store a reference to this table so we can access it later
    line.propertyTableRef = luaL_ref(L, LUA_REGISTRYINDEX);
    // set the table as the user value for the Lua object
    lua_setuservalue(L, -2);

    NSLog(@"New line created.");

    return 1;
}

static int lineGC (lua_State *L){
    NSLog(@"lineGC called");
    GeminiLine  **line = (GeminiLine **)luaL_checkudata(L, 1, GEMINI_LINE_LUA_KEY);

    [*line release];

    return 0;
}

static int lineIndex( lua_State* L )
{
    NSLog(@"Calling lineIndex()");
    /* object, key */
    /* first check the environment */ 
    lua_getuservalue( L, -2 );
    if(lua_isnil(L,-1)){
        NSLog(@"user value for user data is nil");
    }
    lua_pushvalue( L, -2 );

    lua_rawget( L, -2 );
    if( lua_isnoneornil( L, -1 ) == 0 )
    {
        return 1;
    }

    lua_pop( L, 2 );

    /* second check the metatable */    
    lua_getmetatable( L, -2 );
    lua_pushvalue( L, -2 );
    lua_rawget( L, -2 );

    /* nil or otherwise, we return 1 here */
    return 1;
}

// this function gets called with the table on the bottom of the stack, the index to assign to next,
// and the value to be assigned on top
static int lineNewIndex( lua_State* L )
    {
    NSLog(@"Calling lineNewIndex()");
    int top = lua_gettop(L);
    NSLog(@"stack has %d values", top);
    lua_getuservalue( L, -3 ); 
    /* object, key, value */
    lua_pushvalue(L, -3);
    lua_pushvalue(L,-3);
    lua_rawset( L, -3 );

    NSLog(@"Finished lineNewIndex()");

    return 0;
}


// the mappings for the library functions
static const struct luaL_Reg displayLib_f [] = {
    {"newLine", newLine},
    {NULL, NULL}
};

// mappings for the line methods
static const struct luaL_Reg line_m [] = {
    {"__gc", lineGC},
    {"__index", lineIndex},
    {"__newindex", lineNewIndex},
    {NULL, NULL}
};


int luaopen_display_lib (lua_State *L){
    // create meta tables for our various types /////////

    // lines
    luaL_newmetatable(L, GEMINI_LINE_LUA_KEY);
    lua_pushvalue(L, -1);
    luaL_setfuncs(L, line_m, 0);


    /////// finished with metatables ///////////

    // create the table for this library and popuplate it with our functions
    luaL_newlib(L, displayLib_f);

    return 1;
}

The key methods here are newLine and lineNewIndex. In newLine I create the objective C GeminiLine object corresponding to the Lua object and store a pointer to it in Lua userdata. I also store a pointer to the new object in a singleton Gemini object, which is the object that provides the main program with access to executing Lua scripts. This class is given here:

Gemini *singleton = nil;

@interface Gemini () {
@private
    lua_State *L;
}
@end


@implementation Gemini

@synthesize line;

- (id)init
{

    self = [super init];
    if (self) {
        L = luaL_newstate();
        luaL_openlibs(L);

    }

    return self;
}

+(Gemini *)shared {

    if (singleton == nil) {
        singleton = [[Gemini alloc] init];
    }

    return singleton;
}


-(void)execute:(NSString *)filename {
    int err;

lua_settop(L, 0);

    NSString *luaFilePath = [[NSBundle mainBundle] pathForResource:filename ofType:@"lua"];

    setLuaPath(L, [luaFilePath stringByDeletingLastPathComponent]);

    err = luaL_loadfile(L, [luaFilePath cStringUsingEncoding:[NSString defaultCStringEncoding]]);

if (0 != err) {
        luaL_error(L, "cannot compile lua file: %s",
        lua_tostring(L, -1));
        return;
}


    err = lua_pcall(L, 0, 0, 0);
if (0 != err) {
        luaL_error(L, "cannot run lua file: %s",
        lua_tostring(L, -1));
        return;
 }

}
@end

For my test program I have created an application using the single view template. I modified the applicationDidFinishLaunching method on the AppDelegate to call a test script as follows:

-(void) update {

    double width = [[Gemini shared].line getDoubleForKey:"width" withDefault:5.0];
    NSLog(@"width = %f", width);
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]    autorelease];
    // Override point for customization after application launch.

    [[Gemini shared] execute:@"test"];

    timer = [NSTimer scheduledTimerWithTimeInterval:0.01
                                 target:self
                               selector:@selector(update)
                               userInfo:nil
                                repeats:YES];
....

I have also included a timer that fires 100 times per second and an update method as its target. The update method retrieves the attribute set in the lua script, width, and logs it with NSLog.

The test.lua script I am using is given below:

display = require('display')

line = display.newLine()
line.width = 3;

Now when I run this code, it executes correctly for several seconds, printing out the correct message and appropriate line width, but then it fails with an EXC_BAD_ACCESS error on the NSLog(@"width = %f", width); line of the update method. At first I thought maybe the line object was being garbage collected, but the lineGC method would log this and it does not. So I’m convinced the problem is in the way I am using the uservalue of my Lua userdata, either in setup or access.

Can anyone see an error in the way I have implemented this?

EDIT

To confirm that my userdata isn’t being garbage collected, I disabled the GC before even loading the script using lua_gc(L, LUA_GCSTOP, 0);. Still get exactly the same problem.

I forgot to mention earlier that I’m using Lua 5.2.

Turning on every memory debugging flag using “Edit scheme” indicates that the error is happening in the following Lua code base function on the call to setsvalue2s, which is actually a macro:

LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
  StkId t;
  lua_lock(L);
  t = index2addr(L, idx);
  api_checkvalidindex(L, t);
  setsvalue2s(L, L->top, luaS_new(L, k));
  api_incr_top(L);
  luaV_gettable(L, t, L->top - 1, L->top - 1);
  lua_unlock(L);
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-01T09:03:52+00:00Added an answer on June 1, 2026 at 9:03 am

    I’m pretty sure I have the answer to my own question now. The problem is in the getDoubleForKey method:

    -(double)getDoubleForKey:(const char*) key withDefault:(double)dflt {
    
        lua_rawgeti(L, LUA_REGISTRYINDEX, propertyTableRef);
        //lua_pushstring(L, key);
        //lua_gettable(L, -2);
        lua_getfield(L, -1, key);
        if (lua_isnil(L, -1)) {
            return dflt;
        }
        return lua_tonumber(L, -1);
    }
    

    I’m new to Lua and had not realized that I needed to empty the stack after making calls like this. When my library functions are invoked by Lua there is no need, but here I am making the call so Lua does not bail me out.

    I found this out by printing out the stack size at the top of the method and seeing it increasing with every call. Eventually the stack got so big that bad things happened. The solution is to empty out the stack before exiting the method:

    -(double)getDoubleForKey:(const char*) key withDefault:(double)dflt {
    
        lua_rawgeti(L, LUA_REGISTRYINDEX, propertyTableRef);
        lua_getfield(L, -1, key);
        if (lua_isnil(L, -1)) {
            lua_pop(L,2);
            return dflt;
        }
        double rval = lua_tonumber(L, -1);
    
        lua_pop(L, 2);
    
        return rval;
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am writing a library for efficient number processing. I have to support different
I have been writing iOS applications and completed a project with a lot of
I'm currently writing an iOS app and I have many records that I'm writing
I am writing an iOS app and I have one question to make the
I am writing a class library for Mac OS X and iOS to be
Hey, Am writing an iOS application and want to build it so it will
In the iOS app I'm writing, we have an add photo button that's pretty
Im new at writing iOS apps, and have nearly finished writing my first game.
I'm writing an iOS app, and I need to be able to detect if
I'm writing an iOS game that draws many cubes on screen, but I have

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.