Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling GetCurrentTribe(0) can result in a CTD #8

Open
WizzardMaker opened this issue Feb 20, 2021 · 3 comments
Open

Calling GetCurrentTribe(0) can result in a CTD #8

WizzardMaker opened this issue Feb 20, 2021 · 3 comments

Comments

@WizzardMaker
Copy link
Collaborator

When calling GetCurrentTribe(0) every frame, there is a small chance, that S4 crashes.

There is an exception thrown inside the luaD_checkstack() function:

>	S4ModApi.dll!try_cor_exit_process(const unsigned int return_code=1)
 	S4ModApi.dll!exit_or_terminate_process(const unsigned int return_code=1)
 	S4ModApi.dll!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode=_crt_exit_full_cleanup, const _crt_exit_return_mode return_mode=_crt_exit_terminate_process)
 	S4ModApi.dll!exit(int return_code=1)
 	S4ModApi.dll!_lua_error()
 	S4ModApi.dll!_luaD_checkstack()
 	S4ModApi.dll!CSettlers4Api::GetPlayerTribe(unsigned long player=0)

@nyfrk
Copy link
Owner

nyfrk commented Feb 20, 2021

Looks like either an allocation problem or some kind of overflow. Too bad it does not show the exact error message. The responsible source code in the lua lib is this (available online at lua.org):

void luaD_checkstack (int n) {
  struct Stack *S = &L->stack;
  if (S->last-S->top <= n) {
    StkId top = S->top-S->stack;
    int stacksize = (S->last-S->stack)+STACK_UNIT+n;
    luaM_reallocvector(S->stack, stacksize, TObject);
    S->last = S->stack+(stacksize-1);
    S->top = S->stack + top;
    if (stacksize >= STACK_LIMIT) {  /* stack overflow? */
      if (lua_stackedfunction(100) == LUA_NOOBJECT)  /* 100 funcs on stack? */
        lua_error("Lua2C - C2Lua overflow"); /* doesn't look like a rec. loop */
      else
        lua_error("stack size overflow");
    }
  }
}

luaM_reallocvector is just a wrapper for luaM_realloc, which calls the realloc function of bluebytes virtual machine.

void *luaM_realloc (void *block, unsigned long size) {
  size_t s = (size_t)size;
  if (s != size)
    lua_error("memory allocation error: block too big");
  if (size == 0) {
      _s4_free(block);  /* block may be NULL, that is OK for free */ // imported from S4ModApi
    return NULL;
  }
  block = _s4_realloc(block, s); // imported from S4ModApi
  if (block == NULL)
    lua_error("not enough memory");
  return block;
}

Calling a function every frame may simply overload the lua vm. Maybe we should access the game structs ourselfs for simple functions like GetPlayerTribe.

Edit: When you say "every frame", do you mean you call it from inside the frame hook procedure? That should not be allowed as GetPlayerTribe is a game logic operation. All game logic related functions must be called in the tick hook for synchronization purposes.

@WizzardMaker
Copy link
Collaborator Author

I moved the call now in the first round tick and never call it again

Question is, if the error is specific to the GetPlayerTribe function, or every lua funtion.

When you say "every frame", do you mean you call it from inside the frame hook procedure? That should not be allowed as GetPlayerTribe is a game logic operation. All game logic related functions must be called in the tick hook for synchronization purposes.

Oh, of course - yes, I used the tick proc to call GetPlayerTribe

@nyfrk
Copy link
Owner

nyfrk commented Feb 20, 2021

Question is, if the error is specific to the GetPlayerTribe function, or every lua funtion.

For interaction with the lua virtual machine we must use lua_push, lua_callfunction etc. All these functions use luaD_checkstack when called. So I assume that every function implemented in lua is affected.

However most lua functions got an identical C-Function counterpart. Meaning these lua functions just delegate the call back to a C-function. For these functions we could simply skip the interaction with the lua vm and directly call the cfunc. Other functions require a little more conversion before calling the c functions.

For example. Have a look at the implementation of ShowTextMessage. Instead of calling the lua function dbg.stm, I directly call the c function that is used by dbg.stm. Thus not executing any lua code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants