【问题标题】:unexpected seg fault caused by lstat function由 lstat 函数引起的意外 seg 错误
【发布时间】:2019-04-09 05:09:08
【问题描述】:

我正在为编程课做一个作业。
该程序应该:

  1. 从命令行接收字符串。
  2. 打开当前目录并循环浏览其条目,
    并仅在其名称以 我从 CMD 传递的字符串。
  3. 如果这些条目是常规文件,
    我需要计算除空格以外的所有字符,
    并计算以 a/A 开头的单词数。

这是代码。

int main(int argc,char* argv[])
{
    if(argc!=2) //ensures at least an argument is passed.
    {
        puts("enter one argument.");
        exit(EXIT_FAILURE);
    }

    DIR* folder; //folder abstraction
    struct dirent* entry; //entry abstraction
    struct stat info; //file's i node info

    FILE* file;
    int total=0,first=0;
    char temp[100];

    int res;

    folder=opendir("."); //i open the directory

    while((entry=readdir(folder))!=NULL) //i cicle through every entry
    {

        res=strncmp(entry->d_name,argv[1],strlen(argv[1]));
        if(res==0) //if entry name begins with string i continue
        {

            lstat(entry->d_name,&info); //i take file info
            if(S_ISREG(info.st_mode)) //i check if it's a regular file
            {
                file=fopen(entry->d_name,"r"); //i open it
                //printf("%s\n",entry->d_name);
                while((fscanf(file,"%s",temp))!=EOF) //i parse it
                {
                    if(temp[0]=='a'|| temp[0]=='A')
                    {
                        first++;
                    }
                    total+=strlen(temp);
                }
                //now i close the file and print all info
                fclose(file);
                printf("%s\nthe number words that start with a/A: %i\n",entry->d_name,first);
                printf("the amount of characters except spaces is %i\n",total);
                total=0;
                first=0;
            }

        }
        //now the process will be repeated for the remaining entries
    }
    return 0;
}

问题是,程序获得了以我从 CMD 传递的模式开头的第一个条目,并正确评估它,但随后
当在第二个条目上调用 stat 时,会导致 seg fault 11。

如果我注释掉 lstat,所有符合条件的条目都会被识别,即使没有计算我也无法测试它是否是没有 lstat 的常规文件...
是什么原因造成的,过去两个小时我一直在尝试一些东西,请帮助我,谢谢!

编辑:

我发现了问题,基本上我正在工作的目录有可执行文件的二进制文件。

原来二进制文件被认为是普通文件,所以当程序打开它解析它时,它解析了一个导致临时变量缓冲区溢出的长字符串。我认为这些文件是二进制文件,并与常规文件分开。

【问题讨论】:

  • 旁白:while((fscanf(file,"%s",temp))!=EOF) 会更好while((fscanf(file,"%s",temp))==1)
  • Adonai,char temp[100]; ... fscanf(file,"%s",temp) 是 100 或更长的“单词”的问题。如果file == NULLfscanf(file... 也是一个问题。
  • @chux 为什么如果文件为空会出现问题?顺便说一句,更改缓冲区大小并没有解决问题,即使空文件有问题,事实是我什至在打开文件之前调用了 stat,所以这不是问题:/
  • @chux 无论如何,我检查了是否有任何文件为空...没有人是。段错误显然是由于另一个原因而发生的。扩大缓冲区大小甚至没有帮助。
  • 代码不检查来自lstat的返回值。错误检查至关重要,尤其是在出现问题时。有原因的优雅程序退出使开发过程中的生活更轻松(在发布版本中更是如此)。

标签: c operating-system filesystems


【解决方案1】:

由 lstat 函数引起的意外 seg 错误

由于代码其他部分的行为未定义,我们不知道 seg 错误是由lstat 引起的。包含lstat 确实揭示了一个问题,但真正的原因可能在其他地方。


代码有问题,但在各个地方都缺少错误检查。 @Weather Vane

检查函数返回值

folder=opendir(".");
if (folder == NULL) {
  perror("opendir failed);
  exit (EXIT_FAILURE);
}


// lstat(entry->d_name,&info);
if (lstat(entry->d_name,&info)) {
  perror("lstat failed);
  exit (EXIT_FAILURE);
}

file=fopen(entry->d_name,"r");
if (file == NULL) {
  fprintf(stderr, "Unable to open <%s> for reading\n", entry->d_name);
  exit (EXIT_FAILURE);
}

限制宽度

// while((fscanf(file,"%s",temp))!=EOF)
while(fscanf(file,"%99s",temp) == 1) {
  if (strlen(temp) == 99) {
    fprintf(stderr, "Maximum length word read, longer ones might exist\n");
    exit (EXIT_FAILURE);
  }

当然,code cab 不是退出,而是以其他方式处理错误。

次要:我使用宽度类型来计算字符数。

【讨论】:

  • 我在提出问题之前检查了 lstat 返回值,它返回 0 表示执行成功 :/ 。它甚至在 seg fault :/ 之前返回 0。我还将缓冲区扩大到 BUFSIZ,这很多,但没有帮助:/
  • @Adonai "我在灌封之前检查了 lstat 返回值" --> 你是怎么检查的?如果没有看到正确编码的检查(和其他),我们缺乏检查正确完成的证据。
  • @Adonai 更大的缓冲区大小可能会有所帮助,但检查更为重要 - 使用宽度限制,然后验证缓冲区是否足够大。
  • 我发现了问题,基本上我工作的目录有可执行文件的二进制文件。事实证明,二进制文件被认为是常规文件,所以当程序打开它以削减它时,它解析了一个导致临时变量缓冲区溢出的长字符串......我认为那些二进制文件和常规文件分开:(谢谢你们!
  • @Adonai 即使是文本文件,而且大的temp[]fscanf(file,"%s",temp) 也是挥之不去的问题。对"%s" 使用宽度限制可防止异常或恶意文本文件对您的代码造成段错误。它还可以节省您的调试时间。
猜你喜欢
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 2015-05-31
  • 2020-09-28
  • 2021-02-26
  • 1970-01-01
  • 2014-10-04
相关资源
最近更新 更多