Here is my code. I want to copy data from a memory region to other memory region. To avoid overlap data i make the order copy, not from the lsb , but from msb of the array like the picture order of copy
#include<stdio.h>
#include<stdint.h>
void MemCopy2(uint8_t * Src, uint8_t * Dest, uint32_t Len)
{
uint32_t count;
for (count = Len; count > 0; count--)
{
Dest[count-1] = Src[count-1];
}
}
int main()
{
uint32_t A[2] = { 0xABCD1234, 0x567890AB };
uint32_t * Ptr = (uint16_t*)&A + 1; // CD
printf("%d \n", Ptr);
MemCopy2((uint8_t*)&A, (uint8_t*)Ptr, sizeof(A));
printf("%d \n", Ptr);
return 0;
}
I printf before and after executing the function MemCopy2
, the result is
6487570
6444664
which means that the value of pointer Ptr
has been changed
Still this code, if I add a local variable like int i=6;
before initialize array A[2]
in main() , now the result is
6487554
6487554
which means that the value of pointer Ptr
remain,
Anyone know why this happen
I think it because of stacking and unstacking to store local variable in register, something like that.
Here is the minimal example that includes the missing headers, use %p
to print addresses, and resolve warnings:
#include <stdint.h>
#include <stdio.h>
void MemCopy2(const uint8_t *Src, uint8_t *Dest, uint32_t Len) {
for (uint32_t count = Len; count > 0; count--)
Dest[count-1] = Src[count-1];
}
int main(void) {
uint32_t A[2] = { 0xABCD1234, 0x567890AB };
uint32_t *Ptr = (uint32_t *) ((uint16_t *) &A + 1);
printf("%p\n", Ptr);
MemCopy2((uint8_t*)&A, (uint8_t*)Ptr, sizeof(A));
printf("%p\n", Ptr);
return 0;
}
and the output is:
0x7ffeaf38ae82
0x7ffeaf385678
The problem is that you copy sizeof(A)
bytes into a non-zero offset of A
which will cause a buffer overflow. As the offset 1
is sizeof(uint16_t) * 1
i.e. 2 bytes, but you only trail by 1 byte in MemCopy2()
. This is undefined behavior and our systems it happens to overwrite Ptr
. The technical fix is to 2 byte less, i.e.:
Accessing your array uin32_t A[]
via a uint16_t *
is undefined behavior per 6.3.2.3p7. On some platforms it will cause a bus violation and crash the program. On others like amd64 it's a performance overhead.
#include <stdint.h>
#include <stdio.h>
#define OFFSET 1
void MemCopy2(const uint8_t * Src, uint8_t * Dest, uint32_t Len) {
for (uint32_t count = Len; count > 0; count--)
Dest[count-OFFSET] = Src[count-OFFSET];
}
int main(void) {
uint32_t A[2] = { 0xABCD1234, 0x567890AB };
uint32_t *Ptr = (uint32_t *) ((char *) A + sizeof(uint16_t) * OFFSET);
printf("%p\n", Ptr);
MemCopy2((uint8_t*)&A, (uint8_t*)Ptr, sizeof(A) - sizeof(uint16_t) * OFFSET);
printf("%p\n", Ptr);
return 0;
}
The interface is clunky, though, maybe move the offset business into MemCopy2()
to avoid coupling of OFFSET
in both MemCopy2()
and main()
?