I repost the question with full source code.
I'm struggling on Libaio for asynchronous file I/O.
I think it's too strange to understand.
If I malloc array of struct & call io_prep_pwrite like following :
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libaio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <assert.h>
#include "client_file.h"
#include "config.h"
#define MAX_AIO_SUBMIT 128
#define AIO_STRIPE 131072 // 1024*128 = 128KB
int open_rfile(char* filename, int* filesize, char* fileowner){
struct stat st;
struct passwd * pwd;
int fd = open(filename, O_RDONLY);
if (fd<0){
perror("open file fail\n");
}
stat(filename, &st);
*filesize = (int)st.st_size;
pwd = getpwuid(st.st_uid);
strcpy(fileowner, pwd->pw_name);
return fd;
}
io_context_t ctx;
struct iocb* piocbarr[128];
//fd is opened before calling this function
int write_file(int fd, unsigned char* buf, int size, int offset){
memset(&ctx, 0x00, sizeof(ctx));
if (io_setup(128, &ctx) !=0){
printf("io_setup error!\n");
exit(1);
}
int num_iocb = (size+AIO_STRIPE -1) / AIO_STRIPE; //num_iocb is 8 when size is 1M
//temporary abortion
assert(num_iocb<MAX_AIO_SUBMIT);
// struct iocb piocbs[8];
struct iocb* piocbsz;
piocbsz = malloc(sizeof(struct iocb)* num_iocb);
memset(piocbarr, 0, sizeof(piocbarr));
int remain = size;
int i;
printf("ret %p\n", __builtin_return_address(0));
for (i=0;i<num_iocb;i++){
io_prep_pwrite(piocbsz+i, fd, (void *)buf, (size_t)AIO_STRIPE<remain ? AIO_STRIPE : remain , (long long)offset);
piocbarr[i] = piocbsz+i;
printf("%p %p %d %d \n", buf, piocbarr[i], offset, remain);
buf+=AIO_STRIPE;
offset+=AIO_STRIPE;
remain -= AIO_STRIPE;
}
printf("ret %p\n", __builtin_return_address(0));
if (io_submit(ctx, num_iocb, piocbarr)!=num_iocb){
perror("io submit error\n");
goto exit;
}
printf("ret %p\n", __builtin_return_address(0));
struct io_event e;
memset(&e, 0, sizeof(struct io_event));
struct timespec timeout;
memset(&timeout, 0, sizeof(timeout));
timeout.tv_sec = 1;
int cnt = 0;
printf("ret %p\n", __builtin_return_address(0));
while(1){
if (io_getevents(ctx, num_iocb, num_iocb, &e, &timeout) == num_iocb){
break;
}
if (++cnt==3){
perror("aio timeout!");
break;
}
}
printf("ret %p\n", __builtin_return_address(0));
exit:
free(piocbsz);
io_destroy(ctx);
return 0;
}
and call this function like this :
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "client_file.h"
#define TESTFILE "aiotest"
#define MEGA (1024*1024)
int main(){
int fd=open_wfile(TESTFILE);
char buf[1*MEGA];
int i;
char a = 'A';
int offset = 0;
for (i=0;i<1024;i++){
memset(buf+offset, a, 1024);
offset+=1024;
if ((++a) > 'z') a = 'A';
}
write_file(fd, buf, 1*MEGA, 0);
close(fd);
free(buf);
return 0;
}
and I call the function with size = 1048576(1MB) like above, then
output:
ret 0x400b6a
760F8010 2578420 131072 917504
76118010 2578460 262144 786432
76138010 25784A0 393216 655360
76158010 25784E0 524288 524288
76178010 2578520 655360 393216
76198010 2578560 786432 262144
761B8010 25785A0 917504 131072
761D8010 25785E0 1048576 0
ret 0x400b6a
ret 0x400b6a
ret 0x400b6a
ret 0x2578460
I get SIGSEGV(segmentation fault) at the end of this function.
The output log said that return address is corrupted by the value which is the input of second io_prep_pwrite function call(0x2578460).
if I use array which is not created by malloc, It works fine(but I guess there also is stack corruption).
I changed just a few line like this :
//struct iocb* piocbs;
//piocbs = malloc(sizeof(*piocbs)*num_iocb); // I also tried sizeof(struct iocb) and check the size.
struct iocb piocbs[10];
...(same with above);
//free(piocbs);
I guess that stack is corrupted after calling io_getevents function because I set the wrong value to the iocb blocks(piocbs), Someone can help me understanding this?