程序崩了,咋办?

1. 内存溢出是啥?

举个栈溢出的例子。所有的在函数内部申请的局部变量都是保存在栈中的。比如:

 
  1. #include <string.h> 
  2.  
  3. void fn(void
  4.     char a[100]; 
  5.     char *p = a; 
  6.     bzero(p, 1000); 
  7.  
  8. int main(int argc, char *argv[]) 
  9.     fn(); 
  10.     return 0; 

这里,数组a就会保存在栈中。当栈溢出时,最容易出现的问题是返回指针被修改,进而函数返回时会发现返回的代码段指针错误,提示:“stack smashing detected...":

 
  1. peter@ubuntu-910:~/codes/testspace$ ./testspace  
  2. *** stack smashing detected ***: <unknown> terminated 
  3. ======= Backtrace: ========= 
  4. /lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0x2f7008] 
  5. /lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0x2f6fc0] 
  6. [0x80484b2] 
  7. [0x0] 
  8. ======= Memory map: ======== 
  9. 00215000-00216000 r-xp 00000000 00:00 0          [vdso] 
  10. 00216000-00354000 r-xp 00000000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  11. 00354000-00355000 ---p 0013e000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  12. 00355000-00357000 r--p 0013e000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  13. 00357000-00358000 rw-p 00140000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  14. 00358000-0035b000 rw-p 00000000 00:00 0  
  15. 00c38000-00c4d000 r-xp 00000000 08:07 5220       /lib/tls/i686/cmov/libpthread-2.10.1.so 
  16. 00c4d000-00c4e000 r--p 00014000 08:07 5220       /lib/tls/i686/cmov/libpthread-2.10.1.so 
  17. 00c4e000-00c4f000 rw-p 00015000 08:07 5220       /lib/tls/i686/cmov/libpthread-2.10.1.so 
  18. 00c4f000-00c51000 rw-p 00000000 00:00 0  
  19. 00cfc000-00d18000 r-xp 00000000 08:07 4652       /lib/libgcc_s.so.1 
  20. 00d18000-00d19000 r--p 0001b000 08:07 4652       /lib/libgcc_s.so.1 
  21. 00d19000-00d1a000 rw-p 0001c000 08:07 4652       /lib/libgcc_s.so.1 
  22. 00f63000-00f7e000 r-xp 00000000 08:07 5168       /lib/ld-2.10.1.so 
  23. 00f7e000-00f7f000 r--p 0001a000 08:07 5168       /lib/ld-2.10.1.so 
  24. 00f7f000-00f80000 rw-p 0001b000 08:07 5168       /lib/ld-2.10.1.so 
  25. 08048000-08049000 r-xp 00000000 08:08 264941     /home/peter/codes/testspace/testspace 
  26. 08049000-0804a000 r--p 00000000 08:08 264941     /home/peter/codes/testspace/testspace 
  27. 0804a000-0804b000 rw-p 00001000 08:08 264941     /home/peter/codes/testspace/testspace 
  28. 08a74000-08a95000 rw-p 00000000 00:00 0          [heap] 
  29. b785e000-b7860000 rw-p 00000000 00:00 0  
  30. b7874000-b7876000 rw-p 00000000 00:00 0  
  31. bffad000-bffc2000 rw-p 00000000 00:00 0          [stack] 
  32. 已放弃 

