一个令人狂Faint的内存管理问题!!!!!!

newpeak 2003-05-29 11:29:58
在一个大型项目中:
文件1有一静态全局函数句柄Ptr,在Foo_Init()函数中得以初始化然后指向一个合法的内存地址,并且该句柄在以后被文件1的其他过程所调用。
文件2声明了两个大型的静态全局数组,大小为40960,随后在某一过程中进行两个数组之间的memcpy操作(该过程第一次调用时,目标数组基本全被赋值为0)。
现象是:
文件1的静态函数句柄Ptr,其所指向的内存单元,竟然被文件2的那一过程的memcpy操作清空,也就是说,该句柄Ptr本来指向的合法内存单元现在成了指向内存0x00000000!!纵使在跟踪过程中偶尔几次没有改变句柄指向的内存单元,也在随后的过程调用中会在memcpy操作中改变。我在跟踪过程中,很清晰的看到,在memcpy的汇编代码中的"REP MOVSB"指令一执行,句柄Ptr所指向的单元立刻被更改为0。
我实在非常困惑,既然它们都是静态的全局变量,在编译期间就应当被分配给合理的内存值,怎么会造成内存的覆盖呢?事实上,在某次运行中,我看到句柄Ptr本身的地址为0x00d6dafc,被赋值的数组的开始地址为0x00de3ddc,纵使加上数组的大小40960,也不会造成地址冲突啊!
没有办法,我只好希望将句柄Ptr改成为在堆中分配的动态地址,可是如何做到呢?项目都是C实现的,文件1中要多次用到句柄Ptr,而动态分配的地址(malloc)在某一函数调用完后便被释放,我还是没法在全局变量区中储存句柄Ptr被初始化后指向的内存单元。
大家能告诉我:
1 为何会出现内存地址被覆盖的现象?
2 如何用动态内存来储存一个要在其他多个过程中使用的内存地址?
谢谢了!!
...全文
74 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
newpeak 2003-05-29
  • 打赏
  • 举报
回复
定义全局指针是不可以的,比如:
Queue_t Ptr;//Queue_t 就是 void *
//此处定义,那么在编译的时刻,编译器就会给Ptr变量本身一个地址,也就是在目标文件
//中的符号表,而该地址所在的单元本身指向的内存并未赋值
Foo_Init()
{
Ptr = malloc();//此处没有任何问题,Ptr指向堆中的某一地址
Ptr = Queue_Create();//此处Ptr又被指向另外的内存单元
//而现在问题是,Ptr在符号表里的地址,也就是&Ptr,会被改写,
//所以此处我们即便是全局的指针变量,依然会被刷新,
//因此,不是Ptr所指向的内存单元的问题,而是Ptr本身,即&Ptr被改写,
//所以无法用全局指针来进行操作
}
tserpent 2003-05-29
  • 打赏
  • 举报
回复
q1: 指针出错,堆栈溢出,数组越界都可能出现这种问题。
zxm954712 2003-05-29
  • 打赏
  • 举报
回复
I think you may declare a global pointer and allocate the memory area to it. Thus you can use it in the other functions. When the program ends, you should free the memory area the pointer pointing.
rtdb 2003-05-29
  • 打赏
  • 举报
回复
1 为何会出现内存地址被覆盖的现象?
应是内存指针被无意改写了。 你应观察这几个重要指针是否发生了变化。

2. 定义全局指针变量, 在系统初始化时动态分配内存(malloc),
在系统退出时再free. 不是非要在某一函数调用完后便被释放的。
newpeak 2003-05-29
  • 打赏
  • 举报
