0

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).

StoneThrow
  • 5,314
  • 4
  • 44
  • 86
  • What do you mean by "return the rvalue" ? What rvalue? – M.M May 12 '17 at 03:27
  • @M.M - The rvalue is the const char* "Hello?". At this stackoverflow article I saw this pattern of code referred to as "return the rvalue": http://stackoverflow.com/questions/9514569/what-does-an-assignment-return . The pattern being `func( foo = )`, i.e. `foo` is assigned the rvalue, then that value is passed to `func`. Is there another/more proper term for this? – StoneThrow May 12 '17 at 17:23
  • 1
    OK. That was poor terminology, I've edited that other answer. `"Hello?"` is an lvalue (lvalues can appear on the right-hand side of `=`). – M.M May 12 '17 at 23:32
  • @M.M - Is there a definitive article you know of that defines lvalues and rvalues? I've seen rvalues vaguely defined as "nameless, const objects that appear to the right of an assignment operator" including on StackOverflow, so I'd come to adopt that as my understanding. But what you say contradicts that. – StoneThrow May 12 '17 at 23:36
  • 1
    Yeah, the C Standard. You can find a copy by searching for "n1570". The standard actually does not even use the term "rvalue" , but it's often used , in the context of C language, to mean "value that is not an lvalue". ("lvalue" is defined by the Standard). , there is a footnote about this if you do a text search for "rvalue". – M.M May 12 '17 at 23:40
  • @M.M - Is there a proper term also for this "code pattern", i.e. assigning a right-hand operand then relying on the assigned value? I'd like to correct/improve the title of this question. How about "why does this use of right-hand operand assignment fail?" – StoneThrow May 12 '17 at 23:48
  • No usual term comes to mind, maybe "Why does this use of assignment operator in a function argument fail?" – M.M May 12 '17 at 23:59

1 Answers1

3

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.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • Oh, that's new to me, I'd formed the opinion long ago that function arguments were evaluated left-to-right. I learned something new; thank you. – StoneThrow May 12 '17 at 01:46