[C++]运行时,如何确保一个对象是只读的
2011-10-25 22:55
274 查看
相信很多人碰到过一个问题,就是代码太多了,不知道在哪里把这个对象给修改掉了.这个其实有两种办法的.
1. 在调试的时候,可以下数据断点.
gdb有watch断点.比如gdb>watch *(int*)0x12433,要记住,如果想要一只监视这个数据,就要用地址,否则过了这个scope,数据断点就无效了,还有就是,监视的值如果用内置数据类型可以表达的话,是有硬件断点的,否则效率茫茫低.....
2. 运行的时候,本文主要讲这个.
先来回顾一下,我们都知道一个exec,都有好几个段,比如代码段,数据段等.这些段是有读写属性的,例如代码段只可以读,栈段是可以读写~~.那么我们就想把一个对象塞到一个不可以写的段里面,比如.text段....(事实上,我塞进去过,只不过会有警告)
这个异常暴力,而且预留余地太小,不太适合.
现在操作系统都是段模式+分页模式来管理内存的.段模式走不通,换页模式,找个办法设置内存页的属性~~.
非常幸运,Linux下面有mprotect系统调用,可以运行时设置内存页的读写属性,唯一的要求是内存需要4K对齐,浪费了一点.
OK,让我们来看mprotect的man page:http://linux.die.net/man/2/mprotect
签名很简答:int mprotect(const void *addr, size_t len, int prot);
一个地址,一个内存的长度,另外就是读写属性,返回调用的结果,成功返回0,失败返回其他数字.
顺便看看man page中的例子,里面有一个技巧,就是搞到一个4K对齐的内存~~ 通过 ( ptr + 4096 - 1 ) & ~(4096 - 1)搞到的
至此,我们就可以运行时,保证一个对象不可以写,写的话,core掉:-D
PS:
希望windows下也有类似的系统调用,Windows下有VirtualProtect,有兴趣的朋友研究一下
1. 在调试的时候,可以下数据断点.
gdb有watch断点.比如gdb>watch *(int*)0x12433,要记住,如果想要一只监视这个数据,就要用地址,否则过了这个scope,数据断点就无效了,还有就是,监视的值如果用内置数据类型可以表达的话,是有硬件断点的,否则效率茫茫低.....
2. 运行的时候,本文主要讲这个.
先来回顾一下,我们都知道一个exec,都有好几个段,比如代码段,数据段等.这些段是有读写属性的,例如代码段只可以读,栈段是可以读写~~.那么我们就想把一个对象塞到一个不可以写的段里面,比如.text段....(事实上,我塞进去过,只不过会有警告)
这个异常暴力,而且预留余地太小,不太适合.
现在操作系统都是段模式+分页模式来管理内存的.段模式走不通,换页模式,找个办法设置内存页的属性~~.
非常幸运,Linux下面有mprotect系统调用,可以运行时设置内存页的读写属性,唯一的要求是内存需要4K对齐,浪费了一点.
OK,让我们来看mprotect的man page:http://linux.die.net/man/2/mprotect
签名很简答:int mprotect(const void *addr, size_t len, int prot);
一个地址,一个内存的长度,另外就是读写属性,返回调用的结果,成功返回0,失败返回其他数字.
顺便看看man page中的例子,里面有一个技巧,就是搞到一个4K对齐的内存~~ 通过 ( ptr + 4096 - 1 ) & ~(4096 - 1)搞到的
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/mman.h> #include <limits.h> /* for PAGESIZE */ #ifndef PAGESIZE #define PAGESIZE 4096 #endif int main(void) { char *p; char c; /* Allocate a buffer; it will have the default protection of PROT_READ|PROT_WRITE. */ p = malloc(1024+PAGESIZE-1); if (!p) { perror("Couldn't malloc(1024)"); exit(errno); } /* Align to a multiple of PAGESIZE, assumed to be a power of two */ p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1)); c = p[666]; /* Read; ok */ p[666] = 42; /* Write; ok */ /* Mark the buffer read-only. */ if (mprotect(p, 1024, PROT_READ)) { perror("Couldn't mprotect"); exit(errno); } c = p[666]; /* Read; ok */ p[666] = 42; /* Write; program dies on SIGSEGV */ exit(0); }
至此,我们就可以运行时,保证一个对象不可以写,写的话,core掉:-D
PS:
希望windows下也有类似的系统调用,Windows下有VirtualProtect,有兴趣的朋友研究一下
相关文章推荐
- 如何确保只有一个应用程序实例在运行?
- 如何确保应用只有一个实例运行
- C++::如何测试一个函数的运行时间
- C++对象模型之编译器如何处理函数返回一个对象
- L1-040. 最佳情侣身高差【附C++如何保留几位小数,可设置为对一个对象或多个对象生效】
- C++对象模型之编译器如何处理函数返回一个对象
- 如何判断一个C++对象是否在堆上
- 如何判断一个C++对象是否在堆栈上
- 如何判断一个C++对象是否在堆上(通过GetProcessHeaps取得所有堆,然后与对象地址比较即可),附许多精彩评论
- 如何声明一个C++全局类对象
- 如何在VC6.0中得到一个程序的运行时间,也就是这个程序耗费的时钟周期数// C和C++的时间编程
- 如何判断一个C++对象是否在堆栈上(通过VirtualQuery这个API来获取堆栈的起始地址,然后就可以得到答案了),附许多精彩评论
- 用mingw编译C++工程;程序里面的cout<<"aaa";cmd运行c++程序,aaa内容在控制台不显示,如何将aaa输出到控制台屏幕并将控制台内容写到一个文件中。
- C++ STL 如何安全的将一个含有指针变量的类对象放在容器中? 避免浅拷贝问题
- 如何在程序运行中动态改变对象属性在PropertyGrid可见性和只读属性
- 如何在程序运行中动态改变对象属性在PropertyGrid可见性和只读属性
- 如何构建一个名字成员在类外可以被修改而在内部是只读的对象
- 转-如何确保应用只有一个实例运行
- 如何确保 Shell 脚本只有一个实例运行
- 如何判断一个C++对象是否在堆栈上