Been running valgrind on my code the last few days and one that I can not figure out is on the first write to libwebsockets and only the first write valgrind gives me this cryptic branching off of uninitialized variable. After the first write valgrind no longer complains of this issue. Is there something missing in LWS init function shown below? Or is this normal for LWS?
2021-10-25T13:46:56-04:00 : Write:{"protocol": "json", "version": 1 } 37
==911== Thread 6:
==911== Conditional jump or move depends on uninitialised value(s)
==911== at 0x4886530: ??? (in /usr/lib/libwebsockets.so.15)
==911== by 0x48901A3: ??? (in /usr/lib/libwebsockets.so.15)
==911== by 0x488678F: lws_write (in /usr/lib/libwebsockets.so.15)
==911== by 0x1582BB: HostComm::SocketComm::socketComm::lwsClientWriteableHandler(lws*) (socketComm.cpp:1896)
==911== by 0x1575B7: HostComm::SocketComm::socketComm::internalWebsocketStateMachine(lws*, lws_callback_reasons, void*, void*, unsigned long) (socketComm.cpp:1640)
==911== by 0x159DAB: HostComm::SocketComm::socketComm::websocketsStateMachine(lws*, lws_callback_reasons, void*, void*, unsigned long) (socketComm.h:431)
==911== by 0x488AA77: ??? (in /usr/lib/libwebsockets.so.15)
==911== by 0x4889913: lws_handle_POLLOUT_event (in /usr/lib/libwebsockets.so.15)
==911== by 0x48905EF: ??? (in /usr/lib/libwebsockets.so.15)
==911== by 0x4889FC3: lws_service_fd_tsi (in /usr/lib/libwebsockets.so.15)
==911== by 0x48A2B83: ??? (in /usr/lib/libwebsockets.so.15)
==911== by 0x488A0E3: lws_service (in /usr/lib/libwebsockets.so.15)
==911==
==911== (action on error) vgdb me ...
Here is the init routine.
/**
* \brief Initiates the WS connection.
* \return Returns 0 on success otherwise -1
*/
int socketComm::connectWS( const char * url, int port )
{
int retValue = ERROR_NONE;
char path[PATH_MAX_SIZE] = { 0 };
if ( url != nullptr )
{
this->_lwsCloseRequested = false;
this->_lwsStarted = false;
this->_httpStarted = false;
if( this->_lwsInit == false )
{
// Memset both ctx creation and client info
memset( &this->_wsCtxCreationInfo, 0, sizeof( this->_wsCtxCreationInfo ) );
memset( &this->_wsClientConnectInfo, 0, sizeof( this->_wsClientConnectInfo ) );
this->_wsClientConnectInfo.port = port;
this->_wsClientConnectInfo.address = url;
( void ) strncpy( path, this->_serverPath, ( PATH_MAX_SIZE - 1 ) );
( void ) strncat( path, this->_connectionID.c_str( ), ( PATH_MAX_SIZE - 1 - strlen( path ) ) );
this->_wsClientConnectInfo.path = path;
if ( _use_wss == false )
{
// Don't use SSL for this connection
this->_wsClientConnectInfo.ssl_connection = 0;
}
else
{
// Use SSL for this connection
this->_wsClientConnectInfo.ssl_connection = 1;
}
// Set up the context creation info
// We don't want this client to listen
this->_wsCtxCreationInfo.port = CONTEXT_PORT_NO_LISTEN;
// Use our protocol list
this->_wsCtxCreationInfo.protocols = this->_protocols;
// Set the gid and uid to -1, isn't used much
this->_wsCtxCreationInfo.gid = -1;
this->_wsCtxCreationInfo.uid = -1;
// Use our extensions list
this->_wsCtxCreationInfo.extensions = _extensions;
// Pass a copy of our class to be used in the callback.
this->_wsCtxCreationInfo.user = static_cast<void*>(this);
// Create the context with the info
this->_wsCtx = lws_create_context( &this->_wsCtxCreationInfo );
if ( this->_wsCtx == nullptr )
{
this->setInternalError( CREATE_ERROR( SOCK_ERR_CTX ) );
retValue = -1;
}
else
{
// Set up the client creation info
// Use our created context
this->_wsClientConnectInfo.context = this->_wsCtx;
// Set the connections host to the address
this->_wsClientConnectInfo.host = this->_wsClientConnectInfo.address;
// Set the connections origin to the address
this->_wsClientConnectInfo.origin = this->_wsClientConnectInfo.address;
// IETF version is -1 (the latest one)
this->_wsClientConnectInfo.ietf_version_or_minus_one = -1;
// which protocol to use.
this->_wsClientConnectInfo.protocol = this->_protocols[PROTOCOL_WS].name;
// The created client should be fed inside the wsi_test variable
this->_wsClientConnectInfo.pwsi = &this->_wsInterface;
#if( SOCKET_DEBUG == 1)
string msg;
msg = string( "Connecting to " ) + string( "ws://" ) + this->_wsClientConnectInfo.address;
msg += ":" + to_string( this->_wsClientConnectInfo.port );
LOG_DEBUG( msg );
#endif
this->_lwsInit = true;
}
}
// If we are already inited then go head and connect.
if( ( this->_lwsInit == true ) && ( this->_wsCtx != nullptr ) )
{
// Connect with the client info
lws_client_connect_via_info( &this->_wsClientConnectInfo );
if ( this->_wsInterface == nullptr )
{
// Log and store an internal error.
this->setInternalError( CREATE_ERROR( SOCK_ERR_CONNECT ) );
retValue = -1;
}
else
{
// Make sure that LWS service is doing things.
this->setTimer( 500, false );
this->_lwsStarted = true;
}
}
else
{
// Log and store an internal error.
this->setInternalError( CREATE_ERROR( SOCK_ERR_CONNECT ) );
retValue = -1;
}
}
else
{
this->setInternalError( CREATE_ERROR( NULL_PTR_ERROR ) );
retValue = -1;
}
return ( retValue );
}
Here is the LWS callback
/**
* \brief Websocket state machine used by LWS to handle the events coming out of
* the library.
*
* \returns An error if one occurred during the connection.
*/
int socketComm::internalWebsocketStateMachine( struct lws* wsi,
lws_callback_reasons reason,
void *user, void* in, size_t len )
{
int retValue = ERROR_NONE;
// The buffer holding the data to send
// NOTICE: data which is sent always needs to have a certain amount of memory (LWS_PRE) preserved for headers
char * bufDataStart = &this->_rxBuf[LWS_PRE];
int count = 0;
int copySize = MAX_MSG_SIZE;
std::vector<uint8_t> rxMsg;
#if( SOCKET_DEBUG == 1 )
string infomsg;
// The socket is writable quite often
if( ( reason != LWS_CALLBACK_CLIENT_WRITEABLE ) && ( reason != LWS_CALLBACK_TIMER ) )
{
LOG_DEBUG( to_string( reason ) );
}
#endif
if( wsi != nullptr )
{
// For which reason was this callback called?
switch ( reason )
{
// Handles errors in both connections
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: // 1
retValue = this->lwsClientConnectionErrorHandler( wsi,
in );
break;
// The connection was successfully established
case LWS_CALLBACK_CLIENT_ESTABLISHED: // 3
#if( SOCKET_DEBUG == 1 )
LOG_DEBUG( "[PROTOCOL_WS] Connection to server established.\n" );
#endif
// Tell LWS to callback on writable
lws_callback_on_writable( wsi );
break;
// The connection closed
case LWS_CALLBACK_CLOSED: // 4
#if( SOCKET_DEBUG == 1 )
LOG_DEBUG( "[PROTOCOL_WS] Connection closed.\n" );
#endif
break;
// Our client received something Websockets
case LWS_CALLBACK_CLIENT_RECEIVE: // 8
retValue = this->lwsClientReceiveHandler( in, len );
break;
// The server notifies us that we can write data
case LWS_CALLBACK_CLIENT_WRITEABLE: // 10
// Handle writable
retValue = this->lwsClientWriteableHandler( wsi );
break;
// Used by our HTTP client to tell the server we are sending json and a length of 0
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: // 24
retValue = this->lwsHTTPHandshakeHandler( wsi,
reason,
user,
in,
len );
break;
// last call where a wsi is valid
case LWS_CALLBACK_WSI_DESTROY:
// Protection to make sure we are not servicing a null.
if( wsi == this->_wsInterface )
{
this->_lwsStarted = false;
}
else
{
if( wsi == this->_httpInterface )
{
this->_httpStarted = false;
}
}
break;
// Response status to a post.
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: // 44
// This is the HTTP Status.
this->_httpStatus = ( int ) lws_http_client_http_response( wsi );
#if( SOCKET_DEBUG == 1 )
LOG_DEBUG("HTTP_Connected with server response: " + to_string( ( int )lws_http_client_http_response( wsi ) ) );
#endif
retValue = lws_callback_http_dummy( wsi, reason, user, in, len );
break;
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: // 45
retValue = this->lwsHTTPCloseHandler( wsi,
reason,
user,
in,
len );
break;
// Callback telling us there might be something in the buffer.
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: // 46
#if( SOCKET_DEBUG == 1 )
LOG_DEBUG( "LWS_CALLBACK_RECEIVE_CLIENT_HTTP" );
#endif
// This is a call back saying that we need to read. Should read the
// Max amount then when the callback happens it will give an actual
// Length.
this->_count = MAX_MSG_SIZE;
(void)memset( bufDataStart, 0, this->_count );
retValue = lws_http_client_read( wsi, &bufDataStart, &this->_count );
break;
// HTTP done
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: // 47
#if( SOCKET_DEBUG == 1 )
LOG_DEBUG( "LWS_CALLBACK_COMPLETED_CLIENT_HTTP" );
#endif
// Because we are only sending the one message we need to cancel servicing this
// context.
lws_cancel_service( lws_get_context( wsi ) );
retValue = lws_callback_http_dummy( wsi, reason, user, in, len );
break;
/* Call back that actually reads */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: // 48
#if( SOCKET_DEBUG == 1 )
// Read the data and push it onto our rx buffer.
LOG_DEBUG( "Negotiate RECEIVE_CLIENT_HTTP_READ: read " + to_string( len ) );
#endif
if( ( len > 0 ) && ( in != nullptr ) )
{
rxMsg.assign( (uint8_t*)in, &((uint8_t*)in)[len] );
this->addRXMsg( rxMsg, &count );
}
retValue = lws_callback_http_dummy( wsi, reason, user, in, len );
break;
case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE: // 57
#if( SOCKET_DEBUG == 1 )
LOG_DEBUG( "LWS_CALLBACK_CLIENT_HTTP_WRITEABLE" );
#endif
// We do not write body data in this state machine
retValue = lws_callback_http_dummy( wsi, reason, user, in, len );
break;
case LWS_CALLBACK_TIMER: // 73
if( this->_lwsStarted == true )
{
this->setTimer( 500, false );
}
else
{
if( this->_httpStarted == true )
{
this->setTimer( 500, true );
}
}
break;
case LWS_CALLBACK_CLIENT_CLOSED: // 75
retValue = internalSendNotify( COMM_SOCKET_WS_DISCONNECTED );
break;
default:
/*
* We can get extra callbacks here, if nothing to do,
* then do nothing.
*/
break;
}
}
if( this->_lwsCloseRequested == true )
{
retValue = -1;
this->_lwsCloseRequested = false;
}
return ( retValue );
}
Here is the specific function that was calling the write routine.
/**
* \brief Handler for LWS client receive message.
*
* \returns An error if one occurred during the operation.
*/
int socketComm::lwsClientWriteableHandler( struct lws * wsi )
{
std::vector<uint8_t> txMsg;
int messageCount = 0;
// The buffer holding the data to send
// NOTICE: data which is sent always needs to have a certain amount of memory (LWS_PRE) preserved for headers
memset( this->_txBuf, 0, sizeof( this->_txBuf ) );
// See if there is a message on the buffer.
int retValue = this->getTxMsg( &txMsg, &messageCount );
if( messageCount >= 0 )
{
if( txMsg.size( ) > 0 )
{
// Lets try not to blow stacks
int copySize = ( txMsg.size() > ( MAX_MSG_SIZE - 1 ) ) ? ( MAX_MSG_SIZE - 1 ) : txMsg.size();
/* copy our data over to the send buffer and send it out */
(void)memcpy( &this->_txBuf[LWS_PRE], txMsg.data(), copySize );
#if( SOCKET_DEBUG == 1 )
std::string infomsg = string("Write:") + string(&this->_txBuf[LWS_PRE]) + string(" ") + to_string( copySize );
// Only log small messages.
if( copySize < 3048 )
{
LOG_DEBUG( infomsg );
}
#endif
if( wsi != nullptr )
{
// Write the buffer from the LWS_PRE index + 128 (the buffer size)
int numBytes = lws_write( wsi,
(unsigned char *)&(this->_txBuf[LWS_PRE]),
copySize,
LWS_WRITE_TEXT);
if( ( messageCount > 0 ) && ( wsi != nullptr ) )
{
// Tell websockets we have more messages to send.
lws_callback_on_writable( wsi );
}
}
}
}
return( retValue );
}
Output when track-origins is enabled
==1799== Thread 6:
==1799== Conditional jump or move depends on uninitialised value(s)
==1799== at 0x4886530: ??? (in /usr/lib/libwebsockets.so.15)
==1799== by 0x48901A3: ??? (in /usr/lib/libwebsockets.so.15)
==1799== by 0x488678F: lws_write (in /usr/lib/libwebsockets.so.15)
==1799== by 0x158A33: HostComm::SocketComm::socketComm::lwsClientWriteableHandler(lws*) (socketComm.cpp:1912)
==1799== by 0x157CDF: HostComm::SocketComm::socketComm::internalWebsocketStateMachine(lws*, lws_callback_reasons, void*, void*, unsigned long) (socketComm.cpp:1646)
==1799== by 0x15A5BF: HostComm::SocketComm::socketComm::websocketsStateMachine(lws*, lws_callback_reasons, void*, void*, unsigned long) (socketComm.h:431)
==1799== by 0x488AA77: ??? (in /usr/lib/libwebsockets.so.15)
==1799== by 0x4889913: lws_handle_POLLOUT_event (in /usr/lib/libwebsockets.so.15)
==1799== by 0x48905EF: ??? (in /usr/lib/libwebsockets.so.15)
==1799== by 0x4889FC3: lws_service_fd_tsi (in /usr/lib/libwebsockets.so.15)
==1799== by 0x48A2B83: ??? (in /usr/lib/libwebsockets.so.15)
==1799== by 0x488A0E3: lws_service (in /usr/lib/libwebsockets.so.15)
==1799== Uninitialised value was created by a heap allocation
==1799== at 0x4848414: operator new(unsigned long) (vg_replace_malloc.c:334)
==1799== by 0x12109F: HostComm::hostComm::hostComm() (hostComm.cpp:46)
==1799== by 0x192597: SM::sysMgr::sysMgr() (sysMgr.cpp:42)
==1799== by 0x19ECEF: __static_initialization_and_destruction_0(int, int) (sysMgr.cpp:34)
==1799== by 0x19EFE7: _GLOBAL__sub_I__ZN2SM5smMgrE (sysMgr.cpp:3740)
==1799== by 0x1AE50F: __libc_csu_init (elf-init.c:88)
==1799== by 0x5E4435B: (below main) (libc-start.c:264)
==1799==
==1799== (action on error) vgdb me ...
==1799== Continuing ...
2021-10-26T09:15:07-04:00 : 8