記憶體重疊之strcpy/strncpy/strcat/strncat和memcpy---我又踩到地雷了
前面, 我們說過, strcpy是一個非常不安全的函式, 如果大家在專案中還在用strcpy, 那是不是應該反思一下呢? 於是, 有了更好的strncpy.
但是, 有一次, 我在用strncpy的時候,我覺得很自然啊, 卻犯了一個非常隱蔽的錯誤, 只是在當時的情況下, 該錯誤沒有暴露出來。 在其他情況下, 肯定是有錯誤的。 原來實際是出現了記憶體重疊, 被某高人發現, 我心服口服啊。
看看有記憶體重疊的strcpy(為了簡便起見, 我就不說strncpy的記憶體重疊了)
我們期待的結果是:ababcdefghi, 但實際的結果是:ababcdcdghgh (在vc++6.0環境下),原來, strcpy/strncpy是沒有考慮記憶體重疊的。 我不小心踩到了, 也算一種經歷吧, 做軟體開發就是這樣, 犯錯可以, 但不要犯相同的錯誤, 善於從錯誤中學習。#include <iostream> using namespace std; int main() { char str[100] = {0}; strncpy(str, "abcdefghi", 100 - 1); strcpy(str + 2, str); // 記憶體重疊了, bug!!! cout << str << endl; return 0; }
那怎麼辦呢?
我們期待的結果是:ababcdefghi, 實際結果也是這樣的。#include <iostream> using namespace std; int main() { char str[100] = {0}; strncpy(str, "abcdefghi", 100 - 1); cout << str << endl; char szTemp[100] = {0}; strncpy(szTemp, str, sizeof(szTemp) - 1); strcpy(str + 2, szTemp); // 這裡是示意, 防止越界啊 cout << str << endl; return 0; }
微軟啊微軟, 你咋就沒有提前解決這個bug呢? 下面, 我來嘗試寫一個, 不一定100%穩健, 希望大家提出其中可能存在的bug.
結果:ababcdefghi, 和預期一致。 有bug的話, 歡迎大家拍磚, 共同進步。#include <iostream> using namespace std; char *myStrCpy(char *dst, const char *src) { if(NULL == dst || NULL == src) { return NULL; } int len = strlen(src); char *p = (char *)malloc(len + 1); if(NULL == p) { return NULL; } char *q = p; p[len] = '\0'; // 有必要 while(*p++ = *src++) { ; } p = q; while(*dst++ = *p++) { ; } free(q); // 不是free(p); return dst; } int main() { char str[100] = {0}; strncpy(str, "abcdefghi", 100 - 1); myStrCpy(str + 2, str); cout << str << endl; return 0; }
另外, 在記憶體拷貝時候, strcat/strncat/memcpy也是不允許記憶體重疊的, 總之, 一定要注意記憶體重疊問題。 memcpy替代的解決方法是memmove. 原型是:
void *memmove( void* dest, const void* src, size_t count ); 至於其他函式(如 strcpy/strncpy/strcat/strncat/)的替代方法, 就相對迂迴了點, 需要自己多分配不重疊的記憶體去解決。
相關推薦
記憶體重疊之strcpy/strncpy/strcat/strncat和memcpy---我又踩到地雷了
前面, 我們說過, strcpy是一個非常不安全的函式, 如果大家在專案中還在用strcpy, 那是不是應該反思一下呢? 於是, 有了更好的strncpy. 但是, 有一次, 我在用strncpy的時候,我覺得很自然啊, 卻犯了一個非常隱蔽
記憶體溢位之PermGen OOM深入分析和解決方案
閱讀原文 *現在,網上關於討論PermGen OOM的資料很多,但是深入分析PermGen區域記憶體溢位原因的資料很少。本篇文章嘗試全面分析一下PermGen OOM的原因,其中涉及到了Java虛擬機器執行時資料區、型別裝載、型別解除安裝等,測試程式碼涉及到了JMX協議。
Linux記憶體管理之三 頁的分配和釋放
如上圖,Linux分配頁時,只能分配2^n個頁。核心維護MAX_ORDER個連結串列,每個連結串列記錄著連續的空閒頁。第一個連結串列中的每一項為1個空閒頁,第二個連結串列中的每一項為2個空閒頁,第三個連結串列中的每一項為4個空閒頁。。。,依次類推。分配頁時,從對應的連結串列上摘除空閒頁;釋放頁時,將對應的頁歸
C函式:strlen,strcat,strncat,strcmp,strncmp,strcpy,strncpy,strstr詳解
strlen() 原型:size_t strlen( const char *string ); 功能:計算給定字串的(unsigned int型)長度,不包括'\0'在內 說明:返回s的長度,不包括
Linux記憶體回收之LRU連結串列和第二次機會法
一 LRU回收演算法 記憶體回收的核心是圍繞LRU連結串列來進行操作,Linux核心實現了5種LRU連結串列型別 1. 不活躍匿名頁錶鏈表(LRU_INACTIVE_ANON)//shmem 2. 活躍匿名頁錶鏈表(LRU_ACTIVE_ANON)// 3. 不活躍檔案對
Python學習之旅_01day:變數和常量,變數輸入,縮排,if條件,記憶體回收機制
1.變數和常量1.1 變數是為了儲存程式運算過程中的一些中間結果,為了方便日後呼叫1.2 變數存在一定的描述性,讓大眾一看就知道該變數的用途 1.3書寫方式 變數的命名規則 1. 要具有描述性 2. 變數名只能_,數字,字母組成,不可以是空格或特殊字元(#?<.,¥$*!~) 3. 不能以中文為變數名
Nginx學習之路(六)NginX中的記憶體管理之---Nginx中的記憶體對齊和記憶體分頁
Nginx由於極高的效能受到大家的追捧,而Nginx的高效能與它優秀的記憶體管理方式是分不開的,今天就來聊一聊Nginx中的記憶體對齊和記憶體分頁。先說下Nginx中的記憶體對齊,Nginx中的記憶體對齊機制是它高效能的關鍵因素之一,先說點基礎的東西,什麼是記憶體對齊呢? 記
記憶體管理之堆和棧的區別
不知道誰寫的,很詳細,對了解程式資料儲存有一定幫助,轉載過來自己學習同時與眾分享。 一、預備知識―程式的記憶體分配 一個由C/C++編譯的程式佔用的記憶體分為以下幾個部分 1、棧區(stack)― 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。 2、堆區
C和指標之動態記憶體分配之(編寫calloc函式,函式內部使用malloc函式來獲取記憶體)
1、問題 編寫calloc函式,函式內部使用malloc函式來獲取記憶體 2、程式碼實現 #include <stdio.h> #include <stdlib.h&
memcpy memmove區別和實現(如何處理記憶體重疊問題)
memcpy與memmove的目的都是將N個位元組的源記憶體地址的內容拷貝到目標記憶體地址中。 但當源記憶體和目標記憶體存在重疊時,memcpy會出現錯誤,而memmove能正確地實施拷貝,但這也增加了一點點開銷。 memmove的處理措施: (1)當源記憶體的首地址等於目標記憶體的首地址時,不進行任何拷貝
記憶體管理之堆和棧
關於程式的執行,不得不提到記憶體方面的內容,那麼首先就對一個程序虛擬地址空間的佈局用一張圖來看清楚 這張圖基於32位Linux系統,即起始地址為0x08048000,可以看到順序為只讀段(程式碼段等)、讀寫段(資料段、bss段等)、堆(向上即高地址擴充套件)、用於堆擴充套件的未使用空間、動態庫的對
程式的記憶體分配之堆和棧的區別
堆疊概述 在計算機領域,堆疊是一個不容忽視的概念,堆疊是兩種資料結構。堆疊都是一種資料項按序排列的資料結構,只能在一端(稱為棧頂(top))對資料項進行插入和刪除。在微控制器應用中,堆疊是個特殊的儲存區,主要功能是暫時存放資料和地址,通常用來保護斷點和現場
C語言模擬實現strncpy、strncpy、strncat、strstr和strrstr函式實現
以下是我用C語言模擬實現的部分字串函式: 1、strncpy函式的實現 #include<stdio.h> #include<assert.h> #include<
作業系統記憶體管理之 ---堆和棧的區別
一、預備知識—程式的記憶體分配 一個由C/C++編譯的程式佔用的記憶體分為以下幾個部分 (從上到下,從記憶體高地址到記憶體低地址) 1、棧區(stack) — 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。
strcpy、strncpy、strncpy_s和snprintf
1、strcpy 原型宣告: extern char *strcpy(char* dest, const char *src); 依據源串的\0作為結束判斷的,不會檢查需要拷貝的緩衝區的大小,如果目標空間不夠,就有溢位問題。 2、strncpy 原型 char*
Linux下程序記憶體管理之malloc和sbrk
之前自己突發興趣想寫一下malloc函式,順便了解一下程序的記憶體管理。在寫的過程中發現其實malloc只不過是通過呼叫Linux下的sbrk函式來實現記憶體的分配,只是在sbrk之上加了一層對所分配的記憶體的管理罷了,而sbrk以及brk是實現從虛擬記憶體到記憶體的對映的
記憶體管理之malloc、free、calloc和realloc
記憶體區域可以分為棧,堆,靜態儲存區和常量儲存區。區域性變數,函式形參,臨時變數都是在棧上獲得記憶體的,它們獲取的方式都是由編譯器自動執行的。 C 標準函式庫提供了許多函式來實現對堆上記憶體管理,其中包括:malloc函式,free函式,calloc函式和realloc函式
資料結構預備知識之指標,結構體和動態記憶體的分配與釋放
資料結構的整體框架: 資料結構只解決儲存問題,演算法解決操作問題。演算法依附於儲存結構,儲存不同,演算法不同。 衡量演算法的標準: 時間複雜度:執行的次數而非時間空間複雜度:佔用的記憶體難易程度健壯性 1.預備知識之指標 記憶體是CPU唯一可以直接訪問的大容量儲存區域,
mem系列函式(memset memcpy memmove) 和str系列函式(strlen strcpy strcmp strcat strstr strtok)
void *memset(void *s, int ch, size_t n); 函式解釋:將s中前n個位元組 (typedef unsigned int size_t )用 ch 替換並返回 s 。 memset:作用是在一段記憶體塊中填充某個給定的值,它是對較大的
strcpy(字串複製)和memcpy(記憶體複製)
strcpy和memcpy都是標準C庫函式,它們有下面的特點。 strcpy提供了字串的複製。即strcpy只用於字串複製,並且它不僅複製字串內容之外,還會複製字串的結束符。 已知strcpy函式的原型是:char* strcpy(char* dest, const