如何判断内存页面是否标记为只读?

时间:2022-09-11 18:22:43

When using copy-on-write semantics to share memory among processes, how can you test if a memory page is writable or if it is marked as read-only? Can this be done by calling a specific assembler code, or reading a certain spot in memory, or through the OS's API?

使用写时复制语义在进程间共享内存时,如何测试内存页是否可写或是否标记为只读?这可以通过调用特定的汇编程序代码,或读取内存中的某个位置,或通过操作系统的API来完成吗?

4 个解决方案

#1


3  

On Linux you can examine /proc/pid/maps:

在Linux上,您可以检查/ proc / pid / maps:

$ cat /proc/self/maps

002b3000-002cc000 r-xp 00000000 68:01 143009   /lib/ld-2.5.so
002cc000-002cd000 r-xp 00018000 68:01 143009   /lib/ld-2.5.so
002cd000-002ce000 rwxp 00019000 68:01 143009   /lib/ld-2.5.so
002d0000-00407000 r-xp 00000000 68:01 143010   /lib/libc-2.5.so
00407000-00409000 r-xp 00137000 68:01 143010   /lib/libc-2.5.so
00409000-0040a000 rwxp 00139000 68:01 143010   /lib/libc-2.5.so
0040a000-0040d000 rwxp 0040a000 00:00 0
00c6f000-00c70000 r-xp 00c6f000 00:00 0        [vdso]
08048000-0804d000 r-xp 00000000 68:01 379298   /bin/cat
0804d000-0804e000 rw-p 00004000 68:01 379298   /bin/cat
08326000-08347000 rw-p 08326000 00:00 0
b7d1b000-b7f1b000 r--p 00000000 68:01 226705   /usr/lib/locale/locale-archive
b7f1b000-b7f1c000 rw-p b7f1b000 00:00 0
b7f28000-b7f29000 rw-p b7f28000 00:00 0
bfe37000-bfe4d000 rw-p bfe37000 00:00 0        [stack]

The first column is the virtual memory address range, the second column contains the permissions (read, write, execute, and private), columns 3-6 contain the offset, major and minor device numbers, the inode, and the name of memory mapped files.

第一列是虚拟内存地址范围,第二列包含权限(读取,写入,执行和私有),第3-6列包含偏移量,主设备号和次设备号,inode以及映射的内存名称文件。

#2


3  

On Win32, the best way is to use VirtualQuery. It returns a MEMORY_BASIC_INFORMATION for the page an address falls in. One of the members is Protect, which is some combination of these flags, which contain the possible protection modes. The function also tells you if the memory is free, committed, reserved, and whether it is private, part of an image or shared memory section.

在Win32上,最好的方法是使用VirtualQuery。它为地址所在的页面返回MEMORY_BASIC_INFORMATION。其中一个成员是Protect,它是这些标志的某种组合,包含可能的保护模式。该函数还告诉您内存是否空闲,已提交,保留,以及它是否为私有,是映像或共享内存部分的一部分。

The OS's API is the best way to detirmine the a page's protection. The CPU reads the protection mode from a page descriptor, which is only accessible from kernel mode.

操作系统的API是降低页面保护的最佳方法。 CPU从页面描述符中读取保护模式,该描述符只能从内核模式访问。

#3


1  

Are you talking abou the variety of shared memory allocated via shmget (on Unix)? I.e.

你是在谈论通过shmget分配的各种共享内存(在Unix上)?即

int shmget(key_t, size_t, int);

If so, you can query that memory using

如果是这样,您可以使用查询该内存

int shmctl(int, int, struct shmid_ds *);

For example:

key_t key = /* your choice of memory api */
int flag = /* set of flags for your app */
int shmid = shmget(key, 4096, flag);

struct shmid_ds buf;
int result = shmctl(shmid, IPC_STAT, &buf);
/* buf.ipc_perm.mode contains the permissions for the memory segment */

#4


1  

If you're using Win32, there are the calls IsBadReadPtr and IsBadWritePtr. However, their use is discouraged:

如果您使用的是Win32,则会调用IsBadReadPtr和IsBadWritePtr。但是,不鼓励使用它们:

"The general consensus is that the IsBad family of functions (IsBadReadPtr, IsBadWritePtr, and so forth) is broken and should not be used to validate pointers."

“普遍的共识是,IsBad系列函数(IsBadReadPtr,IsBadWritePtr等)已被破坏,不应用于验证指针。”

The title of Raymond Chen's take on this says it all: "IsBadXxxPtr should really be called CrashProgramRandomly"

Raymond Chen对此的看法说明了一切:“IsBadXxxPtr应该真的被称为CrashProgramRandomly”

Chen has some helpful advice about how to deal with this issue here.

陈在这里有一些关于如何处理这个问题的有用建议。

The upshot is, you shouldn't be testing this kind of thing at run-time. Code so that you know what you're being handed, and if it's not what's expected, treat it as a bug. If you really have no choice, look into SEH for handling the exception.

结果是,你不应该在运行时测试这种东西。编码,以便您知道自己被交付的内容,如果不是预期的,请将其视为错误。如果你真的别无选择,请查看SEH以处理异常。

#1


3  

On Linux you can examine /proc/pid/maps:

在Linux上,您可以检查/ proc / pid / maps:

$ cat /proc/self/maps

002b3000-002cc000 r-xp 00000000 68:01 143009   /lib/ld-2.5.so
002cc000-002cd000 r-xp 00018000 68:01 143009   /lib/ld-2.5.so
002cd000-002ce000 rwxp 00019000 68:01 143009   /lib/ld-2.5.so
002d0000-00407000 r-xp 00000000 68:01 143010   /lib/libc-2.5.so
00407000-00409000 r-xp 00137000 68:01 143010   /lib/libc-2.5.so
00409000-0040a000 rwxp 00139000 68:01 143010   /lib/libc-2.5.so
0040a000-0040d000 rwxp 0040a000 00:00 0
00c6f000-00c70000 r-xp 00c6f000 00:00 0        [vdso]
08048000-0804d000 r-xp 00000000 68:01 379298   /bin/cat
0804d000-0804e000 rw-p 00004000 68:01 379298   /bin/cat
08326000-08347000 rw-p 08326000 00:00 0
b7d1b000-b7f1b000 r--p 00000000 68:01 226705   /usr/lib/locale/locale-archive
b7f1b000-b7f1c000 rw-p b7f1b000 00:00 0
b7f28000-b7f29000 rw-p b7f28000 00:00 0
bfe37000-bfe4d000 rw-p bfe37000 00:00 0        [stack]

The first column is the virtual memory address range, the second column contains the permissions (read, write, execute, and private), columns 3-6 contain the offset, major and minor device numbers, the inode, and the name of memory mapped files.

第一列是虚拟内存地址范围,第二列包含权限(读取,写入,执行和私有),第3-6列包含偏移量,主设备号和次设备号,inode以及映射的内存名称文件。

#2


3  

On Win32, the best way is to use VirtualQuery. It returns a MEMORY_BASIC_INFORMATION for the page an address falls in. One of the members is Protect, which is some combination of these flags, which contain the possible protection modes. The function also tells you if the memory is free, committed, reserved, and whether it is private, part of an image or shared memory section.

在Win32上,最好的方法是使用VirtualQuery。它为地址所在的页面返回MEMORY_BASIC_INFORMATION。其中一个成员是Protect,它是这些标志的某种组合,包含可能的保护模式。该函数还告诉您内存是否空闲,已提交,保留,以及它是否为私有,是映像或共享内存部分的一部分。

The OS's API is the best way to detirmine the a page's protection. The CPU reads the protection mode from a page descriptor, which is only accessible from kernel mode.

操作系统的API是降低页面保护的最佳方法。 CPU从页面描述符中读取保护模式,该描述符只能从内核模式访问。

#3


1  

Are you talking abou the variety of shared memory allocated via shmget (on Unix)? I.e.

你是在谈论通过shmget分配的各种共享内存(在Unix上)?即

int shmget(key_t, size_t, int);

If so, you can query that memory using

如果是这样,您可以使用查询该内存

int shmctl(int, int, struct shmid_ds *);

For example:

key_t key = /* your choice of memory api */
int flag = /* set of flags for your app */
int shmid = shmget(key, 4096, flag);

struct shmid_ds buf;
int result = shmctl(shmid, IPC_STAT, &buf);
/* buf.ipc_perm.mode contains the permissions for the memory segment */

#4


1  

If you're using Win32, there are the calls IsBadReadPtr and IsBadWritePtr. However, their use is discouraged:

如果您使用的是Win32,则会调用IsBadReadPtr和IsBadWritePtr。但是,不鼓励使用它们:

"The general consensus is that the IsBad family of functions (IsBadReadPtr, IsBadWritePtr, and so forth) is broken and should not be used to validate pointers."

“普遍的共识是,IsBad系列函数(IsBadReadPtr,IsBadWritePtr等)已被破坏,不应用于验证指针。”

The title of Raymond Chen's take on this says it all: "IsBadXxxPtr should really be called CrashProgramRandomly"

Raymond Chen对此的看法说明了一切:“IsBadXxxPtr应该真的被称为CrashProgramRandomly”

Chen has some helpful advice about how to deal with this issue here.

陈在这里有一些关于如何处理这个问题的有用建议。

The upshot is, you shouldn't be testing this kind of thing at run-time. Code so that you know what you're being handed, and if it's not what's expected, treat it as a bug. If you really have no choice, look into SEH for handling the exception.

结果是,你不应该在运行时测试这种东西。编码,以便您知道自己被交付的内容,如果不是预期的,请将其视为错误。如果你真的别无选择,请查看SEH以处理异常。