Jump to content
  • Advertisement
Sign in to follow this  
golopart

Rules of Access Violations across modules.

This topic is 5034 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a win32 MessageBox macro that when expanded creates memory for a string in the code segment of my loaded win32 exe. The reason it's in the code segment is that it's convenient for development purposes, allowing me to just write the string in the code editor where I call the message macro. If this were done in C++, the compiler would most likely relocate this string out of the code segment and into the global data segment or onto the stack. Anyway, after the memory is made (note this is done at assemble time, so they're just static memory strings, that happen to be in the code segment), I can call the MessageBoxA function loaded from the module: user32.dll (do a dumpbin on it). But before that I of course have to jump passed the string memory to continue execution I call it like this: // code execution (pseudo code) goto end_str1; string1: "This is the Message" title1: "this is the title" end_str1: MessageBoxA(NULL, string1, title1, MB_OK);
      hwnd    msg    title   type 
This code works; there are not access violations caught and reported and no program crashes as a result. However, if I want to do something similar, with _itoa loaded from msvcrt.dll (the MSVC CRT dll; haven't tried crtdll.dll yet, though...) the code looks like:
goto end_str2
string2: "                " // 11 bytes or more of empty memory log10(2^32) + 1 for \0-termination
itoa(some_number, string2, 10)
      number     [out]buf  base
then I get the old Windows "Access Violation Error; would you like to report this: no thanks; Technical details?: yes; Okay, the access violation occured at a memory location in MSVCRT.DLL etc." And upon switching the string to the data section, the code works without the access violation. So my question is, what's the difference between MSVCRT.DLL and USER32.DLL when they're loaded that causes them to act differently? I assure you that it is what's happening, because I've tried large enough memory allocations with the same result. I'm going to try this with another crt library: crtdll.dll; Maybe it's just with msvcrt.dll. But I have spent over an hour looking for errors in my code because of it, so it must have a reason or I will go insane. Thank you.

Share this post


Link to post
Share on other sites
Advertisement
The same thing happens with crtdll.dll. Maybe I'm missing something. I know: don't put data next to code, but besides that. ;P

Edit: I just though of something:
MessageBoxA: doesn't attempt to write to memory location.
_itoa: DOES write to memory location.

Could that be it? If so, I take my hat off to my cpu for being so capable.

Share this post


Link to post
Share on other sites
MSVCRT.DLL is the C run-time. That's where the C standard library functions are implemented. itoa() (which is a non-standard function, always remember that), lives there.

USER32.DLL is the Win32 API library, where the userland functions (like MessageBox()) live.

The access violation is due to the fact that itoa() writes, possibly beyond the end of the array (in spite of your indication of the size of the array, we'd need more information to debug that), while MessageBox() just reads up to the '\0', never overflowing the bounds.

Share this post


Link to post
Share on other sites
But how could itoa practically write out-of-bounds? If the buffer has a size, you would expect nothing to temporarily write over the memory because if it had to, temporarily, it would just make it's own local variable right? This isn't the code that's buggy, but here's a solution for me for putting the string on the stack instead:

; *** DEBUG ***
%define num_str ebx ; passed ebp
%define stack_num_str ebp+4
jmp .end_str1
.str1: db "Debug: Numbers",0
.end_str1:
sub esp, 12 ; allocate 11 bytes on stack: (int)log10(2^32) (+1 for null)
; + 1 to be multiple of 4
push ebp
push ebx
mov ebp, esp ; make stack frame
lea ebx, [stack_num_str]
push dword 10
push num_str
push dword IDirectDrawVtbl.SetCooperativeLevel
call [itoa]
add esp, 12
push dword MB_OK
push .str1
push num_str
push dword 0
call [MessageBox]
pop ebx
pop ebp
add esp, 12
%undef num_str
%undef stack_num_str

Put in Message macro and i'm done. I'm still questioning the access violation though. So what I was saying is maybe it's caused just by attempting to write to a memory location outside of it's segment (?) or just range of absolute memory.

Share this post


Link to post
Share on other sites
Found source code to _itoa: (MSVC)

static void __cdecl xtoa (
unsigned long val,
char *buf,
unsigned radix,
int is_neg
)
{
char *p; /* pointer to traverse string */
char *firstdig; /* pointer to first digit */
char temp; /* temp char */
unsigned digval; /* value of digit */

p = buf;

if (is_neg) {
/* negative, so output '-' and negate */
*p++ = '-';
val = (unsigned long)(-(long)val);
}

firstdig = p; /* save pointer to first digit */

do {
digval = (unsigned) (val % radix);
val /= radix; /* get next digit */

/* convert to ascii and store */
if (digval > 9)
*p++ = (char) (digval - 10 + 'a'); /* a letter */
else
*p++ = (char) (digval + '0'); /* a digit */
} while (val > 0);

/* We now have the digit of the number in the buffer, but in reverse
order. Thus we reverse them now. */


*p-- = '\0'; /* terminate string; p points to last digit */

do {
temp = *p;
*p = *firstdig;
*firstdig = temp; /* swap *p and *firstdig */
--p;
++firstdig; /* advance to next two digits */
} while (firstdig < p); /* repeat until halfway */
}

/* Actual functions just call conversion helper with neg flag set correctly,
and return pointer to buffer. */


char * __cdecl _itoa (
int val,
char *buf,
int radix
)
{
if (radix == 10 && val < 0)
xtoa((unsigned long)val, buf, radix, 1);
else
xtoa((unsigned long)(unsigned int)val, buf, radix, 0);
return buf;
}




Edit: AFAICT, they don't write past the buffer. So maybe it's just writing to the location? I'll make a dll real quick...

Share this post


Link to post
Share on other sites
LOL, just commenting on the code: You could do that without a seperate reverse_string, and this could be optimized in C:

digval = (unsigned) (val % radix);
val /= radix; /* get next digit */

Share this post


Link to post
Share on other sites
Quote:
Original post by golopart
So what I was saying is maybe it's caused just by attempting to write to a memory location outside of it's segment (?) or just range of absolute memory.


Yes, that's what an access violation is.

Share this post


Link to post
Share on other sites
Now I'm confused...
simple dll:

; source: testdll.asm
; binary: testdll.dll
; assemble with: nasmw -fobj testdll.asm
; link with: alink -oPE -dll testdll.obj

; export funcs
global write_to_buf
export write_to_buf

segment code public use32
..start: ; dll entry point
mov eax, 1
retn 12

%define buf_p esp+4
%define buf ebx
;--------------------------------------------------------------------------------
; Proc: write_to_buf
; C proto: void __cdecl write_to_buf(char* buf)
; Args: buf length must be atleast 4 bytes
write_to_buf:
push ebx
mov ebx, dword [buf_p]
mov [buf], byte 'h'
mov [buf+1], byte 'e'
mov [buf+2], byte 'y'
mov [buf+3], byte 0
ret
pop ebx
%undef buf
%undef buf_p




simple dll importing app:

; source: testdlltest.asm
; binary: testdlltest.exe
; assemble with: nasmw -fobj testdlltest.asm
; link with: alink -oPE testdlltest.obj

; import funcs
import write_to_buf testdll.dll
extern write_to_buf
; output
import MessageBoxA user32.dll
extern MessageBoxA
%define MessageBox MessageBoxA
%define MB_OK 0

segment code public use32
..start:
push string
call [write_to_buf]
add esp, 4
push dword MB_OK
push title
push string
push dword 0
call [MessageBox]
mov eax, 0
ret

segment data public
title db "Message Title",0
string resb 5



In an attempt to NOT make an access violation, I put the string memory in the data segment as I would with _itoa, I call write_to_buf on it, and it causes an access violation... ??? Why? How do you write a dll to not cause one like this, if there's nothing wrong with my code that is...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!