valgrind调试c/c++内存问题:非法地址访问_内存泄漏_越界访问

1.valgrind功能简介

程序崩溃的 coredump文件, 通过gdb 能定位非法地址访问位置问题,

但对于内存泄漏, 内存越界访问, 无有效的提示.

valgrind 功能强大, 可以调试定位常见内存问题:

  • 非法地址访问
  • 内存泄漏
  • 内存越界读写

命令
调试内存问题 : valgrind --leak-check=full
更新详细的显示: valgrind --leak-check=full --show-leak-kinds=all

2.valgrind提示信息汇总

  • 内存泄漏 lost in loss record 丢失记录 , 内存泄漏实例[[#2.内存泄漏--不完全释放内存|实例链接]]
  • 段错误 Process terminating with default action of signal 11 (SIGSEGV)
  • 越界访问
    • 栈越界读 --无异常
    • 栈越界写 实例[[#2.栈越界写]]
      • Jump to the invalid address stated on the next line
      • reachable in loss record
      • still reachable:

测试代码链接: gitee-51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c

3.实例

1.无内存泄漏--完全释放内存

shell 复制代码
#include <stdio.h>
#include <stdlib.h>

void full_calloc_free(void)
{
    printf("申请3次内存,并释放\n");
    int * p_data[3];
    p_data[0] = malloc(sizeof(int));
    p_data[1] = malloc(sizeof(int)*3);
    p_data[2] = malloc(sizeof(int)*5);

    free(p_data[0]);
    free(p_data[1]);
    free(p_data[2]);
}

valgrind --leak-check=full ./52_valgrind_内存泄漏提示.out

2921 Command: ./52_valgrind___.out

申请3次内存,并释放

2921

2921 HEAP SUMMARY:

2921 in use at exit: 0 bytes in 0 blocks

2921 total heap usage: 4 allocs, 4 frees , 1,060 bytes allocated -->申请4次,释放4次

2921

2921 All heap blocks were freed -- no leaks are possible -->无内存泄漏可能性

2921

2921 For lists of detected and suppressed errors, rerun with: -s

2921 ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

总结:

无内存泄漏的程序, 运行结束, 应该提示无内存泄漏

2.内存泄漏--不完全释放内存

c 复制代码
void manual_leak_mem(void)
{
    printf("申请3次内存,少释放一次,主动触发 内存泄漏\n");
    int *p_data[3];
    p_data[0] = malloc(sizeof(int));
    p_data[1] = malloc(sizeof(int) * 3);
    p_data[2] = malloc(sizeof(int) * 5);

    free(p_data[0]);
    free(p_data[1]);
    // free(p_data[2]);
}

valgrind --leak-check=full ./52_valgrind_内存泄漏提示.out 1

申请3次内存,少释放一次,主动触发 内存泄漏

2981 HEAP SUMMARY:

2981 in use at exit: 20 bytes in 1 blocks

2981 total heap usage: 4 allocs, 3 frees, 1,060 bytes allocated -->4次申请,3次释放,少一次free

2981

2981 20 bytes in 1 blocks are definitely lost in loss record 1 of 1

2981 at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)

2981 by 0x1092A7: manual_leak_mem (52_valgrind_内存泄漏提示.c:23) -->内存泄漏提示行

2981 by 0x109318: main (52_valgrind_内存泄漏提示.c:37)

2981

2981 LEAK SUMMARY:

2981 definitely lost: 20 bytes in 1 blocks

2981 indirectly lost: 0 bytes in 0 blocks

2981 possibly lost: 0 bytes in 0 blocks

2981 still reachable: 0 bytes in 0 blocks

2981 suppressed: 0 bytes in 0 blocks

2981

2981 For lists of detected and suppressed errors, rerun with: -s

2981 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

总结:
lost in loss record 丢失记录 --> 内存泄漏

3.非法地址访问

3.1非法地址读

c 复制代码
// 2.非法地址访问
void invalid_address_access(void)
{
    // uint8_t *p = 0x12345678; # 非法地址
    uint8_t *p = NULL;
    printf("val = %d\n", *p);
}

valgrind --leak-check=full ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out 2

13358 Command: ./51_mem_valgrind__.out 3

13358

13358 Invalid read of size 1 无效读地址

13358 at 0x109234: invalid_address_access (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:18) 提示错误行

13358 by 0x109312: main (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:47)

13358 Address 0x0 is not stack'd, malloc'd or (recently) free'd

13358

13358

13358 Process terminating with default action of signal 11 (SIGSEGV) SIGSEGV非法地址访问

13358 Access not within mapped region at address 0x0

13358 at 0x109234: invalid_address_access (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:18)

13358 by 0x109312: main (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:47)

13358 If you believe this happened as a result of a stack

13358 overflow in your program's main thread (unlikely but

13358 possible), you can try to increase the size of the

13358 main thread stack using the --main-stacksize= flag.

13358 The main thread stack size used in this run was 8388608.

13358

13358 HEAP SUMMARY:

13358 in use at exit: 0 bytes in 0 blocks

13358 total heap usage: 0 allocs, 0 frees, 0 bytes allocated

13358

13358 All heap blocks were freed -- no leaks are possible

13358

13358 For lists of detected and suppressed errors, rerun with: -s

13358 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

3.1非法地址写

c 复制代码
// 2.非法地址访写
void invalid_address_write(void)
{
    // uint8_t *p = 0x12345678; # 非法地址
    uint8_t *p = NULL;
    *p = 0x12;
}

valgrind --leak-check=full ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out 3

17929 Invalid write of size 1 非法地址写

17929 at 0x109267: invalid_address_write (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:26)

17929 by 0x10933F: main (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:56)

17929 Address 0x0 is not stack'd, malloc'd or (recently) free'd

17929

17929

17929 Process terminating with default action of signal 11 (SIGSEGV) 段错误

17929 Access not within mapped region at address 0x0

17929 at 0x109267: invalid_address_write (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:26) 提示行

17929 by 0x10933F: main (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:56)

17929 If you believe this happened as a result of a stack

17929 overflow in your program's main thread (unlikely but

17929 possible), you can try to increase the size of the

17929 main thread stack using the --main-stacksize= flag.

17929 The main thread stack size used in this run was 8388608.

17929

17929 HEAP SUMMARY:

17929 in use at exit: 0 bytes in 0 blocks

17929 total heap usage: 0 allocs, 0 frees, 0 bytes allocated

17929

17929 All heap blocks were freed -- no leaks are possible

17929

17929 For lists of detected and suppressed errors, rerun with: -s

17929 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault 段错误

4.内存越界

1.栈越界读

c 复制代码
// 4.越界 读写
void corss_border_read_write(void)
{
    uint32_t a = 0x10;
    uint32_t *p = &a + 0x8;

    // 越界读 -- 程序不崩溃,可能导致逻辑错误
    printf("cross border address read %x\n", *p);

    // 越界写 -- 程序错误
    *p = 0x12345678;
    //printf("cross border address write %x\n", *p);
}

运行无错误提示
valgrind --leak-check=full --show-leak-kinds=all ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out 4

2.栈越界写

c 复制代码
// 4.越界 读写
void corss_border_read_write(void)
{
    uint32_t a = 0x10;
    uint32_t *p = &a + 0x8;

    // 越界读 -- 程序不崩溃,可能导致逻辑错误
    // printf("cross border address read %x\n", *p);

    // 越界写 -- 程序错误
    *p = 0x12345678;
    printf("cross border address write %x\n", *p);
}

valgrind --leak-check=full ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out 4

cross border address read 0

cross border address write 12345678

23861 Jump to the invalid address stated on the next line 非法地址

23861 at 0x123456780010935C: ???

23861 by 0x48A1D8F: (below main) (libc_start_call_main.h:58)

23861 Address 0x123456780010935c is not stack'd , malloc'd or (recently) free'd

23861

23861

23861 Process terminating with default action of signal 11 (SIGSEGV) 触发段错误

23861 Bad permissions for mapped region at address 0x123456780010935C

23861 at 0x123456780010935C: ???

23861 by 0x48A1D8F: (below main) (libc_start_call_main.h:58)

23861

23861 HEAP SUMMARY:

23861 in use at exit: 1,024 bytes in 1 blocks

23861 total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated

23861

23861 LEAK SUMMARY:

23861 definitely lost: 0 bytes in 0 blocks

23861 indirectly lost: 0 bytes in 0 blocks

23861 possibly lost: 0 bytes in 0 blocks

23861 still reachable: 1,024 bytes in 1 blocks

23861 suppressed: 0 bytes in 0 blocks

23861 Reachable blocks (those to which a pointer was found) are not shown.

23861 To see them, rerun with: --leak-check=full --show-leak-kinds=all

23861

23861 For lists of detected and suppressed errors, rerun with: -s

23861 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Segmentation fault

更详细的显示
valgrind --leak-check=full --show-leak-kinds=all ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out 4

cross border address write 12345678

25992 Jump to the invalid address stated on the next line

25992 at 0x1234567800109340: ???

25992 by 0x48A1D8F: (below main) (libc_start_call_main.h:58)

25992 Address 0x1234567800109340 is not stack'd, malloc'd or (recently) free'd

25992

25992

25992 Process terminating with default action of signal 11 (SIGSEGV)

25992 Bad permissions for mapped region at address 0x1234567800109340

25992 at 0x1234567800109340: ???

25992 by 0x48A1D8F: (below main) (libc_start_call_main.h:58)

25992

25992 HEAP SUMMARY:

25992 in use at exit: 1,024 bytes in 1 blocks

25992 total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated

25992

25992 1,024 bytes in 1 blocks are still reachable in loss record 1 of 1 ==到达 丢失的记录 ==

25992 at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)

