Memory And Pointer Troubles (mallocing Bytes !/4)


Uprising

Member
Joined
Mar 6, 2006
Messages
110
Website
Visit site
Hey all, think I am getting a bit out of my depth here but I am struggling to understand the reason why the code below does not work correctly -

What I am trying to do is
1. Allocate a certain amount of bytes + (amount of bytes needed for a list) at the same time so I can access either one easily using pointer arithmetic.

2. Arrange a list pointer to +bytes of the memory address returned by malloc and set the values of the list.

3. Do something with remaining memory up to bytes, from the head address returned by malloc.

Here is the code that should compile as it is -
CODE

#include <stdio.h>
#include <stdlib.h>

struct list
{
int info;
void *data;
struct list *next;
struct list *previous;
};

int main(int argc,char *argv[])
{
int x = 0;
unsigned int bytes = 31;
void *memory = NULL;
char *charPointer = NULL;
struct list *listPointer = NULL;

memory = malloc(bytes + sizeof(struct list)); /*Create both the data and the list */
if(memory == NULL)
return 1;

printf("Allocating %d bytes and placing it at %p\n",bytes + sizeof(struct list),memory);

charPointer = memory;

charPointer = charPointer + bytes; /*Find the list*/

listPointer = (struct list*)charPointer;

printf("Assigning value of 'w' to all of the memory just allocated\n");

charPointer = memory;
/*fill the memory*/
for(x = 0; x < bytes + sizeof(struct list); x ++)
{
*(charPointer + x) = 'w';
printf("[%d]%p: value = %c\n",x,charPointer + x,*(charPointer + x));
if(*(charPointer + x) != 'w')
{
printf("Test failed.\n");
x = bytes + sizeof(struct list);
}
}

/*Try and access memory using list pointer*/
printf("Assigning value of 100 to listPointer->info which is at location %p\n",&listPointer->info);
listPointer->info = 100;
printf("list->info now = %d\n",listPointer->info);

if(listPointer->info != 100)
printf("Test failed.\n");

printf("Assigning value of %p to listPointer->data which is at location %p\n",memory,&listPointer->data);
listPointer->data = memory;
printf("list->data now = %p\n",listPointer->data);

if(listPointer->data != memory)
printf("Test failed.\n");

free(memory);
return 0;
}



This seems to work fine on my laptop and all the values are correct. On the gp2x however I cannot get the list pointer to assign correct values if the number of bytes is not divisible by 4. I am guessing this has something to do with memory alignment, since ARM memory allocation is different to x86?

Here is the output of the code above on my gp2x using telnet -
CODE

Allocating 47 bytes and placing it at 0x10a40
Assigning value of 'w' to all of the memory just allocated
[0]0x10a40: value = w
[1]0x10a41: value = w
[2]0x10a42: value = w
[3]0x10a43: value = w
[4]0x10a44: value = w
[5]0x10a45: value = w
[6]0x10a46: value = w
[7]0x10a47: value = w
[8]0x10a48: value = w
[9]0x10a49: value = w
[10]0x10a4a: value = w
[11]0x10a4b: value = w
[12]0x10a4c: value = w
[13]0x10a4d: value = w
[14]0x10a4e: value = w
[15]0x10a4f: value = w
[16]0x10a50: value = w
[17]0x10a51: value = w
[18]0x10a52: value = w
[19]0x10a53: value = w
[20]0x10a54: value = w
[21]0x10a55: value = w
[22]0x10a56: value = w
[23]0x10a57: value = w
[24]0x10a58: value = w
[25]0x10a59: value = w
[26]0x10a5a: value = w
[27]0x10a5b: value = w
[28]0x10a5c: value = w
[29]0x10a5d: value = w
[30]0x10a5e: value = w
[31]0x10a5f: value = w
[32]0x10a60: value = w
[33]0x10a61: value = w
[34]0x10a62: value = w
[35]0x10a63: value = w
[36]0x10a64: value = w
[37]0x10a65: value = w
[38]0x10a66: value = w
[39]0x10a67: value = w
[40]0x10a68: value = w
[41]0x10a69: value = w
[42]0x10a6a: value = w
[43]0x10a6b: value = w
[44]0x10a6c: value = w
[45]0x10a6d: value = w
[46]0x10a6e: value = w
Assigning value of 100 to listPointer->info which is at location 0x10a5f
list->info now = 25600
Test failed.
Assigning value of 0x10a40 to listPointer->data which is at location 0x10a63
list->data now = 0x10a4000
Test failed.



