当前位置: 首页 > news >正文

[C++]运行时,如何确保一个对象是只读的

相信很多人碰到过一个问题,就是代码太多了,不知道在哪里把这个对象给修改掉了.这个其实有两种办法的.

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,有兴趣的朋友研究一下

转载于:https://www.cnblogs.com/egmkang/archive/2011/10/25/2224561.html

相关文章:

  • PowerShell应用之-批量执行SQL脚本
  • 大家都为了考试的事,读疯了。
  • 职场加薪步步高升的五大法则
  • DR模型集群概述
  • MVC LINQ中用封装的TSQL通用更新方法
  • htons htonl ntohl ntohs 的区别和作用
  • node.js 初体验
  • Oracle中账户被锁定的解决方法
  • 增删主键及修改表名
  • 2011.11.6
  • Control 'XXXX' accessed from a thread other than the thread it was created on
  • 退信代号
  • 网规:第1章 计算机网络原理-1.10服务质量控制技术
  • 白话数字签名(3)——Web程序中的数字签名(转)
  • 收集的网络上大型的开源图像处理软件代码(提供下载链接)
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • Android组件 - 收藏集 - 掘金
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • Java超时控制的实现
  • Java知识点总结(JavaIO-打印流)
  • Joomla 2.x, 3.x useful code cheatsheet
  • Linux下的乱码问题
  • MySQL的数据类型
  • Odoo domain写法及运用
  • TypeScript实现数据结构(一)栈,队列,链表
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 阿里云前端周刊 - 第 26 期
  • 工作手记之html2canvas使用概述
  • 基于遗传算法的优化问题求解
  • 双管齐下,VMware的容器新战略
  • 探索 JS 中的模块化
  • 学习Vue.js的五个小例子
  • 异常机制详解
  • 用 Swift 编写面向协议的视图
  • 正则学习笔记
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • #、%和$符号在OGNL表达式中经常出现
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • (145)光线追踪距离场柔和阴影
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (C++20) consteval立即函数
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (十)T检验-第一部分
  • (四)图像的%2线性拉伸
  • (学习日记)2024.01.09
  • (学习日记)2024.02.29:UCOSIII第二节
  • (转)nsfocus-绿盟科技笔试题目
  • (转)scrum常见工具列表
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes