Handling memory exhausted in Windows Qt app - c++

My application can use a lot of memory and I want to be able to handle running out of memory gracefully. So I do this:
bool Application::notify( QObject* receiver, QEvent* event )
{
bool done = true;
try
{
done = QApplication::notify( receiver, event );
}
catch ( std::bad_alloc& ex )
{
releaseMemory();
qWarning() << "bad_alloc exception: " << ex.what();
m_outOfMemoryDlg->exec();
exit( 1 );
}
catch ( const std::exception& ex )
{
releaseMemory();
qWarning() << "exception: " << ex.what();
criticalMessage( nullptr, QString( "%1 has to close due to an exception. Please contact support." ).arg( APP_NAME ) );
exit( 2 );
}
catch ( ... )
{
releaseMemory();
qWarning() << "exception";
criticalMessage( nullptr, QString( "%1 has to close. Please contact support." ).arg( APP_NAME ) );
exit( 3 );
}
return done;
}
Where m_outOfMemoryDlg is a QDialog with a helpful message I create and hide at startup. This all works fine on macOS. I get a std::bad_alloc exception, the QDialog appears and the program shuts gracefully. But on Windows the whole OS just locks. The screen is frozen and I have to power off and back on to make it responsive.
In my .pro file I added:
CONFIG += exceptions
win32 {
QMAKE_CXXFLAGS_EXCEPTIONS_ON = /EHa
QMAKE_CXXFLAGS_STL_ON = /EHa
}
I also added:
#ifdef Q_OS_WIN
#include <new.h>
LONG WINAPI
exceptionFilter( struct _EXCEPTION_POINTERS* exceptionInfo )
{
if ( exceptionInfo )
{
EXCEPTION_RECORD* er = exceptionInfo->ExceptionRecord;
if ( er )
{
qWarning() << "Windows exception: " << er->ExceptionCode;
}
}
exit( 4 );
return EXCEPTION_EXECUTE_HANDLER;
}
int outOfMemory( size_t )
{
qWarning() << "Out of memory";
exit( 5 );
return 0;
}
#endif
Application::Application( int& argc, char** argv )
: QApplication( argc, argv )
{
#ifdef Q_OS_WIN
SetUnhandledExceptionFilter( exceptionFilter );
_set_new_handler( outOfMemory );
#endif
...
}
As per https://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus . Still no luck. Any ideas?
I am using Qt 5.15.2 on Windows 10.

Related

Unable to receive via QUdpSocket multicast

