C++;memset/memcpy/strcpy实现-检查缓冲区溢出 我在C++中实现了基本的MySt/MeMCPY/STRCPY实现,这很好。但是,如果我要这样做,有没有办法检测缓冲区溢出:
例如:C++;memset/memcpy/strcpy实现-检查缓冲区溢出 我在C++中实现了基本的MySt/MeMCPY/STRCPY实现,这很好。但是,如果我要这样做,有没有办法检测缓冲区溢出:,c++,C++,例如: int main() { char *buf = (char *)calloc(10, sizeof(char)); __strcpy(buf, "Hello World"); // buffer size: 10, copy size: 12 (including '\0') - overflow } 实现(typedef unsigned int UINT): 在程序中无法检测到缓冲区溢出。操作系统正在检测它们。您只能检查代码中的潜在陷阱(if/else、
int main()
{
char *buf = (char *)calloc(10, sizeof(char));
__strcpy(buf, "Hello World");
// buffer size: 10, copy size: 12 (including '\0') - overflow
}
实现(typedef unsigned int UINT
):
在程序中无法检测到缓冲区溢出。操作系统正在检测它们。您只能检查代码中的潜在陷阱(if/else、断言、异常)。或者使用valgrind之类的分析工具 程序中无法检测到缓冲区溢出。操作系统正在检测它们。您只能检查代码中的潜在陷阱(if/else、断言、异常)。或者使用valgrind之类的分析工具 程序中无法检测到缓冲区溢出。操作系统正在检测它们。您只能检查代码中的潜在陷阱(if/else、断言、异常)。或者使用valgrind之类的分析工具 程序中无法检测到缓冲区溢出。操作系统正在检测它们。您只能检查代码中的潜在陷阱(if/else、断言、异常)。或者使用valgrind之类的分析工具 检测缓冲区溢出的更安全的方法是提供自己的
calloc
实现。在返回的块之前和之后提供一些字节填充,将它们设置为已知值(不是0或255),并且在调用free
时检查它们是否未被触及。另外,在调用free
后,您应该覆盖整个块(包括两侧的填充),以检查是否有双重free
调用。检测缓冲区溢出的更安全的方法是提供自己的calloc
实现。在返回的块之前和之后提供一些字节填充,将它们设置为已知值(不是0或255),并且在调用free
时检查它们是否未被触及。另外,在调用free
后,您应该覆盖整个块(包括两侧的填充),以检查是否有双重free
调用。检测缓冲区溢出的更安全的方法是提供自己的calloc
实现。在返回的块之前和之后提供一些字节填充,将它们设置为已知值(不是0或255),并且在调用free
时检查它们是否未被触及。另外,在调用free
后,您应该覆盖整个块(包括两侧的填充),以检查是否有双重free
调用。检测缓冲区溢出的更安全的方法是提供自己的calloc
实现。在返回的块之前和之后提供一些字节填充,将它们设置为已知值(不是0或255),并且在调用free
时检查它们是否未被触及。另外,在调用free
后,您应该覆盖整个块(包括两侧的填充),以检查是否有双重free
调用。所有mem*函数都无效。它们复制(或设置)unsigned int类型的对象,而必须复制(或设置)unsigned char类型的对象。考虑到uu大小可以是奇数。
这些函数本身无法在不更改其声明的情况下检查缓冲区溢出
甚至第三个函数也是无效的
char *__strcpy(char *_Dst, const char *_Src)
{
while ((*_Dst++ = *_Src++) != '\0');
return _Dst;
}
函数内部的指针(u Dst)已更改并指向终止零。当您必须返回由Dst指向的字符串的第一个字符的地址时,从函数返回的此地址
这同样适用于前两个函数。所有mem*函数都无效。它们复制(或设置)unsigned int类型的对象,而必须复制(或设置)unsigned char类型的对象。考虑到uu大小可以是奇数。 这些函数本身无法在不更改其声明的情况下检查缓冲区溢出 甚至第三个函数也是无效的
char *__strcpy(char *_Dst, const char *_Src)
{
while ((*_Dst++ = *_Src++) != '\0');
return _Dst;
}
函数内部的指针(u Dst)已更改并指向终止零。当您必须返回由Dst指向的字符串的第一个字符的地址时,从函数返回的此地址
这同样适用于前两个函数。所有mem*函数都无效。它们复制(或设置)unsigned int类型的对象,而必须复制(或设置)unsigned char类型的对象。考虑到uu大小可以是奇数。 这些函数本身无法在不更改其声明的情况下检查缓冲区溢出 甚至第三个函数也是无效的
char *__strcpy(char *_Dst, const char *_Src)
{
while ((*_Dst++ = *_Src++) != '\0');
return _Dst;
}
函数内部的指针(u Dst)已更改并指向终止零。当您必须返回由Dst指向的字符串的第一个字符的地址时,从函数返回的此地址
这同样适用于前两个函数。所有mem*函数都无效。它们复制(或设置)unsigned int类型的对象,而必须复制(或设置)unsigned char类型的对象。考虑到uu大小可以是奇数。 这些函数本身无法在不更改其声明的情况下检查缓冲区溢出 甚至第三个函数也是无效的
char *__strcpy(char *_Dst, const char *_Src)
{
while ((*_Dst++ = *_Src++) != '\0');
return _Dst;
}
函数内部的指针(u Dst)已更改并指向终止零。当您必须返回由Dst指向的字符串的第一个字符的地址时,从函数返回的此地址
这同样适用于前两个函数。您可能需要所欠缓冲区的
大小,该大小可用于迭代多个位置以复制检查缓冲区溢出(如果有),如下所示
char *__strcpy(char *_Dst, const char *_Src, int size)
{
while ((*_Dst++ = *_Src++) != '\0' && size--); //Iterate/copy to allocated Bytes
return _Dst;
}
您可能需要所欠缓冲区的大小
,可用于迭代多个位置以复制检查缓冲区溢出(如有),如下所示
char *__strcpy(char *_Dst, const char *_Src, int size)
{
while ((*_Dst++ = *_Src++) != '\0' && size--); //Iterate/copy to allocated Bytes
return _Dst;
}
您可能需要所欠缓冲区的大小
,可以使用
#define GUARD_LEN = 4 // Arbitrary number of guard bytes.
#define GUARD_BYTE = 0xA5 // Arbitrary but recognizable: 10100101b
#define UNUSED_BYTE = 0x96 // Arbitrary but recognizable: 10010110b
#define FREED_BYTE = 0xC3 // Arbitrary but recognizable: 11000011b
#define MAX_ALLOCS = 1024 // Max # of malloc'ed buffers.
struct {
void *addr; // Address of malloc'ed buffer
size_t len; // Number of requested bytes
} Allocs[MAX_ALLOCS];
// Allocates and initializes memory.
void *chk_malloc(size_t length) {
// Allocate memory for buffer + guard bytes.
void *mem = malloc(length + 2*GUARD_LEN);
if (mem == NULL) {
return NULL;
}
// Initialize: [GUARD][UNUSED_BUFFER][GUARD]
// Caller's usable memory starts after GUARD.
void *buffer = mem + GUARD_LEN;
memset(mem, GUARD_BYTE, GUARD_LEN);
memset(buffer, UNUSED_BYTE, length);
memset(buffer + length, GUARD_BYTE, GUARD_LEN);
// Remember the address and length.
// Simplified for demonstration; you may want this to be smarter.
for (int i = 0; i < MAX_ALLOCS; ++i) {
if (Allocs[i].addr == NULL) {
Allocs[i].addr = buffer;
Allocs[i].len = length;
return buffer;
}
return NULL; // Should also indicate MAX_ALLOCS is too small.
}
// Checks that buffer is filled with val.
bool chk_filled(void *buffer, char val, size_t len) {
for (int i = 0; i < len; ++i) {
if (buffer[i] != val) {
return false;
}
}
return true;
}
// Checks for over/underrun and releases memory.
void chk_free(void *buffer) {
// Find the buffer in the array of alloc'ed buffers.
for (int i = 0; i < MAX_ALLOCS; ++i) {
if (Allocs[i].addr == buffer) {
void *guard = buffer - GUARD_LEN; // Initial guard bytes.
if (!chk_filled(guard, GUARD_BYTE, GUARD_LEN)) {
// Underrun
}
end_guard = buffer + Allocs[i].len; // Terminal guard bytes.
if (!chk_filled(end_guard, GUARD_BYTE, GUARD_LEN)) {
// Overrun
}
// Mark the buffer as free and release it.
memset(guard, FREED_BYTE, Allocs[i].len + 2*GUARD_LEN);
Allocs[i].addr = -Allocs[i].addr; // See text below.
free(guard);
return;
}
}
// Error: attempt to free unalloc'ed memory.
}