![](/img/trans.png)
[英]Changing from assignment operator "=" to memcpy for copying bytes resulting in segmentation fault
[英]Getting segmentation fault SIGSEGV in memcpy after mmap
我編寫了一個簡單的 Android 本機函數,它獲取文件名和更多參數,並通過 mmapping (mmap) 它的內存讀取文件。
因為它是 mmap,所以我真的不需要調用“read()”,所以我只是從 mmap() 返回的地址中調用 memcpy()。
但是,我在某處收到 SIGSEGV 可能是因為我試圖訪問我不允許的內存。 但我不明白為什么,我已經要求映射所有文件的內存!
我附上了我的代碼和我得到的錯誤:
編輯
我修復了未終止循環,但在讀取 25001984 字節后仍然獲得 SIGSEGV。 該函數適用於這些參數: jn_bytes = 100,000,000 jbuffer_size = 8192 jshared=jpopulate=jadvice=0
void Java_com_def_benchmark_Benchmark_testMmapRead(JNIEnv* env, jobject javaThis,
jstring jfile_name, unsigned int jn_bytes, unsigned int jbuffer_size, jboolean jshared, jboolean jpopulate, jint jadvice) {
const char *file_name = env->GetStringUTFChars(jfile_name, 0);
/* *** start count *** */
int fd = open(file_name, O_RDONLY);
//get the size of the file
size_t length = lseek(fd, 0L, SEEK_END);
lseek(fd, 0L, SEEK_SET);
length = length>jn_bytes?jn_bytes:length;
// man 2 mmap: MAP_POPULATE is only supported for private mappings since Linux 2.6.23
int flags = 0;
if (jshared) flags |= MAP_SHARED; else flags |= MAP_PRIVATE;
if(jpopulate) flags |= MAP_POPULATE;
//int flags = MAP_PRIVATE;
int * addr = reinterpret_cast<int *>(mmap(NULL, length , PROT_READ, flags , fd, 0));
if (addr == MAP_FAILED) {
__android_log_write(ANDROID_LOG_ERROR, "NDK_FOO_TAG", strerror(errno));
return;
}
int * initaddr = addr;
if(jadvice > 0)
madvise(addr,length,jadvice==1?(MADV_SEQUENTIAL|MADV_WILLNEED):(MADV_DONTNEED));
close(fd);
char buffer[jbuffer_size];
void *ret_val = buffer;
int read_length = length;
while(ret_val == buffer || read_length<jbuffer_size) {
/*****GETTING SIGSEGV SOMWHERE HERE IN THE WHILE************/
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}
munmap(initaddr,length);
/* stop count */
env->ReleaseStringUTFChars(jfile_name, file_name);
}
和錯誤日志:
15736^done
(gdb)
15737 info signal SIGSEGV
&"info signal SIGSEGV\n"
~"Signal Stop\tPrint\tPass to program\tDescription\n"
~"SIGSEGV Yes\tYes\tYes\t\tSegmentation fault\n"
15737^done
(gdb)
15738-stack-list-arguments 0 0 0
15738^done,stack-args=[frame={level="0",args=[]}]
(gdb)
15739-stack-list-locals 0
15739^done,locals=[]
(gdb)
這里有一個大問題:
addr+=jbuffer_size;
您通過sizeof(int) * jbuffer_size
字節來增加addr
而您只想將它增加jbuffer_size
字節。
我的猜測是sizeof(int)
在你的系統上是 4,因此你在循環的大約 25% 處崩潰,因為你在每次迭代中將addr
增加了 4 倍。
這個循環永遠不會終止,因為ret_val
總是等於buffer
void *ret_val = buffer;
int read_length = length;
while(ret_val == buffer || read_length<jbuffer_size) {
/*****GETTING SIGSEGV SOMWHERE HERE IN THE WHILE************/
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}
memcpy
總是返回它的第一個參數,所以ret_val
永遠不會改變。
while
循環是無限的:
while(ret_val == buffer || read_length<jbuffer_size) {
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}
由於memcpy()
始終返回目標緩沖區,因此ret_val == buffer
將始終為true
(因此作為終止條件的一部分是無用的)。 這意味着addr
在循環的每次迭代中都會增加jbuffer_size
字節並傳遞給memcpy()
,從而導致訪問無效內存。
while(ret_val == buffer || read_length<jbuffer_size)
是錯誤的。 ret_val == buffer
將始終為真,如果到達循環時read_length<jbuffer_size
為真,它將始終保持為真,因為read_length
只會減少(好吧,直到它下溢 INT_MIN)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.