Unable to receive via QUdpSocket multicast.
To be precise, it cannot be received if the Internet is enabled.
However, it may work fine on other PCs. (Some PCs don't work.)
There is no significant difference in those environments.
On Wireshark, I could see the data and on SocketDebugger, I could receive it.
Why is this so strange?
My environment
OS: Windows10
Qt: 5.15.0 MinGW
Peripheral equipment: LUD-U3-AGH
udp.ccp
void Udp::fnUdpSetting(QString localIP,quint16 multicastPort,QString multicastIP)
{
m_pUdpSockRecv = new QUdpSocket(this);
connect(m_pUdpSockRecv, SIGNAL( readyRead() ), this, SLOT( fnUdpRecvData() ));
if( m_pUdpSockRecv->bind( QHostAddress( localIP ) , multicastPort, QUdpSocket::DefaultForPlatform) ){
if( m_pUdpSockRecv->joinMulticastGroup( QHostAddress( multicastIP ) )) {
qDebug() << "Connection Success";
} else {
qDebug() << "Join Error";
}
}
else {
qDebug() << "Bind Error";
}
}
void Udp::fnUdpRecvData()
{
qDebug() << "OK";
}

Grpc access violation on client

I'm in the process of messing around with GRPC. Currently I'm using a C# web application as my GRPC server and I'm using a C++ console application as the client.
I was able to successfully connect and communicate with the server with no issue. The problem arises when
I exit the C++ console client application. Upon exiting an Access Violation is thrown.
Stack trace
MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::thread_body
MeterReaderClientCpp.exe!__acrt_lock
ntdll.dll!RtlpWaitOnCriticalSection()
ntdll.dll!RtlpEnterCriticalSectionContended()
ntdll.dll!RtlEnterCriticalSection()
MeterReaderClientCpp.exe!__acrt_lock(__acrt_lock_id _Lock) Line 55
MeterReaderClientCpp.exe!_free_dbg(void * block, int block_use) Line 1019
MeterReaderClientCpp.exe!free(void * block) Line 32
MeterReaderClientCpp.exe!gpr_free(void * p) Line 53
MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::destroy_thread() Line 142
MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::Join() Line 112
MeterReaderClientCpp.exe!grpc_core::Thread::Join() Line 147
MeterReaderClientCpp.exe!gc_completed_threads() Line 74
MeterReaderClientCpp.exe!stop_threads() Line 331
MeterReaderClientCpp.exe!grpc_timer_manager_set_threading(bool threaded) Line 351
MeterReaderClientCpp.exe!grpc_shutdown_internal_locked() Line 175
MeterReaderClientCpp.exe!grpc_shutdown_internal(void * __formal) Line 208
MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::thread_body(void * v) Line 128
GRPC Client
int main( )
{
using namespace MeterReaderWeb::Services;
using namespace google::protobuf::util;
using namespace google::protobuf;
std::cout << "Press enter\n";
std::cin.ignore( );
std::cout << "Calling Grpc service\n";
std::fstream file{ R"(C:\Certificates\certificate.cer)", std::ios::in | std::ios::beg };
if ( !file.is_open( ) )
{
std::cerr << "Failed to open file\n";
return 1;
}
std::stringstream buffer;
buffer << file.rdbuf( );
grpc::SslCredentialsOptions options;
options.pem_root_certs = buffer.str( );
auto credentials{ grpc::SslCredentials( options ) };
auto channel{ grpc::CreateChannel( "localhost:5001", credentials ) };
auto stub{ MeterReadingService::NewStub( channel ) };
ReadingPacket packet;
packet.set_status( ReadingStatus::METER_READER_SUCCESS );
packet.set_notes( "Here are some random notes" );
auto message{ packet.add_readings( ) };
message->set_customer_id( 1 );
message->set_reading_value( 10001 );
auto timestamp{ message->mutable_reading_time( ) };
timestamp->CopyFrom( TimeUtil::GetCurrentTime( ) );
grpc::ClientContext context;
StatusMessage response;
if ( auto status{ stub->AddReading( &context, packet, &response ) }; status.ok( ) )
{
std::cout << "Added reading successfully\n";
auto responseStatus{ response.status( ) };
if ( responseStatus == ReadingStatus::METER_READER_SUCCESS )
{
std::cout << "Server status: success\n"
<< "Message: " << response.message( ) << '\n';
}
}
else
{
std::cerr << "Error: " << status.error_message( ) << '\n';
std::cerr << "Error Details: " << status.error_details( ) << '\n';
}
std::cin.ignore( );
}
I heavily used the GRPC route_guide_client.cc as a guide to help me write the above application.
I've tried adding calls to both grpc_init( ) and grpc_shutdown( ) even though their client examples don't contain either calls. But adding those had no effect.
What (if anything) am I missing here? Did I forget to call/populate something that the framework is attempting to clean up upon application exit?
OK I believe I've found what was causing the issue.
In my original post I said:
I've tried adding calls to both grpc_init( ) and grpc_shutdown( ) even though
the client examples don't contain either calls. But
adding those had no effect."
This was true, but after re-reading the documentation for grpc_shutdown( ) i noticed this (emphasis mine):
The last call to grpc_shutdown will initiate cleaning up of grpc
library internals, which can happen in another thread. Once the
clean-up is done, no memory is used by grpc, nor are any instructions
executing within the grpc library. Prior to calling, all application
owned grpc objects must have been destroyed.
This is where I think I went wrong. I was calling grpc_shutdown() while I still had grpc objects in scope. To correct I scoped the grpc objects and then called grpc_shutdown() once that scope was exited. This seems to have corrected the issue.
New Grpc Client
int main( )
{
std::cout << "Press enter\n";
std::cin.ignore( );
std::cout << "Calling Grpc service\n";
grpc_init( );
{ // <- Intentionally added scope here.
grpc::SslCredentialsOptions options;
if ( auto certificate{ ReadCertificate( ) } )
options.pem_root_certs = std::move( certificate ).value( );
else return 1;
auto credentials{ grpc::SslCredentials( options ) };
auto channel{ grpc::CreateChannel( "localhost:5001", credentials ) };
auto stub{ MeterReadingService::NewStub( channel ) };
std::cout << "Sending single packet\n";
SendPacket( stub.get( ), 8000 );
std::cout << "Sending multiple packets\n";
StreamDiagnostics( stub.get( ), 3 );
}
std::cout << "Shutting down library\n";
grpc_shutdown_blocking( );
std::cout << "Shut down complete press enter to exit\n";
std::cin.ignore( );
}

LibSSH C++ wrapper - Basic remote connection segfaults when leaving scope

I'm new to libssh and trying to connect to a remote machine to run some commands. All of the connections and commands return without error, but then the program segfaults when leaving scope. What am I doing wrong?
Code
#include <string>
#include <iostream>
using namespace std;
#define SSH_NO_CPP_EXCEPTIONS
#include <libssh/libsshpp.hpp>
int main()
{
ssh::Session session;
//Set options
session.setOption(SSH_OPTIONS_HOST, "192.168.200.101");
session.setOption( SSH_OPTIONS_USER, "user" );
//Connect to host
session.connect();
//Authenticate user
session.userauthPassword( "password" );
//Open channel
ssh::Channel channel( session );
channel.openSession();
//Do something
channel.requestExec( "ps_aux" );
//Close channel
channel.sendEof();
channel.close();
//Disconnect
session.disconnect();
return 0;
}
GDB Trace
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff3a70a2f in ssh_channel_free () from /usr/local/lib/libssh.so.4
(gdb) where
#0 0x00007ffff3a70a2f in ssh_channel_free () from /usr/local/lib/libssh.so.4
#1 0x000000000059f436 in ssh::Channel::~Channel() ()
#2 0x000000000059e603 in main ()
After beating on it awhile, we have a working solution. The first hurdle was recognizing that the remote host must be a "known host". After that, for me, it was necessary to then source the environment before running my executable.
Last, I needed to give it some time to crunch with sleep( 1 ). Enjoy.
#include <iostream>
using namespace std;
#include <libssh/libsshpp.hpp>
int main()
{
int port = 22;
//Can use SSH_LOG_PROTOCOL here for verbose output
int verbosity = SSH_LOG_NOLOG;
ssh::Session session;
try
{
session.setOption( SSH_OPTIONS_LOG_VERBOSITY, &verbosity );
session.setOption( SSH_OPTIONS_PORT, &port );
session.setOption( SSH_OPTIONS_USER, "user" );
session.setOption( SSH_OPTIONS_HOST, "192.168.52.101" );
session.connect();
if( session.isServerKnown() != SSH_SERVER_KNOWN_OK )
{
if( session.writeKnownhost() != SSH_OK )
{
cout << "writeKnownHost failed" << endl;
}
else
{
session.connect();
}
}
if( session.userauthPassword( "password" ) != SSH_AUTH_SUCCESS )
{
cout << "failed auth" << endl;
}
ssh::Channel channel( session );
channel.openSession();
//Source environment if necessary, run executable
channel.requestExec( "source /path/to/set_env.sh; /path/to/executable/..." );
channel.close();
channel.sendEof();
//Unfortunate brute force step, the exec call needed some time
sleep( 1 );
}
catch( ssh::SshException e )
{
std::cout << "Error during connection : ";
std::cout << e.getError() << std::endl;
}
return 0;
}

Unable to migrate simple read/write serial port code from boost::asio::serial_port to QSerialPort

I need a very straightforward piece of code that connects a serial port (where a home made device is connected), writes some data to it and then reads the reply. The written data turns ON a LED on the device (which makes it easy to see if data sent by the PC is actually received by the device)
I have it working with boost/asio and need to port it to QSerialPort. With QSerialPort, I'm able to connect, send data (and I know it's sent because the LED turns ON), but cannot receive any...
Here is the boost asio code working:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/serial_port_base.hpp>
#include <boost/thread.hpp>
static std::vector<char> sReceived;
void readThread( boost::asio::serial_port* port )
{
try
{
char read;
while ( boost::asio::read( *port, boost::asio::buffer(&read,1) ) == 1 )
sReceived.push_back( read );
}
catch (...)
{
// connection most likely closed
}
}
int main( int argc, char* argv[] )
{
int res = 1;
if ( argc != 2 )
{
std::cout << "Specify COM port name as first and unic parameter" << std::endl;
}
else
{
try
{
std::string portName = argv[1];
boost::asio::io_service ioservice;
boost::asio::serial_port port( ioservice );
port.open( portName );
port.set_option( boost::asio::serial_port_base::baud_rate( 921600 ) );
port.set_option( boost::asio::serial_port_base::parity( boost::asio::serial_port_base::parity::none ) );
port.set_option( boost::asio::serial_port_base::stop_bits( boost::asio::serial_port_base::stop_bits::one ) );
port.set_option( boost::asio::serial_port_base::character_size( 8 ) );
port.set_option(
boost::asio::serial_port_base::flow_control(
boost::asio::serial_port_base::flow_control::hardware ) );
if ( port.is_open() )
{
boost::thread thrd( readThread, &port );
static const size_t requestMessageSize = 10;
unsigned char request[requestMessageSize] = { 0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0x00, 0xBE, 0x0B, 0x00 };
if ( boost::asio::write( port,
boost::asio::buffer(request,requestMessageSize) ) == requestMessageSize )
{
boost::this_thread::sleep( boost::posix_time::milliseconds( 1000 ) );
if ( !sReceived.empty() )
{
std::cout << "Received:" << std::hex;
for ( size_t i = 0; i != sReceived.size(); ++i )
{
std::cout << " 0x" << static_cast<int>( sReceived[i] );
}
std::cout << std::endl;
std::cout << "Could open port, send and receive data" << std::endl;
res = 0;
}
else
{
std::cout << "Could open port, send data, but did not received any reply" << std::endl;
}
}
else
{
std::cout << "Could not send data" << std::endl;
}
port.close();
}
else
{
std::cout << "Could not open connection with " << portName << std::endl;
}
}
catch (...)
{
std::cout << "Exception raised by boost asio" << std::endl;
}
}
return res;
}
And here is the Qt code (not working):
#include <QApplication>
#include <QThread>
#include <QMessageBox>
#include <QtSerialPort/QSerialPort>
#include <sstream>
int main( int argc, char* argv[] )
{
QApplication app(argc, argv);
int res = 1;
if ( argc != 2 )
{
QMessageBox::critical( NULL, "Invalid argument", "Specify COM port name as first and unic parameter" );
}
else
{
QString portName = argv[1];
QSerialPort port( portName );
if ( port.open( QSerialPort::ReadWrite ) )
{
if ( port.setBaudRate( 921600 ) &&
port.setFlowControl( QSerialPort::HardwareControl ) &&
port.setStopBits( QSerialPort::OneStop ) &&
port.setParity( QSerialPort::NoParity ) &&
port.setDataBits( QSerialPort::Data8 ) )
{
static const size_t requestMessageSize = 10;
char request[requestMessageSize] = { 0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0x00, 0xBE, 0x0B, 0x00 };
if ( port.write( request, requestMessageSize ) == requestMessageSize )
{
QThread::sleep( 1 );
QByteArray reply = port.readAll();
if ( !reply.isEmpty() )
{
std::stringstream str;
str << "Received:" << std::hex;
for ( size_t i = 0; i != reply.size(); ++i )
{
str << " 0x" << static_cast<int>( reply.at(i) );
}
str << std::endl;
str << "Could open port, send and receive data" << std::endl;
QMessageBox::information( NULL, "OK", str.str().c_str() );
res = 0;
}
else
{
QMessageBox::critical( NULL, "Error", "Could open port, send data, but did not received any reply" );
}
}
else
{
QMessageBox::critical( NULL, "Error", "Unable to send request to port" );
}
}
else
{
QMessageBox::critical( NULL, "Error", "Unable to configure port" );
}
port.close();
}
else
{
QMessageBox::critical( NULL, "Unable to connect", QString("Could not open connection with %1").arg( portName ) );
}
}
return res;
}
When I run both codes with the good port name passed as parameter:
boost's one lights the LED ON and reports Received: 0x.....Could open port, send and receive data
Qt's one lights the LED ON, but reports Could open port, send data, but did not received any reply
What's wrong with my QSerialPort code? Why is it able to send data but fails to receive any?
port.readAll() doesn't block until something is read, in fact no data will ever be sent or read available until you return to the event loop or do a waitForReadyRead to receive data and waitForBytesWritten to write out the buffer.
so replace the Thread::sleep(1) with port.waitForBytesWritten(1000);port.waitForReadyRead(1000);

