这是我的代码。我想将数据从一个内存区域复制到另一个内存区域。我知道这段代码不会检查数据的重叠,但我认为它不会影响指针的值
Ptr
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 %d\n", Ptr, &A[0]);
MemCopy2((uint8_t*)&A, (uint8_t*)Ptr, sizeof(A));
printf("%d %d\n", Ptr, &A[0]);
return 0;
}
我在执行函数之前和之后打印f
MemCopy2
,结果是
6487570 6487568
6444664 6487568
这意味着指针
Ptr
的值已经改变了
还是这段代码,如果我在
int i=6;
之前添加像A[2]
这样的局部变量,现在的结果是
6487554 6487552
6487554 6487552
这意味着指针
Ptr
的值保持不变,
任何人都知道为什么会发生这种情况
我认为这是因为堆栈和取消堆栈将局部变量存储在寄存器中,类似的东西。
这是最小的例子:
#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;
}
输出为:
0x7ffeaf38ae82
0x7ffeaf385678
问题在于您将
sizeof(A)
字节复制到 A
的正偏移量中,这将导致缓冲区溢出。这是未定义的行为,我们的系统恰好会覆盖Ptr
。
修复方法是使用写入偏移较少的数据:
#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 };
size_t offset = 1;
uint32_t *Ptr = (uint32_t *) ((uint16_t *) &A + offset);
printf("%p\n", Ptr);
MemCopy2((uint8_t*)&A, (uint8_t*)Ptr, sizeof(A) - sizeof(uint16_t) * offset);
printf("%p\n", Ptr);
return 0;
}
在非对齐边界访问阵列
A
将导致某些平台上的总线故障。