这类问题其实比较简单,起码在linux系统中,在程序崩溃的同时,系统往往会打印出一些backtrace和memory map之类的东西,其中backtrace可以非常有效的让我们发现栈溢出发生的函数位置。如果函数比较深(比如我们这种情况),或者系统没有打印bt的信息,而是直接段错误了,可以用gdb跟踪,然后用backtrace命令看:

 
  1. peter@ubuntu-910:~/codes/testspace$ gdb 
  2. GNU gdb (GDB) 7.0-ubuntu 
  3. Copyright (C) 2009 Free Software Foundation, Inc. 
  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
  5. This is free software: you are free to change and redistribute it. 
  6. There is NO WARRANTY, to the extent permitted by law.  Type "show copying" 
  7. and "show warranty" for details. 
  8. This GDB was configured as "i486-linux-gnu"
  9. For bug reporting instructions, please see: 
  10. <http://www.gnu.org/software/gdb/bugs/>. 
  11. (gdb) file testspace  
  12. Reading symbols from /home/peter/codes/testspace/testspace...done. 
  13. (gdb) r 
  14. Starting program: /home/peter/codes/testspace/testspace  
  15. [Thread debugging using libthread_db enabled] 
  16. *** stack smashing detected ***: <unknown> terminated 
  17. ======= Backtrace: ========= 
  18. /lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0x228008] 
  19. /lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0x227fc0] 
  20. [0x80484b2] 
  21. [0x0] 
  22. ======= Memory map: ======== 
  23. 00110000-0012b000 r-xp 00000000 08:07 5168       /lib/ld-2.10.1.so 
  24. 0012b000-0012c000 r--p 0001a000 08:07 5168       /lib/ld-2.10.1.so 
  25. 0012c000-0012d000 rw-p 0001b000 08:07 5168       /lib/ld-2.10.1.so 
  26. 0012d000-0012e000 r-xp 00000000 00:00 0          [vdso] 
  27. 0012e000-00143000 r-xp 00000000 08:07 5220       /lib/tls/i686/cmov/libpthread-2.10.1.so 
  28. 00143000-00144000 r--p 00014000 08:07 5220       /lib/tls/i686/cmov/libpthread-2.10.1.so 
  29. 00144000-00145000 rw-p 00015000 08:07 5220       /lib/tls/i686/cmov/libpthread-2.10.1.so 
  30. 00145000-00147000 rw-p 00000000 00:00 0  
  31. 00147000-00285000 r-xp 00000000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  32. 00285000-00286000 ---p 0013e000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  33. 00286000-00288000 r--p 0013e000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  34. 00288000-00289000 rw-p 00140000 08:07 5206       /lib/tls/i686/cmov/libc-2.10.1.so 
  35. 00289000-0028c000 rw-p 00000000 00:00 0  
  36. 0028c000-002a8000 r-xp 00000000 08:07 4652       /lib/libgcc_s.so.1 
  37. 002a8000-002a9000 r--p 0001b000 08:07 4652       /lib/libgcc_s.so.1 
  38. 002a9000-002aa000 rw-p 0001c000 08:07 4652       /lib/libgcc_s.so.1 
  39. 08048000-08049000 r-xp 00000000 08:08 264941     /home/peter/codes/testspace/testspace 
  40. 08049000-0804a000 r--p 00000000 08:08 264941     /home/peter/codes/testspace/testspace 
  41. 0804a000-0804b000 rw-p 00001000 08:08 264941     /home/peter/codes/testspace/testspace 
  42. 0804b000-0806c000 rw-p 00000000 00:00 0          [heap] 
  43. b7fe8000-b7fea000 rw-p 00000000 00:00 0  
  44. b7ffe000-b8000000 rw-p 00000000 00:00 0  
  45. bffeb000-c0000000 rw-p 00000000 00:00 0          [stack] 
  46.  
  47. Program received signal SIGABRT, Aborted. 
  48. 0x0012d422 in __kernel_vsyscall () 
  49. (gdb) bt 
  50. #0  0x0012d422 in __kernel_vsyscall () 
  51. #1  0x001714d1 in raise () from /lib/tls/i686/cmov/libc.so.6 
  52. #2  0x00174932 in abort () from /lib/tls/i686/cmov/libc.so.6 
  53. #3  0x001a7fc5 in ?? () from /lib/tls/i686/cmov/libc.so.6 
  54. #4  0x00228008 in __fortify_fail () from /lib/tls/i686/cmov/libc.so.6 
  55. #5  0x00227fc0 in __stack_chk_fail () from /lib/tls/i686/cmov/libc.so.6 
  56. #6  0x080484b2 in fn () at test.c:8 
  57. #7  0x00000000 in ?? () 

