开发者

64bit architecture - character pointer truncated while returning from function

Environment:

Windows x64 bit with 5GB RAM. My binary is a 64bit one built with compiler of version - "Microsoft (R) C/C++ Optimizing Compiler Version 14.00.50727.762 for x64"

Environment setting:

Microsoft suggests to set the below registry key to test 64 bit applications and I have set the same in my box. The problem doesn't occur if i don't set the below registry because the program is placed at a low address. The same registry key is mentioned in the discussion - As a programmer, what do I need to worry about when moving to 64-bit windows?

To force allocations to allocate from higher addresses before lower addresses for testing purposes, specify MEM_TOP_DOWN when calling VirtualAlloc or set the following registry value to 0x100000:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\AllocationPreference

Sample code:

char *alloc_str()
{
    char *temp;
    temp = (char *) malloc(60);
    /* copy some data to temp */
    return temp;
}

main()
{
    char *str;
    str = (char *)alloc_str();
}

Analysis:

malloc returns address 0x000007fffe999b40 which is stored in temp but when the pointer is returned to main(), str gets only the second half - 0xfffffffffe999b40 and I am not able t开发者_JAVA技巧o access the data at that location.


Two points about style, which could help to diagnose this kind of problems. As you use malloc I suppose that it is compiled as a C program. In that case, do not typecast when it is not necessary. Excessive typecasts may suppress the warnings telling you that you have not correctly declared your functions. If there is no prototype and the function definition is in another module then your call str = (char *)alloc_str(); will suppress the warning that the function is used without declaration and the default declaration of C will be used, i.e. all parameter and return value will be considered as int . Same thing with the malloc, if you forgot the right include, your typecast will suppress the warning and the compiler will assume the function returns an int. This might be already the cause of the truncation. Another point, in C, an empty parameter list is declared with (void) not () which has another meaning (unspecified parameters). These are 2 points that differ between C and C++.


The registry setting you refer to selects top-down memory allocation. You state that this setting will "place program in high address space". It won't do that. What this does is force the Windows memory manager to allocate memory from the top of the address space.

What's more since you are running under 64 bit Windows, I fail to see where PAE comes into play. That would be something used on a 32 bit platform.

I would guess that you are compiling a 32 bit app and so inevitably your pointers are 32 bits wide. But that is only a guess due to the lack of information.

In short your question is impossible to answer because you haven't told us what you are doing.


David, thanks for your time and suggestion. The sample program was not working because I had not included stdlib.h in my C file and so the pointer returned by malloc was 32 bit. The problem I faced was with a production code which was bit different from the sample code.

tristopia, Your explanation is absolutely correct. I was facing the same problem.

In my production C files, I was facing the problem as below

a.c

call_test1()
{
 char* temp;
 temp = (char *)test1();
}

b.c

include stdlib.h
char* test1()
{
 char *str;
 test = (char *)malloc(60);
 /* copy some data to test*/
 return str;
}

When str was returned by test1(), the pointer contained 64 bit address (I analyzed the rx registry (which stores the return value of a function) in windbg using "r rx") but when it was assigned to temp, it got truncated to 32 bit address).

The problem was due to

  1. Not including signature of test1() in the a.c file
  2. Typecasting the return value to char *

Modified source

a.c

char * test1();
call_test1()
{
 char* temp;
 temp = test1();
}

b.c

include stdlib.h
char* test1()
{
 char *str;
 test = (char *)malloc(60);
 /* copy some data to test*/
 return str;
}

I got the solution by trial and error but tristopia explained the reason.

64 bit notes

  1. Use %p instead of %lx to print an address of a pointer in 64 bit environmnent.
  2. Include function signature and try to avoid typecasting pointers
  3. On Windows, If you recompile your C/C++ code into a 64-bit EXE or DLL, you must test it with the AllocationPreference registry value set.

To force allocations to allocate from higher addresses before lower addresses for testing purposes, specify MEM_TOP_DOWN when calling VirtualAlloc or set the following registry value to 0x100000:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\AllocationPreference


I would have to ask if you are using the correct compiler settings and linking against the correct C runtime library.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