回复
to stukov2002:
你说的我当然知道。
Ptr是否静态变量这没有关系,只要它是全局变量,就一定在编译的时候就得到了&Ptr的值,因此,你所说的malloc,是指定了Ptr指向的内存单元,但这并不能阻挡全局数据区内的其他变量访问Ptr本身的地址即在编译时期分配好的&Ptr。
最后还是谢谢大家,问题搞定了,原因是:
由于是以前人员留下的庞大项目,数组的一个大小被在项目中多次define,而memcpy中的长度则由另外不同的宏定义define,最终导致内存访问越界。由于memcpy操作的变量是指针,因此没有在调试信息中看到数组的大小。混乱的项目define真是非常害人的
最后再次谢谢大家。
zosatapo 2003-05-29
  • 打赏
  • 举报
回复
有一个可能就是你没有多线程库引起的
功名半纸 2003-05-29
  • 打赏
  • 举报
回复
数组越界!!!!!!!!!!!!!!
idontlikenickname 2003-05-29
  • 打赏
  • 举报
回复
你说Ptr是静态变量(有static修饰)?那它的作用域就是定义它的这个文件,别的文件是看不到它的.比如你在文件1中定义了Ptr,那文件2中是看不到Ptr的,如果你在文件2中也定义了一个static的Ptr那它和文件1中的Ptr根本不是一回事.

对于静态变量,如果它是全局的(指的是在一个文件中)那它在编译的时候是被初始化成0的.如果Ptr是个指针类型,那它就是null,必须在使用前用malloc分配内存给它.在程序退出前用free释放.

你可以写两个函数专门用于对Ptr的分配和释放,但必须保证分配内存的函数在程序最开始调用,这样才能保证在使用Ptr之前它已经被分配了内存.在程序退出前别忘了调用释放Ptr的函数.

如果以上都做到了,Ptr还是被改写了,那一定是对某个数组的操作越界,数据覆盖到了全局变量和静态变量的数据区.那就查所有的memset,memcpy,strcpy,strncpy和跟[]操作有关的程序段.





rtdb 2003-05-29
  • 打赏
  • 举报
回复
病根就在于有内存越界访问。
不论什么方法, 病根不去是不行的。

还是查内存越界的错误吧。
justaseeker 2003-05-29
  • 打赏
  • 举报
回复
1 为何会出现内存地址被覆盖的现象?
---------数组越界,或者隐式用指针改变了这块内存,所有类型都是编译时决定的,用指针可以绕过这个限制
newpeak 2003-05-29
  • 打赏
  • 举报
回复
to stukov2002:
这样不行啊,解释如下:
当Ptr被定义的时候,编译器就已经给Ptr分配了一个地址a(在全局变量区)
当使用malloc的时候,机器如下进行寻址:查找内存地址a,然后将该地址单元的值设置为malloc返回的地址。
现在的问题是:内存地址a,会被其他同样处于全局变量区的其他变量访问(就是前边我说的数组,至于为何能访问,我无法理解)。因此,本来内存单元a里的值是合法的,但现在被更改为0,所以Ptr无法指向任何单元。
zf0579 2003-05-29
  • 打赏
  • 举报
回复
什么叫静态全局函数啊? 如果你用static修饰函数 那么这个函数只能在本文件内有效
When modifying a variable or function at file scope, the static keyword specifies that the variable or function has internal linkage (its name is not visible from outside the file in which it is declared).

idontlikenickname 2003-05-29
  • 打赏
  • 举报
回复
回答你的第二个问题:
你可以在文件1中定义Ptr为一个全局的char指针,并且在一个单独的头文件中声明为extern,然后在你的文件1和文件2中分别包含这个头文件.具体如下:

头文件ptr.h:
#ifnedf _PTR_H_
#define _PTR_H_

extern char *Ptr;

#endif

文件1:
#include "ptr.h"
....
char *Ptr; // Define Ptr.
...

Foo_Init()
{
Ptr = (char *)malloc(SizeOfPtr); // Allocate memory for Ptr.
memset(Ptr, 0, SizeOfPtr * sizeof(char)); // Clear memory which Ptr points to.
...
}
....

文件2:
#include "ptr.h" // Include this header if you want use Ptr in this file.
....

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