Error handling (Linux, Qt 5.15)
-
I found a way which can help save the app critical data in case access vioation.
header:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <signal.h> #include <QMainWindow> #include <QMessageBox> #include <QString> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_bt_cause_mem_err_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
The code:
#include "mainwindow.h" #include "ui_mainwindow.h" struct sigaction sa; int save_data_to_disk() { QMessageBox mb; mb.setText("App abnormal ending - your data has been saved to disk"); mb.exec(); mb.setText("Critical vars are this: xxx, xxx, xxx, xxx"); mb.exec(); } //--------------------------------- void segfault_sigaction(int signal, siginfo_t *si, void *arg) { save_data_to_disk(); throw "close"; //without it the error can persist } //--------------------------------- MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); memset(&sa, 0, sizeof(struct sigaction)); sigemptyset(&sa.sa_mask); sa.sa_sigaction = segfault_sigaction; sa.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &sa, NULL); } //------------------------------------ MainWindow::~MainWindow() { delete ui; } //------------------------------ void MainWindow::on_bt_cause_mem_err_clicked() { int *tt = NULL; *tt = 123; } //------------------------------
This handling prevents data damages, but still the program cannot run further on. :-\ ;-)
void segfault_sigaction(int signal, siginfo_t *si, void *arg) { save_data_to_disk(); throw "close"; //without it the error can persist }
This is called "out of the frying pan into the fire"!
Neither of these statements is safe to execute from within a signal handler. Have you read up about this?
-
@Kent-Dorfman said in Error handling (Linux, Qt 5.15):
Allowing a null pointer exception/trap to occur is an indication of poor programming. It is expected that the professional programmer understand that dereferencing a null pointer is a fatal error.
For ignoring the the correct and sophisticated path of coding to prevent such errors, there is the fallback of catching the POSIX signal SIGSEGV that is triggered by the illegal instruction.You read unattentively - access violation is not nessesary follows a NULL pointer. And all I wanted is to learn a way to prevent my (QtCreator) program from crashing just in case. Bugs sometimes happen, you see - you are a bad programmer if you state the opposite.
You wrote about " there is the fallback of catching the POSIX signal SIGSEGV that is triggered by the illegal instruction" - please can you give me an example using my example: int *tt = NULL; *tt = 123;. Treat the error from my example in that way and show me your professionalism. Thank you.@qAlexKo said in Error handling (Linux, Qt 5.15):
You read unattentively - access violation is not nessesary follows a NULL pointer. And all I wanted is to learn a way to prevent my (QtCreator) program from crashing just in case. Bugs sometimes happen, you see - you are a bad programmer if you state the opposite.
You wrote about " there is the fallback of catching the POSIX signal SIGSEGV that is triggered by the illegal instruction" - please can you give me an example using my example: int *tt = NULL; *tt = 123;. Treat the error from my example in that way and show me your professionalism. Thank you.but no, dereferencing a null pointer IS an access violation on most modern architectures. While it is true that according to the language standards, it is undefined behaviour, the implementation of most virtual memory system machines triggers a SIGSEGV on such an operation.
For creating an example: nope. There are plenty of online examples that show how to create signal handlers, and in presenting one, I would be encouraging behaviour (in this specific case) that I don't agree with. Sorry.
I will tell you how to avoid your problem:
int myVar; int* const tt = &myVar; // prohibits changing the value of the tt pointer *tt = 1234;
To repeat, take steps to avoid dereferencing null pointers. Don't expect the machine to clean up after you.
-
@qAlexKo said in Error handling (Linux, Qt 5.15):
You read unattentively - access violation is not nessesary follows a NULL pointer. And all I wanted is to learn a way to prevent my (QtCreator) program from crashing just in case. Bugs sometimes happen, you see - you are a bad programmer if you state the opposite.
You wrote about " there is the fallback of catching the POSIX signal SIGSEGV that is triggered by the illegal instruction" - please can you give me an example using my example: int *tt = NULL; *tt = 123;. Treat the error from my example in that way and show me your professionalism. Thank you.but no, dereferencing a null pointer IS an access violation on most modern architectures. While it is true that according to the language standards, it is undefined behaviour, the implementation of most virtual memory system machines triggers a SIGSEGV on such an operation.
For creating an example: nope. There are plenty of online examples that show how to create signal handlers, and in presenting one, I would be encouraging behaviour (in this specific case) that I don't agree with. Sorry.
I will tell you how to avoid your problem:
int myVar; int* const tt = &myVar; // prohibits changing the value of the tt pointer *tt = 1234;
To repeat, take steps to avoid dereferencing null pointers. Don't expect the machine to clean up after you.
@Kent-Dorfman
But this doesn't protect if code might go:*(int *)tt = 1234; // or const_cast<int *>(tt) if that works here
;-)
-
void segfault_sigaction(int signal, siginfo_t *si, void *arg) { save_data_to_disk(); throw "close"; //without it the error can persist }
This is called "out of the frying pan into the fire"!
Neither of these statements is safe to execute from within a signal handler. Have you read up about this?
@JonB said in Error handling (Linux, Qt 5.15):
throw "close"; //without it the error can persist
}This is called "out of the frying pan into the fire"!
Neither of these statements is safe to execute from within a signal handler. Have you read up about this?Yes, the application will crash anyway, but as I showed you can save some important data before crashing..
-
@JonB said in Error handling (Linux, Qt 5.15):
throw "close"; //without it the error can persist
}This is called "out of the frying pan into the fire"!
Neither of these statements is safe to execute from within a signal handler. Have you read up about this?Yes, the application will crash anyway, but as I showed you can save some important data before crashing..
@qAlexKo said in Error handling (Linux, Qt 5.15):
but as I showed you can save some important data before crashing..
No, you can't! In the sense that you are not allowed/supposed to call what
save_data_to_disk()
will do from within a signal handler. Go read up! You are very restricted as to what is allowed, not much more than setting a flag variable. All the stuff you are going to do inside that "save" --- Qt UI stuff, writing to disk etc. --- is not safe to do inside a signal handler. It might work, or might not, it might write rubbish to your file, whatever. The fact that you might find it works when you test in your environment is "luck". Up to you whether you want to read up and take heed. -
@qAlexKo said in Error handling (Linux, Qt 5.15):
but as I showed you can save some important data before crashing..
No, you can't! In the sense that you are not allowed/supposed to call what
save_data_to_disk()
will do from within a signal handler. Go read up! You are very restricted as to what is allowed, not much more than setting a flag variable. All the stuff you are going to do inside that "save" --- Qt UI stuff, writing to disk etc. --- is not safe to do inside a signal handler. It might work, or might not, it might write rubbish to your file, whatever. The fact that you might find it works when you test in your environment is "luck". Up to you whether you want to read up and take heed.In the final, I can only once again to express my disappointment that Linux QtCreator doesn't provide standard means to make a big stable application. A big application as rule consists of many different branches and they can be independent, in a big extent. If one task has a hidden bug it, IMHO, must mean that the app must not crash and the other app branches must be able to continue their work after handling the error. In short Linux QT must learn how to handle any errors that can happen theoretically. Then a system can be called reliable.
You can say that sea ships must not get shell-holes and perfect captains must prevent such from happening. But reliable ships have partition walls, bilge pumps, means for hadnling shell-holes and even lifeboats. ;-) -
In the final, I can only once again to express my disappointment that Linux QtCreator doesn't provide standard means to make a big stable application. A big application as rule consists of many different branches and they can be independent, in a big extent. If one task has a hidden bug it, IMHO, must mean that the app must not crash and the other app branches must be able to continue their work after handling the error. In short Linux QT must learn how to handle any errors that can happen theoretically. Then a system can be called reliable.
You can say that sea ships must not get shell-holes and perfect captains must prevent such from happening. But reliable ships have partition walls, bilge pumps, means for hadnling shell-holes and even lifeboats. ;-) -
@qAlexKo
We have tried to explain to you that it has nothing to do with Qt libraries or Qt Creator.Maybe you could/should auto-save your valuable data on a regular timer, when the application is in a safe and consistent state?
@JonB said in Error handling (Linux, Qt 5.15):
We have tried to explain to you that it has nothing to do with Qt libraries or Qt Creator.
Maybe you could/should auto-save your valuable data on a regular timer, when the application is in a safe and consistent state?Well, actually, as we see QT can handle these severe errors, but on the primitive level. So it certainly has something with QT library.
As for constant saving of important data, yes is is also the way, but it is not as elegant as try/catch in Delphi/CBuilder during every attempt to do sometning with memory. I think memory manager must know the limits of allocated memory.
-
@JonB said in Error handling (Linux, Qt 5.15):
We have tried to explain to you that it has nothing to do with Qt libraries or Qt Creator.
Maybe you could/should auto-save your valuable data on a regular timer, when the application is in a safe and consistent state?Well, actually, as we see QT can handle these severe errors, but on the primitive level. So it certainly has something with QT library.
As for constant saving of important data, yes is is also the way, but it is not as elegant as try/catch in Delphi/CBuilder during every attempt to do sometning with memory. I think memory manager must know the limits of allocated memory.
@qAlexKo said in Error handling (Linux, Qt 5.15):
Well, actually, as we see QT can handle these severe errors, but on the primitive level. So it certainly has something with QT library.
No, it does not. Tried to explain multiple times it has nothing to do with Qt, but you just keep repeating it does. Your understanding of what Qt is is wrong. Qt is not a language. And C++ does not behave the way you would like it to, but that is not a Qt issue.
but it is not as elegant as try/catch in Delphi/CBuilder during every attempt to do sometning with memory
If you really feel this strongly about the way Delphi/CBuilder handles this (which btw only started out as checking for a null pointer, which I would have thought is a minor issue compared to all the other things which can go wrong with pointers) then I would suggest you stick with it to provide exactly what you want. No point switching to a different C++ compiler and then bemoaning that it behaves differently from the original one whose behaviour is what you require.
I think memory manager must know the limits of allocated memory.
Don't know what this means.
If you think that all C++ compilers/the C++ language ought behave the way Delphi/CBuilder does for this issue I suggest you write to the C++ standards committee and ask them to change the language's behaviour to your requirement.
-
@qAlexKo said in Error handling (Linux, Qt 5.15):
Well, actually, as we see QT can handle these severe errors, but on the primitive level. So it certainly has something with QT library.
No, it does not. Tried to explain multiple times it has nothing to do with Qt, but you just keep repeating it does. Your understanding of what Qt is is wrong. Qt is not a language. And C++ does not behave the way you would like it to, but that is not a Qt issue.
but it is not as elegant as try/catch in Delphi/CBuilder during every attempt to do sometning with memory
If you really feel this strongly about the way Delphi/CBuilder handles this (which btw only started out as checking for a null pointer, which I would have thought is a minor issue compared to all the other things which can go wrong with pointers) then I would suggest you stick with it to provide exactly what you want. No point switching to a different C++ compiler and then bemoaning that it behaves differently from the original one whose behaviour is what you require.
I think memory manager must know the limits of allocated memory.
Don't know what this means.
If you think that all C++ compilers/the C++ language ought behave the way Delphi/CBuilder does for this issue I suggest you write to the C++ standards committee and ask them to change the language's behaviour to your requirement.
@JonB said in Error handling (Linux, Qt 5.15):
If you really feel this strongly about the way Delphi/CBuilder handles this (which btw only started out as checking for a null pointer,
Look as an Access Violation handling can be realized withing a function (Linux QTcreator). My example looks not very pleasant but QT developers probably can make macros to make it look good. Yes, in the business of handling first were logjumps, then try/catch followed.
jmp_buf ape; void AcessViolationHandler(int signum) { _ML.p("AcessViolationHandler is called"); //this is my logger // Do stuff here then return to execution below longjmp(ape, 1); } //------------------ void Tmq_blf::on_actionAccess_Violation_tst_triggered() { struct sigaction act; struct sigaction oldact; memset(&act, 0, sizeof(act)); act.sa_handler = AcessViolationHandler; act.sa_flags = SA_NODEFER | SA_NOMASK; sigaction(SIGSEGV, &act, &oldact); int i = 10, *j=NULL; if (0 == setjmp(ape)) { *j = i; sigaction(SIGSEGV, &oldact, &act); } else { sigaction(SIGSEGV, &oldact, &act); /* handle SIGSEGV */ } QMessageBox bx; bx.setText("The app survived AccessViolation and continue to run"); bx.exec(); } //------------------