Reputation: 1263
I'm currently writing code for a size-coding entry. I say this because it causes some restrictions as to what I can do. So if you read the code and ask yourself e.g. "why use wsprintf, not just sprintf", it has a reason. No CRT can be linked. Only WinAPI libs are allowed. The objective is to generate the least amount of assembly instructions going into the linker. With that said, onto the problem.
This macro:
#define GLExt(a) a(wglGetProcAddress(#a))
is used as a shorthand to call OpenGL extension functions previously declared. This problem only concerns one function, which has this signature:
extern "C" {
typedef void(__stdcall*glShaderSource)
(unsigned shader, int count, char** string, const int *length);
}
I load a string constant as a template and use wsprintf to fill in the values. In this small example of the issue it's simply the elapsed time in ms. The following code works fine. I've inserted the generated assembly above the respective LOCs:
const auto starttime = GetTickCount();
do {
char *pflog;
//~ call DWORD PTR __imp__GetTickCount@0
//~ sub eax, DWORD PTR _starttime$1$[esp+24]
//~ push eax
//~ push OFFSET <text from data>
//~ push DWORD PTR _pflog$1[esp+32]
//~ call DWORD PTR __imp__wsprintfA
wsprintf(pflog, "void main(void){int foo=%d;}", GetTickCount() - starttime);
//~ mov eax, DWORD PTR _pflog$1[esp+36]
//~ add esp, 12 ; 0000000cH
//~ mov DWORD PTR _blorg$2[esp+24], eax
char *blorg = pflog;
//~ lea eax, DWORD PTR _blorg$2[esp+24]
//~ push 0
//~ push eax
//~ push 1
//~ push ebp
//~ push OFFSET <glShaderSource>
//~ call esi
//~ call eax
GLExt(glShaderSource)(s, 1, &blorg, 0);
}
However, if I try to use pflog
directly, the code compiles without complaint but crashes on the first call to glShaderSource
. Here's is the annotated version of that:
const auto starttime = GetTickCount();
do {
char *pflog;
//~ call DWORD PTR __imp__GetTickCount@0
//~ sub eax, DWORD PTR _starttime$1$[esp+24]
//~ push eax
//~ push OFFSET <text from data>
//~ push DWORD PTR _pflog$1[esp+32]
//~ call DWORD PTR __imp__wsprintfA
//~ add esp, 12
wsprintf(pflog, "void main(void){int foo=%d;}", GetTickCount() - starttime);
//~ lea eax, DWORD PTR _pflog$1[esp+24]
//~ push 0
//~ push eax
//~ push 1
//~ push ebp
//~ push OFFSET <glShaderSource>
//~ call esi
//~ call eax
GLExt(glShaderSource)(s, 1, &pflog, 0);
} while (1);
I'm a bit stumped. As far as I can tell the variables are accessed in the same way at the same offsets in both versions (apart from the copy). Why is one version unexpectedly crashing, or rather: Why does the temporary variable make a difference?
Upvotes: 0
Views: 78
Reputation: 77295
char *pflog;
wsprintf(pflog, "void main(void){int foo=%d;}", GetTickCount() - starttime);
Whatever happens after this is doomed to fail. Unfortunately, it did not fail right in the second line. You are writing to random memory you do not own. You cannot just write a string to an uninitialized character pointer. You need to allocate the memory behind it, by either using new
(preferred in C++) or any of the alloc
functions.
Upvotes: 1