StoneThrow StoneThrow - 5 months ago 17
C++ Question

Why does this "return the rvalue" fail?

Can someone point out why, in the following code, using variable

p_char
with the "return the rvalue" style when passing to
write()
SIGSEGVs?

#include <iostream>
#include <cerrno>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdint.h>
#include <sstream>
#include <stdexcept>

#define ASSERT( EXPRESSION, SOCKETPAIR ) \
{ \
if ( ! ( EXPRESSION ) ) \
{ \
std::ostringstream oss; \
oss << "Expression \"" << #EXPRESSION << "\" failed at line " << __LINE__ \
<< "; errno == " << errno << " (" << strerror( errno ) << ")"; \
throw MyException( oss.str(), SOCKETPAIR ); \
} \
}

class SocketPair
{
public:
SocketPair()
{
memset( socket_, -1, sizeof( socket_ ) );
}
int* operator()() { return socket_; }
int operator[]( const uint32_t idx )
{
if ( idx > 1 ) return -1;
return socket_[ idx ];
}
private:
int socket_[ 2 ];
};

class MyException : public std::runtime_error
{
public:
MyException( const std::string& what_arg, SocketPair& sp )
: runtime_error( what_arg )
, sp_( sp )
{}
SocketPair& sp_;
};

int main( int argc, char* argv[] )
{
SocketPair sp;
try
{
int result;

errno = 0;
result = socketpair( AF_LOCAL, SOCK_STREAM, 0, sp() );
ASSERT( result == 0, sp );

std::cout << "sp[0]==" << sp[0] << ", sp[1]==" << sp[1] << std::endl;

const char* p_char;
result = write( sp[ 1 ], ( p_char = "Hello?" ), strlen( p_char ) );
ASSERT( result == strlen( p_char ), sp );
}
catch ( MyException& e )
{
std::cout << e.what() << std::endl;
if ( e.sp_[ 0 ] >= 0 ) close( e.sp_[ 0 ] );
if ( e.sp_[ 1 ] >= 0 ) close( e.sp_[ 1 ] );
return 1;
}

close( sp[ 0 ] );
close( sp[ 1 ] );
return 0;
}


If I change the following two lines...

const char* p_char;
result = write( sp[ 1 ], ( p_char = "Hello?" ), strlen( p_char ) );


...to this...

const char* p_char = "Hello?";
result = write( sp[ 1 ], p_char, strlen( p_char ) );


...then the program does not SIGSEGV and exits gracefully.

Compilation tested on gcc 4.8.3 and 4.9.2 (Code Chef).

Update: Sigh...I hate the sagging feeling of being downvoted (in this case for not providing a minimal example, I think). But my attempts at more minimal examples do not exhibit the problem. This actually backs up aschepler's answer because seemingly inconsequential code changes alter the result from
SIGSEGV
to graceful exit.

Answer Source

The order of evaluation of function arguments is undefined (at least in C++14 and earlier).

So in

result = write( sp[ 1 ], ( p_char = "Hello?" ), strlen( p_char ) );

strlen( p_char ) may be evaluated before p_char = "Hello?", resulting in disaster.