25992 by 0x48D879E: printf (printf.c:33)

25992 by 0x1092C0: corss_border_read_write (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:40)

25992 by 0x123456780010933F: ???

25992 by 0x48A1D8F: (below main) (libc_start_call_main.h:58)

25992

25992 LEAK SUMMARY:

25992 definitely lost: 0 bytes in 0 blocks

25992 indirectly lost: 0 bytes in 0 blocks

25992 possibly lost: 0 bytes in 0 blocks

25992 still reachable: 1,024 bytes in 1 blocks

25992 suppressed: 0 bytes in 0 blocks

25992

25992 For lists of detected and suppressed errors, rerun with: -s

25992 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Segmentation fault


5.手动ctrl+c停止进程, 查看内存泄漏

c 复制代码
// 5.内存泄漏 ctrl+c结束进程提示
void manual_leak_mem(void)
{
    printf("申请3次内存,少释放一次,主动触发 内存泄漏\n");
    int *p_data[3];
    p_data[0] = malloc(sizeof(int));
    p_data[1] = malloc(sizeof(int) * 3);
    p_data[2] = malloc(sizeof(int) * 5);

    free(p_data[0]);
    free(p_data[1]);
    // free(p_data[2]);
}

void test5_mem_leak_stop_by_ctrl_c()
{
    // manual_leak_mem();       // 1.只内存泄漏 1次
    while(1)
    {
        manual_leak_mem();      // 2.内存泄漏 多次
        printf("process running\n");
        sleep(1);
    }
}