The strange thing is I can change the values of all the memory fine using a char pointer (all values are set to w as shown) but when using the listPointer it seems to be at the correct address but unable to assign a value. Does anyone know why this is?

I wonder if I am not typecasting the pointer correctly or something.

It seems to work fine if bytes is divisible by 4, so I am just padding (a max of 3 since it is a 32bit processor) bytes if it is not divisible by 4 in my actual project.

Thanks for reading, sorry if anything is a bit vague.
 
The first element in your structure is an int, and therefore must be aligned on a 4-byte boundary (same with data, next and previous, which are also mis-aligned). malloc returns a suitably aligned pointer, but you then mess up this allocation by placing your data at the front of it. It will work if your data size is aligned by 4 as you state.

The best way to cure the problem is having your list memory first, and data afterwards, rather than the other way around. This way, all your variables will have the proper alignment. (If you try and alter the alignment in the structure by placing a char for example, the compiler will automatically insert invisible items to regain alignment suitable for the next item).
 
Squidge gave you the right answer. I will just add a comment:

Uprising said:
This seems to work fine on my laptop and all the values are correct. On the gp2x however I cannot get the list pointer to assign correct values if the number of bytes is not divisible by 4. I am guessing this has something to do with memory alignment, since ARM memory allocation is different to x86?

Your laptop is probably based on x86 which doesn't care about alignment (except performance wise). On ARM you should align your data based on its size : if your data is 16 bit, the address must be dividable by 2, if it's 32 bit, dividable by 4.

Note pointers are 32 bit data, so in your code with bytes = 31 your listPointer is not aligned to a multiple of 4, so any access through it will be unaligned.

On a more technical side, the gp32x kernel can be configured to handle unaligned load and stores by doing something like this (IIRC):
CODE
echo 3 > /proc/cpu/alignment

But you'd rather correct your code and forget your x86 assumptions :p
 
Last edited by a moderator:
Laurent said:
Your laptop is probably based on x86 which doesn't care about alignment (except performance wise). On ARM you should align your data based on its size : if your data is 16 bit, the address must be dividable by 2, if it's 32 bit, dividable by 4.

Note pointers are 32 bit data, so in your code with bytes = 31 your listPointer is not aligned to a multiple of 4, so any access through it will be unaligned.
Ah, thanks for stating this! I didnt really expect I would find much of a difference when coding on the gp2x/arm to coding on the pc/x86, but its good because I have learned more about how malloc works (I hope :D ).

QUOTE

On a more technical side, the gp32x kernel can be configured to handle unaligned load and stores by doing something like this (IIRC):
CODE
echo 3 > /proc/cpu/alignment

But you'd rather correct your code and forget your x86 assumptions :p

Hehe yeah :) , thanks for the option though.

QUOTE

The first element in your structure is an int, and therefore must be aligned on a 4-byte boundary (same with data, next and previous, which are also mis-aligned). malloc returns a suitably aligned pointer, but you then mess up this allocation by placing your data at the front of it. It will work if your data size is aligned by 4 as you state.

The best way to cure the problem is having your list memory first, and data afterwards, rather than the other way around. This way, all your variables will have the proper alignment. (If you try and alter the alignment in the structure by placing a char for example, the compiler will automatically insert invisible items to regain alignment suitable for the next item).


Thanks for clarifying Squidge and also for the solution, I think I understand it now. :)

CODE

Here is a block of 17 bytes of memory returned from malloc, 1 byte is to be used as data and the other 16
bytes as list.

' :(x): ' = the memory address
' - ' = a byte
' | ' = alignment of memory

Unaligned memory due to list being last -

(0): - | - - - :(4): - | - - - :(8): - | - - - :(12): - | - - - :(16): - | :(17)

Aligned memory due to list being first -

(0): - - - - | :(4): - - - - |:(8): - - - - |:(12): - - - - |:(16): - | :(17)
 
Last edited by a moderator:
Back
Top