2013-02-14 41 views
1

失败我已经出现在嵌入式应用中的一些问题readdir(),所以我在应用程序代码中的一个方便的地方加入这个自成体系的测试:嵌入式Linux:READDIR()有时EFAULT

FILE *f; 
DIR *d; 

f = fopen ("/mnt/mydir/myfile", "r"); 
printf ("fopen %p\r\n", f); 
if (f) fclose(f); 

d = opendir ("/mnt/mydir"); 
printf ("opendir ret %p\r\n", f); 
if (d) 
{ 
    struct dirent *entry; 
    do 
    { 
    errno = 0; 
    entry = readdir (d); 
    printf ("readdir ret %p %s, errno %d %s\r\n", entry, entry ? entry->d_name : "", errno, strerror(errno)); 
    } while (entry); 
    closedir (d); 
} 

/mnt/mydir是一个NFS挂载(尽管我不确定这是否相关)。在该目录中调用打开文件的fopen()总会成功,并且目录上的opendir()也总是成功。但是,有时(大多数)readdir()errno=EFAULT而失败。

我不相信应用程序中的其他任何地方都在使用该目录进行任何操作。测试与写入完全相同,所有变量都是本地堆栈范围。

如果我将它作为独立程序运行,它总是成功。

任何人都可以提供任何建议,以什么可能导致EFAULT在这里?我很确定我的DIR指针变量没有被破坏,尽管DIR结构本身可能是我想的。我在其他地方没有看到有关堆腐败的证据。

+0

AFAICT,这不是'readdir()'的有效返回。在调用readdir()之前,您的(非独立)代码是否真的重置了'errno'?其他任何事情可以在通话之前或之后进行设置吗?你还使用哪个libc? – Hasturkun 2013-02-14 10:45:25

+0

是的,我明确地重置了每次通话时的errno。使用uClibc for ARM。 – gimmeamilk 2013-02-14 11:47:54

+0

你的程序是多线程的吗?我不完全确定,但它看起来像一些旧版本的uClibc(可能使用linuxthreads)不会使'errno'线程本地。请参阅https://bugs.uclibc.org/2089和http://lists.uclibc.org/pipermail/uclibc/2010-July/044196.html – Hasturkun 2013-02-14 14:11:16

回答

0

我想我找到了问题。 opendir/readdir的uClibc实现在目录上执行stat(),然后执行大小为statbuf.st_blksize的堆栈alloca()。我的NFS目录用rsize = 512KB装入,导致readdir()尝试在堆栈上分配512KB以容纳凹痕。我的嵌入式设置在堆栈之间没有太多空间,所以在某些时候在内存中触及了某些内容并导致了EFAULT。

如果我将我的NFS安装选项更改为rsize = 4096,它工作正常。

0

man 2 readdir页:

 EFAULT Argument points outside the calling process's address space. 

这意味着你的结构损坏

+0

这也是我的想法,但我无法想象是什么在破坏它,或者为什么一切似乎都很好。我会做更多的挖掘。 – gimmeamilk 2013-02-14 11:48:45