簡體   English   中英

讀取文件時轉儲​​了分段故障核心

[英]Segmentation fault core dumped when reading file

我在第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文件)。 有人可以看看嗎?

從代碼中的許多問題中,最重要的是

  1. 你並不需要強制轉換 malloc ,這是沒有必要的,並可能導致無法跟蹤的錯誤。

  2. 你並不需要使用 malloc固定大小的局部變量。

  3. 您永遠不會檢查任何在失敗時返回NULL的函數的返回NULL ,即該函數

    1. malloc()
    2. fopen()
    3. strok()

    所有這些函數在失敗時都將返回NULL

  4. malloc並分配了指針str2 ,但隨后在處將其覆蓋

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

    這樣做毫無意義,這意味着您不了解指針的工作方式。 strstr()返回指向傳遞給它的相同字符串的指針,只是將其遞增以指向要查找的子字符串的開頭,如果未找到則為NULL

  5. 你有

     key = strtok(str2, ":"); /* some other code */ strtok(key, "$"); 
  6. fclosefd2外部I / O流while循環,但你fopen()這里面,你可能fopen很多倍主編它比你fclose ð它。

    您有兩個選擇,或者將fclose()移到while循環內,或者將fopen()移到while循環外,第二個當然更好。

    這是錯誤的,因為您增加了指向同一字符串的指針,因此必須這樣做,讀取strtok()

     strtok(NULL, "$"); 

如您所見,您有很多潛在的未定義行為,尤其是在代碼中取消引用NULL指針時,如果要防止SEGMENTATION FAULT ,則應修復所有這些問題。

看到程序員忽略這些事情是很普遍的,但是您應該通過小心確保程序不會崩潰。

  • 除非很明顯它不會為NULL ,否則檢查每個取消引用的指針。
  • 使每個指針在聲明時或聲明后都為NULL ,這樣可以確保如果還沒有指向任何指針,則為NULL ,然后可以進行檢查。

處理指針是一件非常困難的事情,但是一旦養成了這些好習慣,就永遠不會再有愚蠢的bug了-> 好吧,幾乎永遠不會

C沒有像Java這樣的異常機制。 獲取有關錯誤的信息的唯一方法是檢查從函數返回的值,有時還獲得更多信息errno

在您的代碼中,您應該檢查fopen成功,如果不成功則返回錯誤信息。

您的程序崩潰是因為您可能嘗試讀取您沒有讀取權限的文件,並且由於fopen返回NULL 修補程序是作為root或sudo運行程序。

編輯

我試了一下,您的程序崩潰了:

程序收到信號SIGSEGV,分段故障。 _IO_fgets(buf = 0x7fffffffd6a0“”,n = 200,fp = 0x0)位於iofgets.c:50 50 iofgets.c:無此類文件或目錄。

因為添加時沒有波蘭語.txt ,所以運行平穩,沒有錯誤

問題是此行缺少錯誤檢查:

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

fopen() 返回指向已填充的FILE對象的指針,如果無法打開文件(該文件不存在,或者用戶沒有足夠的權限讀取該文件fopen() 返回 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行崩潰的原因。

// 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM