进程终止,信号 13 (SIGPIPE) 的默认动作

Process terminating with default action of signal 13 (SIGPIPE)

提问人:Mohammed Ahmed 提问时间:10/1/2023 更新时间:10/1/2023 访问量:81

问:

我正在尝试在缓冲区中读取用户写入的全部数据,以在我自己的 shell“称为 hsh”中处理它,但该过程以信号 13 终止: 这是我传递给我的 shell 的命令:

valgrind echo "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   /bin/ls                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    " | ./hsh

结果如下:

==203856== Process terminating with default action of signal 13 (SIGPIPE)
==203856==    at 0x4960077: write (write.c:26)
==203856==    by 0x48E0E8C: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1181)
==203856==    by 0x48E17A7: new_do_write (fileops.c:449)
==203856==    by 0x48E17A7: _IO_new_file_xsputn (fileops.c:1255)
==203856==    by 0x48E17A7: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1197)
==203856==    by 0x48E037F: fputs_unlocked (iofputs_u.c:37)
==203856==    by 0x10A7AE: ??? (in /usr/bin/echo)
==203856==    by 0x4876082: (below main) (libc-start.c:308)
==203856==
==203856== HEAP SUMMARY:
==203856==     in use at exit: 0 bytes in 0 blocks
==203856==   total heap usage: 228 allocs, 228 frees, 25,267 bytes allocated
==203856==
==203856== All heap blocks were freed -- no leaks are possible
==203856==
==203856== For lists of detected and suppressed errors, rerun with: -s
==203856== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

以下是我读取数据的步骤:

  1. 使用 lseek 转到文件末尾并计算写入的字节数
  2. 再次使用 lseek 返回到文件的开头
  3. 为空字符分配一个缓冲区,其中包含此数量的数据 + 另一个字节
  4. 以块形式读取数据并将其存储在临时缓冲区中
  5. 将写入临时缓冲区的数据复制到实际缓冲区 但是,这种方法给了我一个信号 13(断管信号),我不知道为什么

这是我的代码: 注意:每个名称中带有 underscore(_) 的函数都在其他地方实现,其原型在“main.h”头文件中声明。

#include "main.h"
#define CHUNK_SIZE 1000

/**
 * _getlines - Read the command lines
 * @commands: The list where commands will be stored
 * Return: On success - number of commands
 *         On error - "-1"
 */
int _getlines(char **commands)
{
    char *line, *page, *chunk, ch, qoute;
    ssize_t bytes_read, total_bytes_read = 0;
    int j = 0, cmd_count = 0, i = 0, file_size;
    line = malloc(CHUNK_SIZE * sizeof(char));
    file_size = lseek(STDIN_FILENO, 0, SEEK_END);
    lseek(STDIN_FILENO, 0, SEEK_SET);
    page = malloc(file_size);
    if (page == NULL)
        return (-1);
    while ((bytes_read = read(STDIN_FILENO, line, CHUNK_SIZE) > 0))
    {
        _strcpy(page + total_bytes_read, line);
        total_bytes_read += bytes_read;
    }
    if (bytes_read == -1)
    {
        free(page);
        return (-1);
    }
    printf("%s\n", page);
    while (i < total_bytes_read)
    {
        ch = page[i++];
        if (ch == '\"' || ch == '\'')
        {
            line[j++] = ch;
            qoute = ch;
            do {
                ch = page[i++];
                line[j++] = ch;
            } while (ch != qoute);
        }
        else if (ch == '\n')
        {
            line[j++] = '\0';
            commands[cmd_count] = _strdup(line);
            j = 0;
            (cmd_count)++;
        }
        else
            line[j++] = ch;
    }
    if (cmd_count == 0)
    {
        commands[cmd_count] = _strdup(line);
        cmd_count++;
    }
    free(line);
    return (cmd_count);
}
C 表示 系统调用 getline lseek

评论

1赞 Fe2O3 10/1/2023
首先,...不能保证是以 null 结尾的 C 字符串。此函数调用可以/可能导致 UB..._strcpy(page + total_bytes_read, line);line
1赞 Craig Estey 10/1/2023
不能在 之后使用,因为无法确保读取的数据具有函数所需的0x00终止符。使用长度strcpyreadstr*memcpybytes_read

