精华内容
下载资源
问答
  • 踩内存 2. 内存重复释放 3. 内存泄露 使用方法用 dbg_malloc, dbg_free 替换原程序中的malloc, free. 适当的时候调用dbg_memory_check 以检查内存泄露。 原理: 在申请的内存前后添加 隔离带,并做记录。...
  • 提供了一种利用内存保护技术实现程序踩内存的检测方法, 利用内存保护技术, 在应用程序申请内存后根据情况将其所申请的内存页面属性设置为只读....
  • 本文主要对内存泄漏、内存溢出、内存踩踏【踩内存】以及malloc的底层实现原理进行了总结。话不多说,直接往下看: 参考文章: 内存泄漏与内存溢出: https://blog.csdn.net/ruiruihahaha/article/details/70270574...

    本文主要对内存泄漏、内存溢出、内存踩踏【踩内存】以及malloc的底层实现原理进行了总结。话不多说,直接往下看:

    参考文章:

    1. 内存泄漏与内存溢出:

      https://blog.csdn.net/ruiruihahaha/article/details/70270574

    2. 踩内存:

      https://blog.csdn.net/u014485485/article/details/104714934

    3. malloc的底层实现原理:

      https://blog.csdn.net/ypshowm/article/details/89071869


    内存泄漏与内存溢出

    内存泄漏与内存溢出的概念:

    1. 内存泄漏(memory leak):

      是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏不断堆积后,就会造成内存溢出。

    2. 内存溢出(out of memory):

      指程序申请内存时,没有足够的内存供申请者使用。通俗理解就是内存不够,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。


    内存泄漏与内存溢出二者的关系

    内存泄漏的堆积最终会导致内存溢出。

    1. **内存泄漏:**你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。

      就相当于你租了个带钥匙的柜子,你存完东西之后把柜子锁上之后,把钥匙丢了或者没有将钥匙还回去,那么结果就是这个柜子将无法供给任何人使用,也无法被垃圾回收器回收,因为找不到他的任何信息。

    2. **内存溢出:**通俗理解就是内存不够,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。

      一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出。比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。说白了就是我承受不了那么多,那我就报错。


    内存泄漏的分类(按发生方式分类)

    1. **常发性内存泄漏:**发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
    2. **偶发性内存泄漏:**发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
    3. **一次性内存泄漏:**发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
    4. **隐式内存泄漏:**程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

    内存踩踏【踩内存】

    踩内存的概念

    访问了不合法的地址 。

    通俗一点就是访问了不属于自己的地址。如果这块地址分配给了另一个变量使用,就会破坏别人的数据。从而导致程序运行异常,挂死,输出图像破图等。

    出现踩内存的情形

    1. 内存访问越界

      a) 数组访问越界;

      b) 字符串操作越界;

    2. 非法指针

      a) 使用了空指针;

      b) 使用了释放掉的指针;

      c) 指针类型转换错误;

    3. 栈溢出;

    4. 多线程读写的数据没有加锁保护;

    5. 多线程使用了线程不安全的函数。

    如何排查踩内存bug

    1. 删减模块代码,缩小排查范围;
    2. 加log,打印内存地址/值;
    3. 将被踩内存设置成只读,在调用栈中查看谁在写;

    还有一些结合内核分析的高级手段,待学习。

    如何避免踩内存bug:

    写代码时严格遵守编程规范!!!

    1. 数组访问边界检查,防止溢出,关于数组大小等关键数值使用宏代替;

    2. 使用strcpy,strcat,sprintf,strcmp,strcasecmp等字符串操作函数需谨慎,可以以使用strncpy,strlcpy,strncat,strlcat,snprintf,strncmp,strncasecmp等代替防止读写越界;

      memcpy在内存重叠时不保证拷贝是正确的,memmove在内存重叠时保证拷贝是正确的;

    3. 指针释放后及时置空,必要时使用指针非空检查;

    4. 不要定义过大的局部变量,例如数组,容易造成栈溢出;

    5. 变量定义好后及时赋初值,特别像结构体这种;

    6. 代码嵌套适量,防止资源重复申请/释放;

    7. 多线程时做好线程保护;

    踩内存定位的成本很高。一旦写出内存踩踏的代码,排查的成本是按规范写代码的成本的1000x。

    注:

    在相机系统中,出现系统崩溃或者图像损坏(绿条,粉条,马赛克等)可以检查一下是否有踩内存,但有一种情况就是同一帧的图像出现块状的错位拼接,大片规则粉块,很有可能是由DDR带宽不够,造成某个模块的ddr lantency太大造成的,需要谨慎查找。

    malloc的底层实现原理

    malloc 函数的实质是它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。

    调用 malloc()函数时,它沿着连接表寻找一个大到足以满足用户请求所需要的内存块。(如果没有搜索到,那么就会用sbrk()才推进brk指针来申请内存空间)。

    然后,将该内存块一分为二(一块的大小与用户申请的大小相等,另一块的大小就是剩下来的字节)。 接下来,将分配给用户的那块内存存储区域传给用户,并将剩下的那块(如果有的话)返回到连接表上。

    调用 free 函数时,它将用户释放的内存块连接到空闲链表上。

    到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段, 那么空闲链表上可能没有可以满足用户要求的片段了。于是,malloc() 函数请求延时,并开始在空闲链表上检查各内存片段,对它们进行内存整理,将相邻的小空闲块合并成较大的内存块。

    搜索空闲块最常见的算法有:首次适配,下一次适配,最佳适配。 (其实就是操作系统中动态分区分配的算法)

    1. 首次适配:第一次找到足够大的内存块就分配,这种方法会产生很多的内存碎片。
    2. 下一次适配:也就是说等第二次找到足够大的内存块就分配,这样会产生比较少的内存碎片。
    3. 最佳适配:对堆进行彻底的搜索,从头开始,遍历所有块,使用数据区大小大于size且差值最小的块作为此次分配的块。
    展开全文
  • 一种踩内存的定位方法(C++)

    千次阅读 2019-10-27 11:57:53
    在嵌入式应用开发过程中,踩内存的问题常常让人束手无策。使用gdb调试工具,可以大幅加快问题的定位。不过,对于某些踩内存的问题,它的表现是间接的,应用崩溃的位置也是不固定的,这就给问题定位带来了更大的困难...

        在嵌入式应用开发过程中,踩内存的问题常常让人束手无策。使用gdb调试工具,可以大幅加快问题的定位。不过,对于某些踩内存的问题,它的表现是间接的,应用崩溃的位置也是不固定的,这就给问题定位带来了更大的困难。

        笔者见过带有虚函数C++的类对象在试图调用虚函数时,因指向虚函数的表指针被踩了,导致获取虚函数的地址是错识的,从而应用崩溃。此问题的表现就是间接的:在踩内存发生时,应用没有崩溃;当应用崩溃时,执行的代码是踩内存的“历史遗迹”。为了让应用在踩内存时就发生崩溃(这样可以使用gdb调试,或分析其coredump),一种方法是将C++类对象配置成只读属性;可用的系统调用为mprotect,它可以配置一段对页对齐的内存区域内存的读写属性。

    下面笔者对此问题进行了抽象和简化,完整的代码如下(memory-test.cpp):

     

    #include <new>
    #include <cstdio>
    #include <cerrno>
    #include <cstring>
    #include <cstdlib>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <malloc.h>
    
    #define MEM_PAGESIZE   4096
    
    class MemBase {
    public:
            MemBase(int x_ = 1, int y_ = 9);
            virtual void testFunc0();
            virtual void testFunc1();
            virtual ~MemBase();
    
    protected:
            void memProtect(bool readonly);
    
    protected:
            unsigned char area[MEM_PAGESIZE * 3];
            int x, y;
    };
    
    class MemDeriv : public MemBase {
    public:
            MemDeriv(int x_ = 2, int y_ = 8);
            virtual void testFunc0();
            virtual void testFunc1();
            virtual ~MemDeriv();
    
    protected:
            int z;
    };
    
    int main(int argc, char *argv[])
    {
            MemDeriv * obj0;
    
            obj0 = new MemDeriv(3, 6);
            obj0->testFunc0();
            obj0->testFunc1();
    
            delete obj0;
            obj0 = NULL;
            return 0;
    }
    
    void MemBase::memProtect(bool readonly)
    {
            int ret;
            size_t msize;
            unsigned long pa;
    
            pa  = (unsigned long) area;
            pa -= sizeof(void *); /* sizeof the TAB, what ever it is */
            if (pa & (MEM_PAGESIZE - 1)) {
                    pa &= ~(MEM_PAGESIZE - 1);
                    pa += MEM_PAGESIZE;
                    msize = MEM_PAGESIZE * 2;
            } else {
                    msize = MEM_PAGESIZE * 3;
            }
    
            if (readonly) {
                    /* initialize the memory */
                    memset(area, 0xA5, sizeof(area));
            }
    
            ret = mprotect((void *) pa, msize,
                    readonly ? PROT_READ /* or PROT_NONE */ : PROT_READ | PROT_WRITE);
            if (ret != 0) {
                    fprintf(stderr, "Error, failed to mprotect(%p): %s\n",
                            (void *) pa, strerror(errno));
                    fflush(stderr);
            }
    }
    
    MemBase::MemBase(int x_, int y_)
    {
            x = x_;
            y = y_;
            fprintf(stdout, "Constructing MemBase, this: %p, area: %p, x: %d (%p), y: %d (%p)\n",
                    (void *) this, (void *) area, x, &x, y, &y);
            fflush(stdout);
    }
    
    void MemBase::testFunc0()
    {
            fprintf(stdout, "In function [%s], x: %d\n", __FUNCTION__, x);
            fflush(stdout);
    }
    
    void MemBase::testFunc1()
    {
            fprintf(stdout, "In function [%s], y: %d\n", __FUNCTION__, y);
            fflush(stdout);
    }
    
    MemBase::~MemBase()
    {
            fprintf(stdout, "Deconstructing MemBase, this: %p\n", (void *) this);
            fflush(stdout);
    }
    
    MemDeriv::MemDeriv(int x_, int y_) : MemBase(x_, y_)
    {
            z = x + y;
            fprintf(stdout, "Construction MemDeriv, this: %p, z: %d (%p)\n",
                    (void *) this, z, &z);
            fflush(stdout);
            memProtect(true);
    }
    
    void MemDeriv::testFunc0()
    {
            fprintf(stdout, "In function [%s], z: %d\n", __FUNCTION__, z);
            fflush(stdout);
    }
    
    void MemDeriv::testFunc1()
    {
            fprintf(stdout, "In function [%s], z: %d\n", __FUNCTION__, z);
            fflush(stdout);
    }
    
    MemDeriv::~MemDeriv()
    {
            memProtect(false);
            fprintf(stdout, "Deconstructing MemDeriv, this: %p\n", (void *) this);
            fflush(stdout);
    }
    

        由于mprotect系统调用的限制,我们只能对基类(MemBase)中增加的3个页大小的内存区域area(中的两个页大小的内存区域)设置只读属性(假设设备的内存页大小为4096字节)。不过,在某些情况下,我们也希望对函数表指针进行保护,于是就有了第60行代码:

    pa -= sizeof(void *); /* sizeof the TAB, what ever it is */

        这样做是有原因的。当创建C++类对象时,大多数情况下,area缓存的起始地址并不是页对齐的;当类对象的起始地址(即this指针)是页对齐的,那么area就偏移了sizeof(void *)字节,这样一来被配置为只读属性的起始地址就是在this指针偏移了4096字节之后:有时候,被踩内存的大小不足一个页的大小,就不会发生踩内存时的崩溃问题了。这是加入第60行代码的原因。

    试着运行一下,此方法确定可行的,测试应用可以正常运行:

        见上图,这里没有测试踩内的异常情况,因此应用可以正常退出。下面让我们来测试一下上面假设的情况,即创建的C++类对象恰好在页对齐的地址上。我们将完整的代码重命名为memory-test1.cpp,将重写main函数,确保创建的类对像this指针是页对齐的,这样就可以对虚函数表指针进行mprotect保护了:

    int main(int argc, char *argv[])
    {
            void * palign;
            MemDeriv * obj0;
    
            palign = memalign(MEM_PAGESIZE, sizeof(MemDeriv));
            if (palign == NULL) {
                    fprintf(stderr, "malloc(%#x) has failed: %s\n",
                            (unsigned int) sizeof(MemDeriv), strerror(errno));
                    fflush(stderr);
                    exit(1);
            }
    
            obj0 = new(palign) MemDeriv(4, 5);
            obj0->testFunc0();
            obj0->testFunc1();
            obj0->~MemDeriv();
    
            free(obj0);
            obj0 = NULL;
            return 0;
    }
    

        如果一切顺利,memory-test1.cpp编译得到的test1就能够正常运行:

        结果却是应用崩溃了!使用gdb试一下,发现应用崩溃发生在子类的析构函数中,在调用memProtect成员函数前,就会对虚函数表指针进行写操作。一方面,我们得知mprotect确实能够正常工作,将一段内存设置为只读;另一方面,我们知道,在子类析构函数中,会操作虚函数表,因此该定位踩内存的方法存在严重缺陷——所有的工作都浪费了:

        这样的结果是不可接受的。我们不希望浪费这些工作,需要继续改进此方法;而改进此方法的手段,就是让C++子类的析构函数在调用memProtect成员函数之后再对虚函数表指针进行写操作。这样在memory-test1.cpp的基础上,改成了memory-test2.cpp,对MemDeriv的析构函数增加了很多nop指令:

    MemDeriv::~MemDeriv()
    {
            asm volatile (
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n" : : : "memory");
            memProtect(false);
            asm volatile (
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n"
                    "\tnop\n" : : : "memory");
            fprintf(stdout, "Deconstructing MemDeriv, this: %p\n", (void *) this);
            fflush(stdout);
    }
    

    相应的,析构函数的反汇编如下(反汇编test2):

        有了足够的nop指令填充代码段的空间,就可以对test2进行修改了,编写简单hed操作指令,对test2进行修改(hed的源码在下载页的压缩包中)。修改完成后,对析构函数的反汇编就变成了:

    可以看到,test2在修改前后,文件大小未改变,但MD5较验值不同:

        接下来最后一搏,对test2进行测试,就能够正常运行了:

    至此,我们的调试C++类被踩内存的方法就成功了:它将我们从踩内存的第二现场带到了案发第一现场。不过在应用崩溃时,还是需要gdb的协助,才得到定位。需要注意的是,该方案有几点要说明一下:

    1. 需要对基类增加页大小整数倍的area缓存成员变量,且需要是第一个成员变量(这样在area与this之间,不存在其他成员变量);
    2. 由子类的构造函数和析构函数调用memProtect,分别设置area(及其之前的虚函数表指针)的只读、可读可写属性;
    3. 若修改源码,每次编译生成的可执行文件或动态库,都需重新构造hed指令,修改子类析构函数,在调用memProtect之后对虚函数表进行写操作。
    展开全文
  • 高铁北京回杭州的路上,想到一个简单的话题...在一个复杂的程序中,发生踩内存是一件非常恶心的事情,很难通过什么线索直到谁在哪个函数中往哪个地址写了什么,比方说数组越界写什么的。 去年,我曾经长篇大论了一篇: ...

    高铁北京回杭州的路上,想到一个简单的话题。

    在一个复杂的程序中,发生踩内存是一件非常恶心的事情,很难通过什么线索直到谁在哪个函数中往哪个地址写了什么,比方说数组越界写什么的。

    去年,我曾经长篇大论了一篇:
    https://blog.csdn.net/dog250/article/details/90690292

    现在看来,我又忍不住怼一波了…那篇文章里的方法纯粹就是为了炫技,搞什么又是纯汇编又是内联汇编,简直太复杂了。

    本文给出一个清新版的,试试看下面的代码:

    // mem_monitor.c
    #include <sys/mman.h>
    #include <stdio.h>
    #include <signal.h>
    #include <asm/processor-flags.h>
    
    char *buff = NULL;
    
    void new_func(int index)
    {
    	buff[index] = 'c'; // write memory!
    	buff[index + 1] = 'd'; // write memory!
    }
    
    void main_func()
    {
    	buff[0] = 'a'; // write memory!
    	buff[1] = 'b'; // write memory!
    	new_func(2);
    	buff[4] = 'e'; // write memory!
    }
    
    #define F_OFFSET		200
    #define PC_OFFSET		192
    #define BP_OFFSET		144
    #define CR2_OFFSET		240
    
    // 单步信号处理函数
    void resume_trap()
    {
    	unsigned long *p;
    
    	p = (unsigned long*)((unsigned char *)&p + F_OFFSET);
    
    	mprotect(buff, 1024, PROT_READ);
    	*p &= ~X86_EFLAGS_TF;
    
    }
    
    // 写保护信号处理函数
    void wp_trap(int signo)
    {
    	unsigned long *p;
    
    	p = (unsigned long*)((unsigned char *)&p + PC_OFFSET);
    	printf("---RIP:[%lx]----", *p); // 打印指令地址
    	p = (unsigned long*)((unsigned char *)&p + BP_OFFSET);
    	printf("STACK:[%lx]----", *p);  // 打印堆栈地址
    	p = (unsigned long*)((unsigned char *)&p + CR2_OFFSET);
    	printf("at Address:[%lx]----\n", *p); // 打印写入的位置
    
    	p = (unsigned long*)((unsigned char *)&p + F_OFFSET);
    	*p |= X86_EFLAGS_TF;
    
    	mprotect(buff, 1024, PROT_READ|PROT_WRITE);
    
    	return;
    }
    
    int main()
    {
    	int i;
    
    	buff = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
    	printf("buffer base at[%lx]\n", buff);
    	mprotect(buff, 1024, PROT_READ);
    
    	signal(SIGSEGV, wp_trap);
    	signal(SIGTRAP, resume_trap);
    
    	main_func();
    	buff[5] = 'f'; // write memory!
    
    	for (i = 0; i < 6; i++) {
    		printf("%c ", buff[i]);
    	}
    	printf("\n");
    
    	return 0;
    }
    

    来,看下效果:

    [root@localhost checker]# gcc mem_monitor.c
    [root@localhost checker]# ./a.out
    buffer base at[7f0f8c72e000]
    ---RIP:[40067a]----STACK:[7fffb98ec3c0]----at Address:[7f0f8c72e000]----
    ---RIP:[400688]----STACK:[7fffb98ec3c0]----at Address:[7f0f8c72e001]----
    ---RIP:[400653]----STACK:[7fffb98ec3b0]----at Address:[7f0f8c72e002]----
    ---RIP:[40066a]----STACK:[7fffb98ec3b0]----at Address:[7f0f8c72e003]----
    ---RIP:[4006a0]----STACK:[7fffb98ec3c0]----at Address:[7f0f8c72e004]----
    ---RIP:[40083b]----STACK:[7fffb98ec3e0]----at Address:[7f0f8c72e005]----
    a b c d e f
    

    和去年那篇相比,本文实现了更加细粒度的内存写监控。去年那个是函数级别的,本文这个是则是指令级别的,从上面的代码和执行效果上,可以一目了然!

    当然了,经理会认为这些不值得一提。


    浙江温州皮鞋湿,下雨进水不会胖!

    展开全文
  • 踩内存问题,个人认为算是比较容易出现但是有很难定位的问题,被踩者轻者功能瘫痪,重者一命呜呼,直接诱发死机。产生踩内存的的原因也比较多样,比较典型的有如下几种: 数组越界访问 字符串越界操作 直接操作...

    在这里插入图片描述

    踩内存问题,个人认为算是比较容易出现但是有很难定位的问题,被踩者轻者功能瘫痪,重者一命呜呼,直接诱发死机。产生踩内存的的原因也比较多样,比较典型的有如下几种:

    • 数组越界访问
    • 字符串越界操作
    • 直接操作野指针
    • 操作了一块已经被释放了内存

    这几种问题,单独说起来都是比较容易发现问题,但这些问题往往在某些环境中不会出现,但是在另外的环境下几乎是必现问题,这时定位起来难度就便增加了很多。这种情况往往是基本逻辑没有问题,在某些环境下(多核、异步、其他复杂环境等)逻辑上出现错误导致出现踩内存的问题。

    下面我记录一下遇到过的踩内存问题,定位了很久… 记忆尤新,可能让我亢奋的是我定位时的骚操作

    1. 发现问题

    发现问题比较简单,测试或者使用过程中突现了一个死机问题,通过core文件(获取其他信息)显示,第一想法是Oh, no, impossible, 这些死机问题怎么能死在这里???,代码不可能进入这个流程呀?,如果是这种情况,恭喜你中奖了,它基本上是因为踩内存引起的。

    如果大概率是踩内存引起的死机问题,在仔细分析代码后没有什么效果的情况下,那么我们需要尝试去稳定复现此问题(可能很多条件不允许)

    2. 复现问题出现的场景

    想方设法找到必现条件。Why? 如果找不到必现条件,就算想验证我的想法都变得比较难,因为我不确定是它没有出现还是已经把它改好了。因此我认为找到必现条件几乎是必要的(目前还是一个小白)。

    3. 分析代码逻辑

    这个过程是贯穿整个问题的生命周期,甚至更长。分析代码并结合复现情景,把出现此问题的所有可能都进行分析,并进行尝试。尝试定位过程中不要求解决问题,**首先确定该问题是否为此问题引起的。**比如说:你怀疑由于提前释放了某一块内存,后面有操作了它,那么好,现在劳资就不释放此内存,然后对齐进行测试,确定是否出现此问题。如果问题依旧,那不好意思,咱们需要继续定位。但是如果不出现刚才的死机问题(可能由于没有释放内存出现OM了),那恭喜你,基本就是它导致的了。

    这里我说一下我当时干过的骚操作:

    在我确定踩内存与某些结构有关的情况下,但是我又不知道谁踩内存,

    struct ohMyGod{
    	int *buff;
    	int length;
    	int cryptAlg;
    	int cryptAlgLen;
    	int hashAlg;
    	int hashAlgLen;
    }
    

    于是乎我将上述的结构体改为这样:

    struct ohMyGod{
    	int unused[128];
    	int *buff;
    	int length;
    	int cryptAlg;
    	int cryptAlgLen;
    	int hashAlg;
    	int hashAlgLen;
    	int unused[128];
    }
    

    我当时的想法:你小子不是要踩内存吗? 劳资给你开一个VIP包间,你尽情的踩吧,我反正不使用这些内存。结果通过这种方式定位到了其中一个结构体。然后结合复现条件慢慢定位到了踩内存是由于新增的异步处理造成的。

    4. 解决问题

    踩内存的问题难度在于定位,解决往往比较简单。

    展开全文
  • 本文主要分享一个Cache一致性踩内存问题的定位过程,涉及到的知识点包括:backtrace、内存分析、efence、wrap系统函数、硬件watchpoint、DMA、Cache一致性等。 1 背景 设备上跑的是嵌入式实时操作系统(RTOS,具体为...
  • 关于踩内存

    千次阅读 2020-03-07 15:55:53
    1.什么是踩内存 访问了不合法的地址 。通俗一点就是访问了不属于自己的地址。如果这块地址分配给了另一个变量使用,就会破坏别人的数据。从而导致程序运行异常,挂死,输出图像破图等。 2.踩内存的可能的情形 1...
  • 踩内存

    千次阅读 2014-04-17 17:48:28
    众所周知,踩内存是一个非常麻烦的问题,不管是在应用层或是内核层,关于踩内存的检测也有各种各样的工具,比如应用层的优秀开源valgrind,内核内置的kmemcheck等。关于这些工具的具体信息就不在这里做进一步描述了...
  • 对于 C 语言来说,内存是比较常见的问题,轻则普通变量被改写程序逻辑出错,重则指针变量被改写引发指针解引用出现未定义行为风险; 定位内存一直是棘手的难题,如果出现程序跑死,一般可以通过堆栈信息来...
  • 一文读懂踩内存

    2021-01-26 16:13:38
    2. 踩内存的可能的情形 1)内存访问越界 a)数组访问越界; b)字符串操作越界; 2)非法指针 a)使用了空指针; b)使用了释放掉的指针; c)指针类型转换错误; 3)栈溢出; 4)多线程读写的数据没有...
  • 踩内存问题定位总结

    2020-04-20 09:01:21
    大致原因:数组越界,字符串操作越界,栈指针操作越界,操作了释放掉了的指针,多线程时序对资源保护控制不当,内存管理异常,使用了其他地方的内存 定位方法: 1. 类似内存泄漏的问题,先定界,后定位,通过内存...
  • C++ 踩内存

    2019-08-11 21:40:54
    1、从上往下,栈在堆上面(记忆方法:站在...2、模拟踩内存,让程序崩溃。代码如下:int main(int argc, char* argv[]){ int a = 263; int* pa = &a; char tmp[4]="ab"; strcpy(tmp,"aaaaaaaaaaaaaaaaaaaaaaaaa...
  • 记一次踩内存debug

    千次阅读 2019-01-18 14:54:37
    思考:后来想了下和这个问题,一直困扰了点时间后,总结一下,其实每次复线都是死在不相干的同一个堆栈信息,也就是说这个踩内存不是乱踩而是指定的踩,这里就可以总结其实是有一个地方固定踩了固定内容的的内存,而...
  • Linux用户态程序踩内存时可以用mprotect定位,mprotect本身是linux系统上的一个系统 调用,这个系统调用可以改变一段内存的读写属性, 当有非法的访问访问对应的内存的时候 会给进程发一个SIGSEGV信号,进程可以在...
  • 踩内存(内存重叠)的处理

    千次阅读 2018-06-06 01:11:19
    memcpy和memmove()都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下:[cpp] view plaincopyprint?void *memcpy(void *dst, const void *src, size_t count); void...
  • 踩内存专题分析

    千次阅读 2016-10-11 16:01:54
    kernel内存种类 先了解下kernel内存种类,才知道如何针对分析。 全局变量 这个最直接,直接在驱动里定义全局变量就可以拿来使用,不过要注意互斥访问。 内存是分配在.data/.bss段的。 局部变量 ...
  • 内核由于共享内存地址空间,如果没有合适的工具,很多踩内存的问题即使复现,也无法快速定位; 在新的内核版本中引入了一个新工具hardware breakpoint,其能够监视对指定的地址的特定类型(读/写)的数据访问,有利于该...
  • 解这类问题最关键的两点就是,1,找到被内存地址,2,抓住被的时序。 想要找到被内存地址,这里很多时候可以通过堆栈反汇编,和调试,查找出来,虽然很多时候被的地方不固定,这就糟糕了。就要想方法...
  • stm32踩内存的问题

    2019-01-01 22:32:03
    最近重构代码的时候发现一个踩内存的bug,当时没有时间将这个问题记录下来,这一次简单记录一下。 问题描述 经过打印发现代码中的数据会被莫名的改掉,全局搜索发现没有地方修改这个结构体。这个问题随机出现,确认...
  • 问题定位:内存泄漏,踩内存

    万次阅读 2013-07-27 00:27:40
    1.内存泄漏  确定现象:  linux 内存泄漏,可以查看slabinfo 和另外一个proc下(貌似meminfo),关于内存的信息,可以看到内存是否在不断减少,以及减少的速度。  vxworks系统,内存是否有相关信息???  如果...
  • 用mprotect来定位Linux踩内存的问题

    千次阅读 2018-03-01 22:48:03
    最恶心的Bug莫过于踩内存,定位了内核问题的朋友都知道。这类问题一直没有很套路的方法解决,都需要走读大量的代码,做大量调试来解决。解这类问题最关键的两点就是,1,找到被踩的内存地址,2,抓住被踩的时序。 ...
  • 51-SWITCH踩内存问题定位分析 现象 51交换机中移入ERPS功能后,通过ping设备抓包发现设备的mac地址的后两位并不是设备的原先的地址,原先的mac地址为fc:19:d0:01:02:03,但是设备arp应答的地址却是 fc:19:d0:01:05:...
  • Linux C/C++内存越界定位: 利用mprotect使程序在crash在第一现场 https://blog.csdn.net/thisinnocence/article/details/80025064 linux c之使用mprotect检测内存访问 ... 用mprotect定位...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,056
精华内容 8,422
关键字:

踩内存