簡體   English   中英

意外的跟蹤陷阱

[英]Unexpected trace trap

我有以下代碼:

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

#define MAX_FIL 15
#define MAX_COL 15
#define MAX 15*15


int frase_a_taula(char frase[], char taula[MAX_FIL][MAX_COL]) {
    int i, j, k = 0, l, res = 0, final = 0;
    for (i = 0; !final; i++) {
        l = 0;
        for (j = i; frase[j] != ' ' && frase[j] != '.'; j++) {
            taula[k][l] = frase[j];
            l++;
        }
        taula[k][l] = '\0';
        if (frase[j] == '.') final = 1;
        i = j;
        k++;
        res++;
    }
    return res;
}


void mescla_string_taula(char taula[MAX_FIL][MAX_COL], int n_filas, int coeficient) {
    int n_mescles = 0, i, ind1, ind2;
    if (coeficient == 2) {
        n_mescles = n_filas / 2;
    }
    else if (coeficient == 1) {
        n_mescles = n_filas / 4;
    }

    srand(time(NULL));
    for (i = 0; i < n_mescles; i++) {
        ind1 = rand() % n_filas;
        ind2 = rand() % n_filas;
        char *temp = (char *)malloc((strlen(taula[ind1]) + 1) * sizeof(char));
        strcpy(temp, taula[ind1]);
        strcpy(taula[ind1], taula[ind2]);
        strcpy(taula[ind2], temp);
        free(temp);
    }

}

void alenteix_i_mescla_frase(char frase[MAX], char frase_lenta[MAX], 
                             int velocitat, int coeficient) {
    char taula[MAX_FIL][MAX_COL];
    int i, j, len_frase_lenta;
    int n_paraules = frase_a_taula(frase, taula);
    mescla_string_taula(taula, n_paraules, coeficient);

    
    strcpy(frase_lenta, taula[0]);

    len_frase_lenta = strlen(frase_lenta);
    for (i = 1; i < n_paraules; i++) {
        if (velocitat == 1) {
            if (i % 2 == 0) {
                frase_lenta[len_frase_lenta] = '.';
                frase_lenta[len_frase_lenta + 1] = '.';
                frase_lenta[len_frase_lenta + 2] = '.';
                len_frase_lenta += 3;
                for (j = 0; j < strlen(taula[i]); j++) {
                    frase_lenta[len_frase_lenta] = taula[i][j];
                    len_frase_lenta++;
                }
            }
            else {
                frase_lenta[len_frase_lenta] = ' ';
                len_frase_lenta++;
                for (j = 0; j < strlen(taula[i]); j++) {
                    frase_lenta[len_frase_lenta] = taula[i][j];
                    len_frase_lenta++;
                }
            }
        }
        else if (velocitat == 2) {
            frase_lenta[len_frase_lenta] = '.';
            frase_lenta[len_frase_lenta + 1] = '.';
            frase_lenta[len_frase_lenta + 2] = '.';
            len_frase_lenta += 3;
            for (j = 0; j < strlen(taula[i]); j++) {
                frase_lenta[len_frase_lenta] = taula[i][j];
                len_frase_lenta++;
            }
        }
    }
    frase_lenta[len_frase_lenta] = '.';
    frase_lenta[len_frase_lenta+1] = '\0';
    
}


int main() {
    printf("Introdueix nom del fitxer: ");
    char path[MAX];
    scanf("%s", path);
    printf("Introdueix velocitat de parla: ");
    int velocitat;
    scanf("%d", &velocitat);
    printf("Introdueix el coeficient de yodificacio: ");
    int coef;
    scanf("%d", &coef);
    FILE* f = fopen(path, "r");
    if (f == NULL) {
        printf("Fitxer no trobat!");
    }
    else {
        char line[MAX], frase_yodificada[MAX];
        while (fgets(line, MAX, f) != NULL) {
            alenteix_i_mescla_frase(line, frase_yodificada, velocitat, coef);
            printf("%s\n", frase_yodificada);
        }
        printf("De processar...ha acabat, el fitxer\n");
    }
    return 0;
}

和文件yodatest.txt

may the force be with you.
may the force be with you every day of your life.
avui fa un dia molt bonic.
hola.
si entrenes molt i ets perseverant arribaras lluny i tindras molts poders.
un dia em comprare una moto i anire volant fins a l'estrella de la mort.
no hi ha dia que no m'agradi mirar les estrelles de nit.

Ubuntu wsl下的Windows wsl 中編譯和執行此代碼時,我沒有收到任何錯誤。 但是,當我編譯代碼並在MacOs中執行它時,我得到 output:

[1] 60023 trace trap./main.exe