Segmentation fault when catching exceptions in a libpthread linked app ( linux, C++ )

I have this piece of code here:
These are functions used to create and stop a pthread:
void WatchdogController::conscious_process_handler_start() {
if ( debug ) cout << "WatchdogController: starting conscious process thread" << endl;
cn_pr_thread_active = true;
if ( pthread_create( &cn_pr_thread, NULL, conscious_process_handler, this ) < 0 ) {
cn_pr_thread_active = false;
throw WatchdogException( "Unable to start new thread" );
}
}
void WatchdogController::conscious_process_handler_stop() {
if ( debug ) cout << "WatchdogController: stopping conscious process thread" << endl;
cn_pr_thread_active = false;
int *retval;
pthread_join( cn_pr_thread, ( void ** )&retval );
if ( *retval < 0 ) {
delete retval;
string err = string( "Error returned by conscious_process_handler(): " ) + string( pthread_err );
throw WatchdogException( err.c_str() );
}
delete retval;
}
I use select() in function passed to pthread, and when stopped it returns an error resulting in return value from pthread being negative, but that's not the issue, I'll fix it later - problem is, that when the exception is thrown here:
throw WatchdogException( err.c_str() );
and caught here:
try {
watchdog_controller->hardware_watchdog_stop();
watchdog_controller->unconscious_process_handler_stop();
watchdog_controller->conscious_process_handler_stop();
}
catch ( HardwareWatchdogException &e ) {
cerr << "Error stopping hardware watchdog!" << endl;
cerr << e.get_reason() << endl;
string err = string( "Exception thrown by hardware watchdog controller" ) + string( e.get_reason() );
if ( log ) write_log( err.c_str() );
delete watchdog_controller;
return -1;
}
catch ( WatchdogException &e ) {
cerr << "Exception cought when exiting!" << endl;
cerr << e.get_reason() << endl;
string err = string( "Exception cought when exiting" ) + string( e.get_reason() );
if ( log ) write_log( err.c_str() );
delete watchdog_controller;
return -1;
}
I get segmentation fault then trying to access the object at this point:
cerr << e.get_reason() << endl;
What could be the reason?
Reference &e points to something, but it seems as if the address was invalid.
Here's the exception class:
class WatchdogException {
public:
/**
#brief Default constructor
*/
WatchdogException() : reason() {
}
/**
#brief Overloaded constructor - setting the error message
#param why Error message
*/
WatchdogException( const char *why ) : reason( why ) {
}
/**
#brief The destructor
*/
virtual ~WatchdogException() {
}
/**
#brief A getter for the error message
#return Returns a string containing error description
*/
virtual std::string get_reason() const {
return reason;
}
protected:
/**
#var reason String containing the error message
*/
std::string reason;
};
I am guessing that you are not properly allocating memory for retval, or that somehow you are returning an invalid pointer from cn_pr_thread, and that is why you get a segmentation fault when you call pthread_join.
In WatchDogException's constructor, are you remembering the pointer to the c-string passed in or are you making a copy of it.
If you're simply storing the pointer then when "err" goes out of scope when the exception is thrown the pointer returned by c_str() will be bad, hence your seg fault when you try and use it.