valgrind --leak-check=full --show-leak-kinds=all ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out 5

申请3次内存,少释放一次,主动触发 内存泄漏

process running

申请3次内存,少释放一次,主动触发 内存泄漏

process running

申请3次内存,少释放一次,主动触发 内存泄漏

process running
^C ----ctrl+c 停止进程----

4658 Process terminating with default action of signal 2 (SIGINT)

4658 at 0x49641B4: clock_nanosleep@@GLIBC_2.17 (clock_nanosleep.c:78)

4658 by 0x4969EC6: nanosleep (nanosleep.c:27)

4658 by 0x4969DFD: sleep (sleep.c:55)

4658 by 0x1093CD: test5_mem_leak_stop_by_ctrl_c (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:65)

4658 by 0x109449: main (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:84)

4658

4658 HEAP SUMMARY:

4658 in use at exit: 140 bytes in 7 blocks

4658 total heap usage: 22 allocs, 15 frees , 1,276 bytes allocated 有7个内存数据未free()释放

4658

4658 140 bytes in 7 blocks are definitely lost in loss record 1 of 1 7个数据丢失记录位置

4658 at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)

4658 by 0x109377: manual_leak_mem (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:51) 提示代码行

4658 by 0x1093B7: test5_mem_leak_stop_by_ctrl_c (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:63)

4658 by 0x109449: main (51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c:84)

4658

4658 LEAK SUMMARY:

4658 definitely lost: 140 bytes in 7 blocks 总结: 肯定丢失7个内存数据

4658 indirectly lost: 0 bytes in 0 blocks

4658 possibly lost: 0 bytes in 0 blocks

4658 still reachable: 0 bytes in 0 blocks

4658 suppressed: 0 bytes in 0 blocks

4658

4658 For lists of detected and suppressed errors, rerun with: -s

4658 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)


总结

  1. 开发功能除了功能实现, 也要对自己编写的代码安全,稳定负责, 个人编写c/c++代码程序之后,
  • 自测试功能完成, 无明显逻辑问题, 程序崩溃现象
  • cppcheck 检查代码可能潜在的风险
  • valgrind 检测程序是否有内存安全问题
  • top , perf, \time查看程序占用cpu,mem,上下文资源是否合理

相关推荐
ChoSeitaku13 分钟前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
娅娅梨15 分钟前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
DdddJMs__13518 分钟前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
兵哥工控19 分钟前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
汤米粥20 分钟前
小皮PHP连接数据库提示could not find driver
开发语言·php
冰淇淋烤布蕾23 分钟前
EasyExcel使用
java·开发语言·excel
我爱工作&工作love我27 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
拾荒的小海螺30 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
马剑威(威哥爱编程)1 小时前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
娃娃丢没有坏心思1 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++