0

I am currently making a mod for GTA San Andreas via DLL Injection. I have the function shown below to show a player an in-game message box.

void showDialog (int send, int dialogID, int typedialog, char * caption,
    const char * text, char * button1, char * button2)
{ 
    uint32_t func = pSAMP + SAMP_DIALOG_SHOW; //pSAMP = DWORD base of samp.dll
    uint32_t data = pSAMP + SAMP_DIALOG_INFO_OFFSET; 

    __asm mov eax, dword ptr [data]
    __asm mov ecx, dword ptr [eax]
    __asm push send 
    __asm push button2
    __asm push button1
    __asm push text
    __asm push caption
    __asm push typedialog
    __asm push dialogID
    __asm call func
} 

The text contained in the message box is dynamically created once on starting the game by starting with an empty global std::string (for example, std::string string;) and using string::append() to create the desired string. The string is not edited (purposely) anywhere in the program after it's initial creation.

When a key is pressed, the showDialog() function is called:

 showDialog(0, 2 , 2, "MYTITLE", string.c_str(), "OK", "CLOSE");

Roughly 50% of the time, this code will run perfectly, showing the required text, and usually if the in-game dialog shows correctly the first time it is called, it will work perfectly every time it is called thereafter.

The remaining 50%, when this showDialog() function is called, the game will freeze immediately without the dialog showing. No error report or registers are given and the game freezes at the current frame. The only way to exit the game is by signing out of Windows as no other process windows are usable. Sometimes there will be a ~5 second delay between pressing the key and the game freezing without the message box being shown in-game.

If showDialog() is called by specifying a static string while calling the function, e.g:

showDialog(0, 2 , 2, "MYTITLE", "MY TEXT", "OK", "CLOSE");

it will run correctly without freezing ever. I assume this rules out the possibility of my showDialog() function being incorrect.

My question is, does the freezing sound like it is being caused by a memory corruption linked somehow to my use of char*, std::string, .c_str(), etc...? Does anyone have a suggestion as to how I can make this code work without freezing the game?

Deduplicator
  • 43,322
  • 6
  • 62
  • 109
R G
  • 21
  • 1
  • is this c++ formatting? – Samer Sep 26 '14 at 21:18
  • yes, this is C++. sorry I'm new to Stack Overflow – R G Sep 26 '14 at 23:05
  • What happens if you give it a pointer to a character array instead of std::string or literal string? – iwolf Sep 27 '14 at 00:53
  • @iwolf in the examples, I did give it a char*, via string::c_str() which returns a "const char*" – R G Sep 27 '14 at 12:02
  • You have to give it a char* no matter what. The one from giving it a string literal is pointed at the executable's string literal table, the one returned by a standard string is pointed at the heap. I'm curious what happens when you give it one that points to the stack. – iwolf Sep 27 '14 at 21:36
  • @iwolf as far as I can tell, using " char *str = "mystring"; " works fine, but I require my string to be dynamically created on each run of the game so using a string literal isn't an option. – R G Sep 27 '14 at 23:28
  • @RG: In the case of " char *str = "mystring"; " (declared locally in the function) the pointer is on the stack, but it still references memory in the program's string literal table. My question was about what happens when the string data itself is on the stack ("char tempString[size];" or alloca, if it's supported by your compiler and you know what you're doing). Though, I'm losing hope that knowing the answer to this will help very much, unless the halt you're seeing is due to heap corruption (which could manifest intermittently in a variety of ways). – iwolf Sep 29 '14 at 18:18
  • @iwolf Thanks for the help so far! I used the following code which worked sometimes and other times caused the game to halt as previously described: `int length = string.length(); char *buffer; buffer = (char*)alloca(length + 1); buffer = strdup(string.c_str()); showDialog(0, 2 , 2, "MYTITLE", buffer, "OK", "CLOSE"); free(buffer);` – R G Sep 29 '14 at 19:48
  • strdup doesn't do what you want it to in this sample. It allocates new memory on the heap (via malloc) and copies the string to there. You're then reassigning the buffer pointer to point to the newly allocated string. Use something like sprintf or strcpy to populate the buffer that alloca makes on the stack. Then the call to free should go away. Allocations from alloca free themselves when going out of scope. It's only necessary in the above sample because it ends up freeing the memory from strdup's call to malloc, which "buffer" ends up pointing to. – iwolf Sep 29 '14 at 21:06
  • Also, try populating from both the std string and a literal, just to see what happens: sprintf(buffer, "%s", string.c_str()); and sprintf(buffer, "%s", "mystring") – iwolf Sep 29 '14 at 21:09
  • Using DLL injection, you may need to be extra conscious and intentional with your use of heap memory. Annoying things can happen. http://stackoverflow.com/questions/10820114/do-statically-linked-dlls-use-a-different-heap-than-the-main-program – iwolf Sep 29 '14 at 22:13

0 Answers0