这里便看到了:

 
  1. # #6  0x080484b2 in fn () at test.c:8  

以便我们锁定问题。

很多时候,当内存溢出问题不严重时,并不会直接终止我们程序的运行。但是,我们会在调试程序中碰到非常奇怪的问题,比如某一个变量无缘无故变成乱码,不管是在堆中,还是栈中。这便很有可能是指针的错误使用导致的。这种情况出现时,一种调试方法是:使用gdb加载程序,并用watch锁定被改成乱码的变量。这样,如果这个变量被修改,程序便会停下来,我们就可以看到底是哪条语句修改了这个程序。

2. 内存泄漏

内存泄漏只会是在堆中申请的内存没有释放而导致的。也就是,我们在malloc()后没有及时的进行free()。这里,可以利用现有的一些软件帮助我们调试,如Valgrind(http://valgrind.org)。使用方法请参见其主页的帮助文档。

3. 缓冲区:能大就大点

很多内存溢出的问题都是因为缓冲区不够大。因此,我们在开辟缓冲区的时候,一定要给使用打出余量,不能每次想申请多少就申请多少,要想到这部分内存的用途,并进行上限估计。估不出来的时候尽量放大点。

当然,不能随便的放大,可能会出现问题,比如:栈内申请空间过大,程序一使用变量直接段错误。

4. snprintf比sprintf好,那么strncpy就比strcpy好?!

有经验的前辈总是这样说:”小同志,不要随便用sprintf(),要用snprintf(),这样如果打印的数据溢出了可以保护呀!“我们发现,这样做虽然要多写一个参数,但是的确比原来的程序安全了!何乐不为。

之后,我们又看到了strncpy(),一看就高兴!又带一个n!马上用了一下:

 
  1. #include <stdio.h> 
  2. #include <string.h> 
  3.  
  4. void fn(void
  5.     char a[10]; 
  6.     strncpy(a, "hello", 100); 
  7.  
  8. int main(int argc, char *argv[]) 
  9.     fn(); 
  10.     return 0; 
  11. }

很好,程序崩了。

有心的人早就发现了,长度100明显不对阿。可是有人也就想了,为啥10个字节还不够放"hello"这些玩意呢?man一下才知道:

 
  1. STRCPY(3)                                              Linux Programmer's Manual                                              STRCPY(3) 
  2.  
  3. NAME 
  4.        strcpy, strncpy - copy a string 
  5.  
  6. SYNOPSIS 
  7.        #include <string.h> 
  8.  
  9.        char *strcpy(char *dest, const char *src); 
  10.  
  11.        char *strncpy(char *dest, const char *src, size_t n); 
  12.  
  13. DESCRIPTION 
  14.        The  strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to 
  15.        by dest.  The strings may not overlap, and the destination string dest must be large enough to receive the copy. 
  16.  
  17.        The strncpy() function is similar, except that at most n bytes of src are copied.  Warning: If there is no null byte  among  the 
  18.        first n bytes of src, the string placed in dest will not be null terminated. 
  19.  
  20.        If the length of src is less than n, strncpy() pads the remainder of dest with null bytes. 
  21.  
  22.        A simple implementation of strncpy() might be: 
  23.  
  24.            char
  25.            strncpy(char *dest, const char *src, size_t n){ 
  26.                size_t i; 
  27.  
  28.                for (i = 0 ; i < n && src[i] != '\0' ; i++) 
  29.                    dest[i] = src[i]; 
  30.                for ( ; i < n ; i++) 
  31.                    dest[i] = '\0'
  32.  
  33.                return dest; 
  34.            } 
关键是最后的一句:
 
  1. "If the length of src is less than n, strncpy() pads the remainder of dest 
  2. with null bytes. " 

也就是说,strncpy并不仅仅是做一个n长度的保护,而会把剩下的字符清为0x00。要知道,snprintf()是没这档子事情的。所以,我们要记住:

snprintf()总是比sprintf()安全,但是strncpy()和strcpy()比就不一定了。 


总之,程序出问题是怎么也避免不了的。特别是出现诡异的问题的时候,要学会冷静分析产生问题的结果。往往这些问题都是我们编程过程中的错误导致的,而不是我们见鬼了。要对自己解决问题的能力有信心嘛!

程序这东西就是这样,用好了,越用越顺手;用不好,死都不知道怎么死的。

本文出自 “LoudMouth Peter” 博客,请务必保留此出处http://xzpeter.blog.51cto.com/783279/329052

### Matlab 服务器溃的原因及解决方法 #### 可能原因分析 Matlab 服务器溃可能由多种因素引起,以下是常见的几个方面: 1. **兼容性问题** 如果使用的操作系统版本较新而 MatLab 版本较旧,则可能存在 API 接口不匹配的情况。例如,MATLAB 7.0 不支持 Windows 10/11 的 API 接口[^2]。 2. **依赖库缺失或损坏** 缺少必要的动态链接库(DLL 文件),或者某些关键组件被意外删除也可能导致溃。这通常发生在安装过程中未完全配置好环境变量的情况下[^1]。 3. **硬件架构冲突** 对于特定类型的 CPU(如 AMD 处理器),可能会因为内部优化库的不同而导致兼容性问题。可以通过设置系统变量 `BLAS_VERSION` 来指定合适的 DLL 文件路径来缓解此问题[^2]。 4. **图形驱动程序老旧** 显卡驱动更新不足可能导致渲染错误或其他视觉相关的问题,进而引发整个应用程序异常终止。建议定期检查并升级至最新版显卡驱动程序[^1]。 5. **内存管理不当** 当处理非常庞大的数据集时,如果未能合理分配资源则很容易超出物理内存限制从而造成系统不稳定甚至死机现象发生[^3]。 6. **第三方插件干扰** 某些扩展包如果没有正确加载也会影响正常运行流程;另外还有可能是由于 Java 虚拟机(JVM) 配置不合适所引起的启动阶段即告失败情形[^4]。 #### 解决办法汇总 针对以上提到的各种可能性提供相应的修复措施如下所示: - **启用兼容模式**:对于那些无法直接适应当前操作系统的古老软件来说,“向下兼容”的策略往往能够奏效——只需调整目标exe文件属性里的“高级选项”,将其模拟成更早以前的操作平台即可尝试解决问题。 ```bash # Windows环境下具体步骤如下: 右键点击matlab可执行文件->选择"属性" ->切换到"兼容性"标签页下勾选相应项比如这里推荐选用Windows NT 4.0(Service Pack 5) ``` - **补充必要组件**:下载并重新安装Microsoft Visual C++ Redistributable Package系列中的对应版本号产品以确保所有必需的支持都被满足到位; 此外还可以通过命令行方式强制开启调试日志以便定位确切位置处产生的故障信息:`matlab -nodesktop -nosplash`. - **定制化参数传递给虚拟机内的实例**:当本地机器难以克服上述种种障碍之时考虑采用隔离手段不失为明智之举之一—构建专门用于承载此类任务的独立沙盒区域(譬如借助VirtualBox 或 VMware Workstation Pro 创建一个新的Guest OS),然后再按照官方文档指示完成部署工作流。 示例脚本片段展示如何自定义JRE目录地址作为额外输入参数传入setup进程当中去: ```bash setup.exe -v -javadir "C:\Program Files\Java\jre1.8.0_291" ``` - **优调资源配置状况**:鉴于大型项目所需消耗掉大量RAM空间的事实前提之下,务必要提前规划好整体布局结构图谱并且适时运用parfor循环语句实现分布式运算加速效果的同时也要注意监控各节点之间的通讯延迟情况以免形成瓶颈效应影响最终成果质量。 最后提醒一点就是保持良好的习惯做法始终关注来自MathWorks官网发布的补丁公告及时获取最新的安全加固改进内容防止潜在风险隐患进一步扩散蔓延开来危害更大范围群体利益受损。 ```python import os os.environ['BLAS_VERSION'] = r"D:\MATLAB7\bin\win32\atlas_Athlon.dll" ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值