有時它執行正確,有時它不正確,但我嘗試在Ubuntu下多次執行它,我總是得到正確的答案。 此外,評論mescla_string_taula似乎有效,但同樣,由於錯誤的性質,我不能確定。 基本上,那 function 只是洗牌矩陣。 關於為什么會發生這種情況的任何線索?

一個正確的例子是:

Introdueix nom del fitxer: yodatest.txt
Introdueix velocitat de parla: 1
Introdueix el coeficient de yodificacio: 1
may the...force you...with be.
with the...force be...may of...every day...you your...life.
avui fa...un bonic...molt dia.
hola.
si molts...molt i...ets poders...arribaras lluny...i perseverant...entrenes tindras.
volant anire...em comprare...una fins...i dia...un moto...a l'estrella...de la...mort.
no de...ha dia...que nit...m'agradi mirar...les no...hi estrelles.
De processar...ha acabat, el fitxer

我將首先展示我是如何使用調試器來查找問題的,因為這是一種並不像應有的那樣廣為人知的技術。

首先,我將提供的源代碼復制並粘貼到文件yoda.c中,並將提供的測試輸入復制並粘貼到文件yodatest.txt中。 (作為旁觀者閱讀本文的旁觀者:這就是為什么我們總是要求在問題中以文本形式提供源代碼和測試數據,而不是圖像或任何內容。從我的 web 中復制和粘貼內容只需幾秒鍾瀏覽器,進入我的 C 編譯環境,然后我就關閉並運行了。)

我編譯了yoda.c並運行它,得到了一個非常相似的錯誤:

Abort trap: 6

這是很有希望的。 (有時很難或不可能重現錯誤,使其更難診斷幾個數量級。)

接下來我為調試編譯:

cc -g yoda.c

並在調試器下運行程序:

$ lldb a.out
(lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) run

鍵入“運行”運行程序。 但是現在,當它崩潰時,我從調試器中得到了相當多的 output:

2022-01-18 19:21:07.871139-0500 a.out[34597:99984533] detected source and destination buffer overlap
Process 34597 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff57022e3e libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fff57022e3e <+10>: jae    0x7fff57022e48            ; <+20>
    0x7fff57022e40 <+12>: movq   %rax, %rdi
    0x7fff57022e43 <+15>: jmp    0x7fff5701a0b8            ; cerror_nocancel
    0x7fff57022e48 <+20>: retq   
Target 0: (a.out) stopped.

我可以輸入“bt”來獲取堆棧回溯:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00007fff57022e3e libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff57161150 libsystem_pthread.dylib`pthread_kill + 333
    frame #2: 0x00007fff56f7f312 libsystem_c.dylib`abort + 127
    frame #3: 0x00007fff56f7f485 libsystem_c.dylib`abort_report_np + 177
    frame #4: 0x00007fff56fa3c2d libsystem_c.dylib`__chk_fail + 48
    frame #5: 0x00007fff56fa3c3d libsystem_c.dylib`__chk_fail_overlap + 16
    frame #6: 0x00007fff56fa3c6e libsystem_c.dylib`__chk_overlap + 49
    frame #7: 0x00007fff56fa3e39 libsystem_c.dylib`__strcpy_chk + 64
    frame #8: 0x000000010000084e a.out`mescla_string_taula(taula=0x00007ffeefbff550, n_filas=12, coeficient=1) at yoda.c:44
    frame #9: 0x0000000100000907 a.out`alenteix_i_mescla_frase(frase="si entrenes molt i ets perseverant arribaras lluny i tindras molts poders.\n", frase_lenta="hola.", velocitat=1, coeficient=1) at yoda.c:56
    frame #10: 0x0000000100000dd2 a.out`main at yoda.c:117
    frame #11: 0x00007fff56ed3115 libdyld.dylib`start + 1

這告訴我,對strcpy的違規調用是yoda.c第 44 行的調用。 (這很方便,因為程序中有四個對strcpy的調用,否則我可能不知道是哪一個導致了問題。)

明顯是線

strcpy(taula[ind1], taula[ind2]);

mescla_string_taula()中可以在自身之上復制一個字符串。 strcpy未定義為在這種情況下正常運行。

一個定義為在重疊情況下正常工作的 functionmemmove 我用

memmove(taula[ind1], taula[ind2], strlen(taula[ind2])+1);

現在該程序似乎可以工作了。

請注意,我沒有更深入地分析問題,也沒有檢查其他問題,更不用說證明程序對所有輸入都是正確的。 (在評論中,Ruud Helderman 發現了一些其他可疑代碼。)但在我的機器上,修改后的程序現在確實為那個測試用例生成了所需的 output。

暫無
暫無

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

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