【发布时间】:2014-04-23 07:48:17
【问题描述】:
我有一个简单的程序,我试图保护一块内存,然后将一个文件读入该内存,当它发生段错误时释放它.. 首先我认为只有文件是fifo才会有问题。但现在看来即使是普通文件也失败了,
这是代码:
#include <errno.h>
#include <string.h>
#include <iostream>
#include <assert.h>
#include <malloc.h>
#include <sys/mman.h>
#include <unistd.h>
#include <map>
#include <algorithm>
#include <unistd.h>
#include <signal.h>
using namespace std;
#define BUFFER_SIZE 8000
#define handle_error(msg) \
do { cout << __LINE__ << endl ;perror(msg); exit(EXIT_FAILURE); } while (0)
volatile int fault_count = 0;
char* buffer = 0;
int size = 40960;
int my_fault_handler(void* addr, int serious) {
if (mprotect(buffer, size,
PROT_READ | PROT_WRITE) == -1)
handle_error("mprotect");
++fault_count;
cout << "Segfaulting" << endl;
return 1;
}
static void handler(int sig, siginfo_t *si, void *unused) {
my_fault_handler(si ->si_addr, sig);
}
int main (int argc, char *argv[])
{
long pagesize = sysconf(_SC_PAGESIZE);
struct sigaction sa;
sa.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = &handler;
if (sigaction(SIGSEGV, &sa, NULL) == -1)
perror("sigaction");
cerr << "pageSize: " << pagesize << endl;
buffer = (char*)memalign(pagesize, size);
if (buffer == NULL)
handle_error("memalign");
if (mprotect(buffer, size, PROT_READ) == -1)
handle_error("mprotect");
FILE* file = fopen("test", "r");
cout << "File Open" << endl;
if (!file) {
cout << "Failed opening file " << strerror(errno) << endl;
return 0;
}
//*buffer = 0;
while(fread(buffer, pagesize*2, 1, file)) {
if (mprotect(buffer, size,
PROT_READ) == -1)
handle_error("mprotect");
}
cout << ' ' << strerror(errno) << endl;
return(0);
}
注意 //*buffer = 0;,如果我取消标记此行,程序会出现段错误并正常工作.. 有人知道吗? errno 是错误的地址。
谢谢!
更新: 这里似乎问了一个类似的问题: Loading MachineCode From File Into Memory and Executing in C -- mprotect Failing 在建议 posix_memalign 的地方,我已经尝试过了,但没有成功。
【问题讨论】:
-
您能否准确解释一下当您在未更改的情况下运行程序时会发生什么,以及您期望会发生什么?对我来说,程序将页面大小打印为 4096,然后是“文件打开”,然后是“成功”。这发生在未更改的程序和取消注释
*buffer = 0行之后。 -
您有“测试”文件吗?对我来说,当我评论 *buffer = 0;我得到一个错误的地址错误,当文件正在读取时没有段错误
-
可以添加你使用的编译器命令行吗?
-
我创建了一个空的
test文件用于测试目的。编译器调用就像g++ a.c一样简单。 (我还必须删除#include <sigsegv.h>行,因为我的系统上不存在该头文件。) -
是的,这不是必需的,您能否在 segfault 函数中添加一个 cout 以确保您在两种情况下都存在 segfaulting?我也用过简单的 g++