意外的跟踪陷阱

Nor*_*her 0 c macos

我有以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

还有文件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.
Run Code Online (Sandbox Code Playgroud)

Ubuntu wsl在under编译并执行此代码时Windows,我没有收到任何错误。但是,当我编译代码并在 中执行它时MacOs,我得到输出:

[1] 60023 trace trap ./main.exe

有时它执行正确,有时则不正确,但我尝试Ubuntu多次执行它,并且总是得到正确的答案。另外,评论mescla_string_taula似乎有效,但同样,由于错误的性质,我无法确定。基本上,该函数只是对矩阵进行洗牌。关于为什么会发生这种情况有任何线索吗?

一个正确的例子是:

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
Run Code Online (Sandbox Code Playgroud)

Ste*_*mit 6

我将首先展示如何使用调试器来查找问题,因为这种技术并不像应有的那样广为人知。

首先,我将提供的源代码复制并粘贴到一个文件中yoda.c,并将提供的测试输入复制粘贴到一个文件中yodatest.txt。(对于任何阅读本文的旁观者来说:这就是为什么我们总是要求在问题中以文本形式提供源代码和测试数据,而不是图像或其他任何东西。从我的网络中复制和粘贴内容只需几秒钟浏览器,进入我的 C 编译环境,然后我就可以开始运行了。)

我编译yoda.c并运行它,并得到一个非常相似的错误:

Abort trap: 6
Run Code Online (Sandbox Code Playgroud)

这是很有希望的。(有时很难或不可能重现错误,这使得诊断变得更加困难。)

接下来我编译进行调试:

cc -g yoda.c
Run Code Online (Sandbox Code Playgroud)

并在调试器下运行程序:

$ lldb a.out
(lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) run
Run Code Online (Sandbox Code Playgroud)

输入“run”运行该程序。但现在,当它崩溃时,我从调试器中得到了更多的输出:

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.
Run Code Online (Sandbox Code Playgroud)

我可以输入“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
Run Code Online (Sandbox Code Playgroud)

这告诉我,有问题的调用strcpy是 的第 44 行上的调用yoda.cstrcpy(这很方便,因为程序中有四次调用,否则我可能不知道是哪一个导致了问题。)

明显是线

strcpy(taula[ind1], taula[ind2]);
Run Code Online (Sandbox Code Playgroud)

inmescla_string_taula()可以在其自身之上复制一个字符串。 strcpy未定义为在这种情况下正常运行。

定义为在重叠情况下正常工作的一个函数是memmove。我将有问题的行替换为

memmove(taula[ind1], taula[ind2], strlen(taula[ind2])+1);
Run Code Online (Sandbox Code Playgroud)

现在这个程序似乎可以工作了。

请注意,我没有更深入地分析问题,也没有检查其他问题,更不用说证明程序对于所有输入都是正确的。(Ruud Helderman 在评论中发现了其他一些可疑代码。)但在我的机器上,修改后的程序现在确实为该测试用例生成了所需的输出。