读取文件时转储​​的分段故障核心

时间:2015-01-15 22:35:30

标签: c segmentation-fault fgets

我在第24行(fgets)中遇到了分段错误(核心转储)错误。我不是很熟悉c,但我必须为我的课程制作一个程序。我有以下代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[]){
   FILE *fd1, *fd2;
   char *str1, *str2;
   char *salt, *hash, *key, *key1;
   char buf[13], word[200], pass[200];

   if(argc != 2){
       fprintf(stderr, "Usage: %s <file shadow>\n", argv[0]);
       exit(1);
   }

   str1 = (char*) malloc(100);
   str2 = (char*) malloc(100);

   fd1 = fopen(argv[1], "r");

   fprintf(stderr, "Please, wait...\n");

   while(fgets(str1, 100, fd1) != NULL){
       str2 = strstr(str1, "$1$");
       if(str2 != NULL){
           key = strtok(str2, ":");
           snprintf(pass, sizeof(pass), "%s", key);
           printf("pass=%s (%lu)\n", pass, strlen(pass));

           strtok(key, "$");
           salt = strtok(NULL, "$");
           hash = strtok(NULL, "\0");

           snprintf(buf, sizeof(buf), "$1$%s$", salt);

           fd2 = fopen("polish.txt", "r");

           while(fgets(word, 200, fd2) != NULL){
               (&word[strlen(word)])[-1] = '\0';

           key1 = crypt(word, buf);

           if(!strncmp(key1, pass, strlen(key1))){
               printf("OK!, The password is: %s\n\n", word);
               break;
           }


           }
       }

   }
   fclose(fd1);
   fclose(fd2);
   free(str1);
   free(str2);

   return 0;
 }

当我尝试读取/ etc / shadow文件时,它会引发我的分段错误(也尝试使用自定义txt文件)。谁能看看这个?

4 个答案:

答案 0 :(得分:2)

从代码中的许多问题中,最重要的问题是

  1. 您不需要强制转换 malloc,这不是必需的,可能导致无法解决的错误。

  2. 您无需使用 malloc获取固定大小的本地变量。

  3. 您永远不会检查失败时返回NULL的任何函数的返回值,即此函数

    1. malloc()
    2. fopen()
    3. strok()
    4. 所有这些函数在失败时返回NULL

    5. malloc并指示指针str2,但随后您将其覆盖

      str2 = strstr(str1, "$1$");
      

      没有必要这样做,这意味着你不明白指针是如何工作的。 strstr()返回一个指向传递给它的同一个字符串的指针,只是增加指向你要查找的子字符串的开头,或NULL如果找不到它。

    6. 你有

      key = strtok(str2, ":");
      /* some other code */
      strtok(key, "$");
      
    7. fclose循环外的fd2 I / O流,while I / O流,但您fopen()内置fopen它比你fclose它的次数多很多倍。

      您有两种选择,可以在fclose()循环中移动while,也可以将fopen()移到while循环之外,第二种当然是,更好。

      这是错误的,因为你指向相同字符串的增量指针,你必须这样做,阅读strtok()

      strtok(NULL, "$");
      
    8. 如您所见,您有很多潜在的未定义行为,特别是在代码中取消引用NULL指针,如果您想阻止SEGMENTATION FAULT,则应该修复所有这些内容。< / p>

      看到程序员忽略这些东西是相当普遍的,但你应该确保你的程序不会崩溃,只需要小心。

      • 检查每个指针dereferenc,除非非常明显它不是NULL
      • 将每个指针NULL置于声明之后或之后,这样你可以确保如果它还没有指向任何东西,那么它是NULL,你可以检查它。

      处理指针是一件非常困难的事情,但是一旦你养成这些好习惯,你就永远不会再有愚蠢的错误 - &gt; 嗯,几乎从不

答案 1 :(得分:1)

C没有像Java这样的异常机制。唯一的方法是获取有关错误的信息,以检查函数返回的值,有时获取更多信息errno

在您的代码中,您应该检查fopen是否成功,如果没有退出并显示错误信息。

您的程序崩溃了,因为您可能会尝试阅读由于fopen返回NULL而无法获得读取权限的文件。它的修补程序是以root身份或sudo运行程序。

修改

我试过了,你的程序崩溃了:

  