答:

0赞 Fe2O3 10/1/2023 #1

虽然大部分代码整洁,但仍有许多问题需要解决。我砍掉了一些部分,专注于有问题的行。(顺便说一句。将超过 6000 个 SP 发送到您的代码中肯定会导致溢出,因为字符被复制到其 1000 字节长度。line

int _getlines(char **commands) // Unknown size of ptr array being populated

    char *line, *page, *chunk, ch, qoute; // Illegible block of declarations. "chunk" is unused.
    ssize_t bytes_read, total_bytes_read = 0;
    int j = 0, cmd_count = 0, i = 0, file_size; // "sizes" should be unsigned

    line = malloc(CHUNK_SIZE * sizeof(char)); // sizeof a char is 1. Don't multiply
    // Missing verification of success

    file_size = lseek(STDIN_FILENO, 0, SEEK_END); // Not needed

    page = malloc(file_size); // Did you mean "file_size + 1"?
    if (page == NULL)
        return (-1); // What about the allocation of "line"?

        _strcpy(page + total_bytes_read, line); // "line" is not a string!

    if (bytes_read == -1) {
        free(page); // What about the allocation of "line"?

    while (i < total_bytes_read) { // have to scroll back to verify i starts at 0
        if (ch == '\"' || ch == '\'') {
            line[j++] = ch; // No verification the j < size of line[]

                line[j++] = ch; // again, here
            } while (ch != qoute);

        else if (ch == '\n') {
            commands[cmd_count] = _strdup(line); // unnecessary allocation (see below)

            line[j++] = ch; // and again, here
    }

    if (cmd_count == 0) // Not sure about this...
    {
        commands[cmd_count] = _strdup(line); // line is NOT necessarily a C string
        cmd_count++;
    }
    free(line); // finally... but what about "page"?
    return (cmd_count); // return is not a function call. () unnecessary

有太多的烦恼需要“轻轻触摸”来纠正。

以下内容通过相当大的检修纠正了这些问题。这段代码至少有几条注释来解释它的操作。

int _getlines(char **commands, unsigned sz) { // array max size available
    char k1024[ 1024 ], *page = NULL; // buffers here

    ssize_t total = 0;
    int i;
    while( ( i = read( STDIN_FILENO, k1024, sizeof k1024 ) > 0 ) ) {
        void *tmp = realloc( page, total + i + 1 ); // ongoing growth of input buffer
        if( tmp == NULL ) {
            // perhaps a diagnostic emitted here?
            free( page );
            return -1;
        }
        page = tmp;
        memcpy( page + total, k1024, i );
        total += i;
    }
    page[ total++ ] = 0; // terminate to form C string

    i = 0;
    while( isspace( page[ i ] ) ) i++; // toss away leading whitespace here
    if( !page[ i ] ) {
        free( page ); // that was a waste of time
        return 0;
    }

    if( i )
        memmove( page, page + i, total - i ); // shift everything to start of buffer

    int cmd_count = 0;
    commands[ cmd_count++ ] = page; // TODO: verify cmd_count doesn't exceed allowance

    char qch = 0;
    i = 0;
    while( page[i] )
        switch( page[i] ) {
            case '\"':
            case '\'':
                if( !qch )
                    qch = page[ i ];
                else if( page[ i ] == qch )
                    qch = 0;
                i++;
                break;
            case '\n':
                if( qch ) { i++; break; }
                page[ i++ ] = 0;
                if( page[ i ] )
                    commands[ cmd_count++ ] = page + i;  // TODO: verify cmd_count
                break;
            default:
                i++;
                break;
        }

    return cmd_count;
}

调用方只需熄灭分配的整个块。(留给读者添加相关标题。free( commands[0] )


编辑
或...也许指向段的指针数组也是动态分配的!很难说,因为尚未提供调用此函数的代码。

评论

0赞 Mohammed Ahmed 10/1/2023
你没有使用lseek,为什么不需要它?
0赞 Fe2O3 10/1/2023
为什么不呢?因为这个版本读取“块”并将它们添加到不断增长的缓冲区中(注意:对 ...假设传入的数据是合理的(不是 47 Tb!!),则无需“预先分配”预期大小的缓冲区。realloc()