Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.1k views
in Technique[技术] by (71.8m points)

c++ - Why splice syscall fails when my program runs on Linux but succeeds when it runs in gdb?

I try to run a book's sample code. Its function is to accept a line of input and output it to the standard output and operation parameters specified file. Here is the code:

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

int main( int argc, char* argv[] )
{
    if ( argc != 2 )
    {
        printf( "usage: %s <file>
", argv[0] );
        return 1;
    }
    int filefd = open( argv[1], O_CREAT | O_WRONLY | O_TRUNC, 0666 );
    assert( filefd > 0 );

    int pipefd_stdout[2];
        int ret = pipe( pipefd_stdout );
    assert( ret != -1 );

    int pipefd_file[2];
        ret = pipe( pipefd_file );
    assert( ret != -1 );

    //the first splice()
    ret = splice( STDIN_FILENO, NULL, pipefd_stdout[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    assert( ret != -1 );

    ret = tee( pipefd_stdout[0], pipefd_file[1], 32768, SPLICE_F_NONBLOCK ); 
    assert( ret != -1 );

    //the second splice()       
    ret = splice( pipefd_file[0], NULL, filefd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    assert( ret != -1 );

    //the third splice()
    ret = splice( pipefd_stdout[0], NULL, STDOUT_FILENO, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    printf("errno:%d
",errno);
    assert( ret != -1 );


    close( filefd );
        close( pipefd_stdout[0] );
        close( pipefd_stdout[1] );
        close( pipefd_file[0] );
        close( pipefd_file[1] );
    return 0;
}

After i compiled the code, i ran it and typed "123", it can't output to stdout, the third splice() fails and errno is 22. here is the screenshot of result: p1

And when i use gdb to run the code, it works normally. Here is the screeshot: p2

kernel version: 4.19.163-1

gcc version: 10.2.0

gdb version: 10.1

my compile command: g++ test.cpp -g -o LinuxServer

my run command: ./LinuxServer test.txt

my gdb command: gdb LinuxServer

So why the splice syscall fails when my program runs on Linux but succeeds when it runs in gdb?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In linux manual splice(2), there is a description of ERRORS: EINVAL The target file is opened in append mode.

The stdout in my terminal is at append mode, that's why the third splice syscall fail.

And to solve this problem, we can add fcntl(STDOUT_FILENO, F_SETFL, fcntl(STDOUT_FILENO, F_GETFL) & ~O_APPEND);before the splice syscall.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...