编程接收信号SIGSEGV,分段故障。   iofgets.c上的_IO_fgets(buf = 0x7fffffffd6a0&#34;&#34;,n = 200,fp = 0x0):50 50 iofgets.c:没有这样的文件或目录。

因为我添加它时没有 polish.txt ,运行顺畅而没有错误

答案 2 :(得分:1)

问题是此行没有错误检查:

 fd1 = fopen(argv[1], "r");

fopen() returns指向已填充的FILE对象的指针,如果无法打开文件,则为NULL(文件不存在,或者用户没有足够的特权阅读它)。

结果,NULL指针被传递到第24行的fgets()调用中。

你应该检查它是否为NULL:

fd1 = fopen(argv[1], "r");
if (fd1 == NULL)
{
    fprintf(stderr, "Couldn't open file for reading\n");
    exit(1);
} 

在我们关于NULL指针的主题的地方,你也应该检查对malloc()的调用。这些不太可能失败,但也可能导致第24行的崩溃。

答案 3 :(得分:0)

// always check returned values from system I/O functions
// always enable all warnings so problems are addressed
// do not use 'magic' numbers
// initialize local variables that are pointers
//   (and generally all local variables)
// when an error is encountered during execution,
//    then release allocated memory, close files before exiting
// always look for and handle errors during execution

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <crypt.h> // <-- added for crypt() function

#define MAX_WORD_LEN (200)
#define MAX_STR_LEN  (100)
#define MAX_BUF_LEN  (13)

int main(int argc, char* argv[])
{
    FILE *fd1 = NULL;
    FILE *fd2 = NULL;

    char *str1 = NULL;
    char *str2 = NULL;

    char *salt, *hash, *key, *key1;

    char buf[MAX_BUF_LEN]   = {'\0'};
    char word[MAX_WORD_LEN] = {'\0'};
    char pass[MAX_WORD_LEN] = {'\0'};

    if(argc != 2)
    {
        fprintf(stderr, "Usage: %s <file shadow>\n", argv[0]);
        exit(1);
    }

    // implied else, command line parameter count correct

    if( NULL == (str1 = malloc(MAX_STR_LEN) ))
    { // then, malloc failed
        perror( "malloc for str1 failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    if( NULL == (str2 = malloc(MAX_STR_LEN) ))
    { // then, malloc failed
        perror( "malloc for str2 failed" );
        free( str1 ); // cleanup
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    if( NULL == (fd1 = fopen(argv[1], "r") ) )
    { // then fopen failed
        perror( "fopen for parameter file name failed" );
        free( str1 ); // cleanup
        free( str2 );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    fprintf(stderr, "Please, wait...\n");

    while( fgets(str1, MAX_STR_LEN, fd1) )
    {
        if( NULL == (str2 = strstr(str1, "$1$") ) )
        { // then, strstr failed
            perror( "strstr for $1$ failed" );
            continue;
        }

        // implied else, strstr successful

        if( NULL != (key = strtok(str2, ":") ) )
        { // then, strtok failed
            perror( "strtok for : failed" );
            continue;
        }

        // implied else, strtok successful

        snprintf(pass, sizeof(pass), "%s", key);
        printf("pass=%s (%lu)\n", pass, strlen(pass));

        if( NULL == strtok(key, "$") )
        { // then strtok failed
            perror( "strtok for $ failed" );
            continue;
        }

        // implied else, strtok successful

        if( NULL == (salt = strtok(NULL, "$") ) )
        { // then strtok failed
            perror( "strtok for salt failed" );
            continue;
        }

        // implied else, strtok successful

        if( NULL == (hash = strtok(NULL, "\0") ) )
        { // then strtok failed
            perror( "strtok for hash failed" );
            continue;
        }

        // implied else, strtok successful

        snprintf(buf, sizeof(buf), "$1$%s$", salt);

        if( NULL == (fd2 = fopen("polish.txt", "r") ) )
        { // then fopen failed
            perror( "fopen for polish.txt failed" );
            fclose(fd1); // cleanup
            free(str1);
            free(str2);
            exit( EXIT_FAILURE );
        }

        // implied else, fopen successful

        while( fgets(word, MAX_WORD_LEN, fd2) )
        {
            (&word[strlen(word)])[-1] = '\0'; // what last char is being dropped?

            key1 = crypt(word, buf);

            if(!strncmp(key1, pass, strlen(key1)))
            {
                printf("OK!, The password is: %s\n\n", word);
                break;
            }

            else
            {
                printf("Oh No, The password did not match\n\n");
            } // end if
        } // end while

        // prep for next test sequence
        fclose( fd2 );
        fd2 = NULL;
    } // end while

    fclose(fd1);
    fclose(fd2);

    free(str1);
    free(str2);

    return 0;
} // end function: main