I need a gtest that will pass if sigabrt doesn't happen, but need to know if it does happen, or fail the test. How would I do that?
I was thinking of this sort of thing:
TEST_F(TestTest, testSigabrtDoesntHappen)
{
MyObject &myObject = MyObject::instance();
for(int i=0; i<2; i++){
myObject.doWork(); //this will sigabrt on the second try, if at all
ASSERT_TRUE(myObject);
}
ASSERT_TRUE(myObject);
}
So assuming a sigabrt would exit out of the test if it occurs, then we would get 3 test passes otherwise. Any other ideas?
Not on Window:
::testing::KilledBySignal(signal_number) // Not available on Windows.
You should look the guide.
It seems like that for me (not tested) :
TEST_F(TestTest, testSigabrtDoesntHappen)
{
MyObject &myObject = MyObject::instance();
for(int i=0; i<2; i++){
EXPECT_EXIT(myObject.doWork(), ::testing::KilledBySignal(SIGBART)), "Regex to match error message");
ASSERT_TRUE(myObject);
}
ASSERT_TRUE(myObject);
}
On Window:
You'll have to handle signal yourself with this kind of code:
// crt_signal.c
// compile with: /EHsc /W4
// Use signal to attach a signal handler to the abort routine
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
if (signal == SIGABRT) {
// abort signal handler code
} else {
// ...
}
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGABRT, SignalHandler);
abort(); //emit SIGBART ?
}
doc
But seriously if you have one time get a SIGBART running your code, there are some problems with your code that you have to remove before release the software.
But if you really want to debug your code (with googletest), use this with your debugger:
foo_test --gtest_repeat=1000 --gtest_break_on_failure
You can add others option to it, again : check the doc :)
Related
I have tried to write a program that run in ubuntu terminal .Program will open a new gnome terminal and run command in that new terminal to open new abcd.txt using vim.And then when i Ctrl+C in the first terminal which run the program ,new gnome terminal will shut vim down and have an announcement in the first terminal
I have tried system("`gnome-terminal`<< vim abcd.txt");
and this system("vim abcd.txt>>`gnome-terminal`");
but the new one terminal cannot recieve command
My full code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop=1;
void DEF()
{
system("kill -9 pidof vim");
loop=0;
}
void *subthreads(void *threadid)
{
loop=1;
long tid;
tid=(long)threadid;
system("`gnome-terminal`<< vim abcd.txt");
signal(SIGINT,DEF);
while(loop){}
pthread_exit(NULL);
}
void main()
{
int loop=1;
pthread_t threads;
int check;
long tID;
check= pthread_create(&threads,NULL,&subthreads,(void*)tID);
while(loop){}
printf("Ctrl+C is pressed!\n");
}
Not sure what you are trying to achieve in the end. But here are a few ideas, starting from your code:
The terminal command (in system()) should be something like Mark Setchell pointed out, like for example system("gnome-terminal -e vim file.txt");
The system() command is blocking further execution of your code, so the call to signal() is not happening until you terminate the system() call.
pidof is not working on my Linux system. I would use pkill <program>. Still, that would kill all running instances of , for example vim or your terminal.
You are declaring the variable loop in the global scope first and then redeclaring it in main(). If you really want to use it as a global variable, it should just be loop=1 in main().
You are not using the variable tid for anything.
Here is an improved version of your program, with additional printf calls to explain to the user what is happening. I also used xterm and nano because I don't have gnome-terminal, and I didn't want to interfere with my running instance of vim. But it still is maybe not exactly what you are trying to do. The main problem is that system("xterm -e sh &") is blocking and when you press Ctrl-C, that system call will terminate xterm so that the def() function will do nothing when it is called later.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop = 1;
void def()
{
printf("In def\n");
system("pkill xterm");
loop=0;
}
void *subthreads(void *threadid)
{
printf("Starting subthread\n");
loop = 1;
long tid;
tid = (long)threadid;
signal(SIGINT, def);
system("xterm -e sh -c nano &"); // Note: xterm will still exit when you press Ctrl-C
printf("Terminal exited in subthread\n");
while (loop);
printf("Exited loop in subthread\n");
pthread_exit(NULL);
}
void main()
{
pthread_t threads;
int check;
long tID;
check = pthread_create(&threads, NULL, &subthreads, (void*)tID);
printf("In main after thread creation\n");
while (loop);
printf("Ctrl+C is pressed!\n");
}
Another option is to use fork() instead of pthread to split into a separate process. (Note that processes are like separate applications while threads are processor threads in the same application.)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void def()
{
system("pkill nano");
printf("def(): Killed nano\n");
}
int subprocess()
{
signal(SIGINT, def);
pid_t parent_id = getpid(); // Get process ID of main process
fork(); // Fork into two identical copies of the running app.
if (getpid() != parent_id) { // The part in the if block is only done in the second process!
system("xterm -e sh -c nano &");
printf("subprocess(): system call ended in forked process\n");
exit(0);
}
}
int main()
{
subprocess();
printf("Entering while loop in main process\n");
while (1);
printf("Exited main thread\n");
}
The one flaw with this version is the same as the previous one: when Ctrl-C is pressed, xterm/nano is killed and def() will subsequently do nothing except catch any Ctrl-C done afterwards.
If you explain further what your final goal is, maybe I can give some suggestions.
Like, why do you want to start vim in a terminal from a C application and then kill vim? Do you want to kill the whole terminal or only vim?
I have a Linux program, that from time to time ends with a segmentation fault. The program is running periodically every hour, but the segmentation fault occurs only sometimes.
I have a problem to debug this, because if I run the program again with the same input, no error is reported and all is OK.
Is there a way, how to "report" in which part of the code error occured or what caused the problem?
The usual way is to have the crashing program generate a corefile and analyze this after the crash. Make sure, that:
the maximum corefile-size is big enough (i.e. unlimited) by calling ulimit -c unlimited in the shell, which starts the process.
The cwd is writable by the segfaulting process.
Then you can analyze the file with
gdb <exe> <corefile>
Since your code not crashing every time, you can use backtrace as well. Using this you can see the function call stack at the time of crash. There are many examples available. In my projects I normally use the following code for backtracing.
/*
* call reg_usr2 function from main
* gcc -rdynamic myfile.c -o output
*/
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <execinfo.h>
#define FILE_NAME "/tmp/debug"
#define MODE 0xFFFF
void dbgprint(int flag, char* fmt, ...)
{
if(flag & MODE) {
char buf[100];
va_list vlist;
FILE *fp = fopen(FILE_NAME,"a");
va_start(vlist, fmt);
vsnprintf( buf, sizeof( buf), fmt, vlist);
va_end( vlist);
fprintf(fp,"[%x]->%s\n", flag, buf);
fclose(fp);
}
}
/** Here is the code to print backtrace **/
void print_stack_trace ()
{
void *array[20];
size_t size;
char **strings;
size_t i;
size = backtrace (array, 20);
strings = backtrace_symbols (array, size);
dbgprint(0xFFFF, "Obtained %zd stack frames.", size);
dbgprint(0xFFFF, "-------------------------");
dbgprint(0xFFFF, "---------Backtrace-------");
for (i = 0; i < size; i++)
dbgprint (0xFFFF, "%s", strings[i]);
dbgprint(0xFFFF, "-------------------------");
free (strings);
}
void sig_handler(int signo)
{
FILE *fp = fopen(FILE_NAME,"a");
if (signo == SIGUSR2){
dbgprint(0xFFFF, "received SIGUSR2");
dbgprint(0xFFFF, "----------------");
}
print_stack_trace();
exit(0);
}
void reg_usr2()
{
if (signal(SIGUSR2, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGUSR2\n");
}
int main()
{
reg_usr2(); //should be first line of main after variables
//Code.....
return 0;
}
You can generate backtrace by catching SIGSEGV signal, and see where your application throw an invalid access.
see https://stackoverflow.com/a/77336/4490542
But there is more easier solution, try running your application with catchsegv
catchsegv './program args'
and better alternative, valgrind
valgrind --tool=none ./program args
#include "IRSensor.h"
#include "Turret.h"
#include "StepperButtonController.h"
#include "LoadBottleButton.h"
LoadBottleButton go(A3,1000);
void setup()
{
Serial.begin(9600);
Serial.println("Port Open");
}
void loop()
{
if(go.Read())
{
go.Monitor();
}
}
Above is the Main code
#ifndef LoadBottleButton_cpp
#define LoadBottleButton_cpp
#include "Arduino.h"
#include "ScaleObject.h"
#include "LoadBottleButton.h"
#include "Turret.h"
#include "StepperButtonController.h"
ScaleObject* so;
Turret* tPointer;
LoadBottleButton::LoadBottleButton(int pin, int debounce):StepperButtonController(pin,debounce)
{
}
void LoadBottleButton::Monitor()
{
Serial.println("In Monitor");
while(tPointer->getTurret().BottleCenterState==false)
{
Serial.println("In Monitor While Loop");
tPointer->Start();
SETUP = true;
load = true;
unload = !so->getScale().Empty();
Serial.println(load);
Serial.println(unload);
Serial.println(!so->getScale().Empty());
if(unload)
{
unload=!so->getScale().Empty();
}
else if(load && !so->getScale().Empty())
{
load = !tPointer->BottleCentered();
}
if(!load && !unload && SETUP)
{
tPointer->Stop();
SETUP = false;
}
}
}
#endif
And above is the LoadBottleButtonClass.cpp file.
#ifndef Turret_cpp
#define Turret_cpp
//#include "HX711.h"
#include "Turret.h"
#include "Arduino.h"
#include "StepperButtonController.h"
#include "ScaleObject.h"
#include "IRSensor.h"
//StepperButtonController Clear(9,1000);
void StepTurret();
Turret turret(2,3,4,StepTurret);
void StepTurret()
{
turret.Step();
}
ScaleObject* tso;
IRSensor* irs;
Turret::Turret()
{
}
Turret Turret::getTurret()
{
return turret;
}
Turret::Turret(int en, int dir, int clk, void(*stepFunction)()):stepper2(en,dir,clk,stepFunction)
{
tso->getScale().tare();
tso->getScale().set_gain(128);
tso->getScale().set_scale(-3483.4);
}
void Turret::SeekBottleCenter()
{
Start();
while(irs->IRState()==1)
{
Serial.println("High");
Serial.println(irs->IRState());
}
while(irs->IRState()==0)
{
Serial.println("Low");
}
}
bool Turret::BottleCentered()
{
return turret.BottleCenterState;
}
void Turret::ClearFunction()
{
wt = tso->getScale().get_units();
while(wt>5)
{
Serial.println("Clearing");
wt = tso->getScale().get_units();
Rotate(20);
}
}
#endif
And above is the Turret.cpp file.
#ifndef IRSensor_cpp
#define IRSensor_cpp
#include "Arduino.h"
#include "IRSensor.h"
IRSensor i(5);
IRSensor::IRSensor(int pin)
{
IRSensorPin = pin;
pinMode(pin,INPUT);
}
int IRSensor::IRState()
{
return digitalRead(i.IRSensorPin);
}
#endif
And above is the IRSensor.cpp file. So essentially I press the go button declared in my main, that button calls monitor in the LoadBottleButton.cpp file, that method uses a turret point to get access to the Turret.cpp methods and a boolean named BottleCenterState. But the code only gets so far, it stops after printing "In" of the Serial.println("In Monitor") line. Why is that?
Don't count on the output to tell you where the error is. That serial print may have completed successfully and the message is buffered in an output stream waiting for a chance to be written to the serial port.
A much more likely cause of the crash is the line below the serial print.
Serial.println("In Monitor");
while(tPointer->getTurret().BottleCenterState==false)
tPointer is used and I don't see anywhere in the provided code it is assigned a valid, dereferencable pointer. Dereferencing an undefined pointer results in undefined behaviour, and in this case probably a crash. Even if it isn't the crash you are seeing, this is almost certainly wrong.
How to fix it?
From the code provided it doesn't look like tpointer needs to be a pointer at all.
Turret turret;
May be all you need. Allocating turret statically eliminates the possibility of pointer and memory management bugs and reduces the chance of leaks.
Otherwise,
Turret* tPointer = new Turret();
But this leaves you with the problem of how and when do you delete tPointer;.
Check that your string doesn't contain a NULL character. This will terminate the string abruptly.
I'm trying to following the code from this post to have signal handlers print a backtrace on errors such as floating point and segmentation faults. I'm using seg fault signals as a starting point. Here is the code:
#include <cstdlib> //for exit()
#include <signal.h> //signal handling
#include <execinfo.h> //backtrace, backtrace_symbols and backtrace_fd
#include <iostream>
#include <string.h>
#include <stdio.h>
#define TRACE_MSG fprintf(stderr, "TRACE at: %s() [%s:%d]\n", \
__FUNCTION__, __FILE__, __LINE__)
void show_stackframe()
{
void *trace[1024];
char **messages = (char **) NULL;
int i, trace_size = 0;
TRACE_MSG;
trace_size = backtrace(trace, 1024); // segfault here???
// More code here to print backtrace, but not needed at the moment..
TRACE_MSG;
}
void sigSegvHandler( int signum, siginfo_t* info, void* arg )
{
TRACE_MSG;
show_stackframe();
return;
}
double func_b()
{
show_stackframe(); // Show that backtrace works without being
// called inside sighandler.
TRACE_MSG;
int int_a[5];
int_a[0] = 4;
int_a[11] = 10; // cause a segfault on purpose to see
// how the signal handling performs.
return 1.1;
}
int main()
{
// Examine and change the seg fault signal
struct sigaction segvAction; // File: /usr/include/bits/sigaction.h
// Initialize segvAction struct to all zeros for initialiation
memset( &segvAction, 0, sizeof( segvAction ) );
segvAction.sa_sigaction = sigSegvHandler;
segvAction.sa_flags = SA_SIGINFO; //Invoke signal catching function with 3 arguments instead of 1
// Set the action for the SIGSEGV signal
sigaction( SIGSEGV, &segvAction, NULL );
func_b(); // Produce a SIGSEGV error
}
I am compiling using:
g++ -rdynamic testprogram.cpp -o testprogram
I receive the following output from the program:
TRACE at: show_stackframe() [stackoverflow.cpp:15]
TRACE at: show_stackframe() [stackoverflow.cpp:17]
TRACE at: func_b() [stackoverflow.cpp:33]
TRACE at: sigSegvHandler() [stackoverflow.cpp:22]
TRACE at: show_stackframe() [stackoverflow.cpp:15]
Segmentation fault
My question is why does show_stackframe() cause a segmentation fault inside of sigaction but works fine when not inside of the sigaction handler? I obviously seem to be setting up the signal handler/action incorrect but I haven't been able to find it all day. GDB doesn't seem to be any help in this case.
As stated here, the backtrace function is AS-Unsafe, which means it is unsafe to call from an asynchronous signal handler. Doing so invokes undefined behavior.
I've been "playing around with" boost threads today as a learning exercise, and I've got a working example I built quite a few months ago (before I was interrupted and had to drop multi-threading for a while) that's showing unusual behaviour.
When I initially wrote it I was using MingW gcc 3.4.5, and it worked. Now I'm using 4.4.0 and it doesn't - incidentally, I've tried again using 3.4.5 (I kept that version it a separate folder when I installed 4.4.0) and it's still working.
The code is at the end of the question; in summary what it does is start two Counter objects off in two child threads (these objects simply increment a variable then sleep for a bit and repeat ad infinitum - they count), the main thread waits for the user via a cin.get() and then interrupts both threads, waits for them to join, then outputs the result of both counters.
Complied with 3.4.5 it runs as expected.
Complied with 4.4.0 it runs until the user input, then dies with a message like the below - it seems the the interrupt exceptions are killing the entire process?
terminate called after throwing an instance of '
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
boost::thread_interrupted'
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
From what I read, I think that any (?) uncaught exception that is allowed to propagate out of a child thread will kill the process? But, I'm catching the interrupts here, aren't I? At least I seem to be when using 3.4.5.
So, firstly, have I understood how interrupting works?
And, any suggestions as to what is happening and how to fix?
Code:
#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/date_time.hpp>
//fixes a linker error for boost threads in 4.4.0 (not needed for 3.4.5)
//found via Google, so not sure on validity - but does fix the link error.
extern "C" void tss_cleanup_implemented() { }
class CCounter
{
private:
int& numberRef;
int step;
public:
CCounter(int& number,int setStep) : numberRef(number) ,step(setStep) { }
void operator()()
{
try
{
while( true )
{
boost::posix_time::milliseconds pauseTime(50);
numberRef += step;
boost::this_thread::sleep(pauseTime);
}
}
catch( boost::thread_interrupted const& e )
{
return;
}
}
};
int main( int argc , char *argv[] )
{
try
{
std::cout << "Starting counters in secondary threads.\n";
int number0 = 0,
number1 = 0;
CCounter counter0(number0,1);
CCounter counter1(number1,-1);
boost::thread threadObj0(counter0);
boost::thread threadObj1(counter1);
std::cout << "Press enter to stop the counters:\n";
std::cin.get();
threadObj0.interrupt();
threadObj1.interrupt();
threadObj0.join();
threadObj1.join();
std::cout << "Counter stopped. Values:\n"
<< number0 << '\n'
<< number1 << '\n';
}
catch( boost::thread_interrupted& e )
{
std::cout << "\nThread Interrupted Exception caught.\n";
}
catch( std::exception& e )
{
std::cout << "\nstd::exception thrown.\n";
}
catch(...)
{
std::cout << "\nUnexpected exception thrown.\n"
}
return EXIT_SUCCESS;
}
Solved.
It turns out adding the complier flag -static-libgcc removes the problem with 4.4.0 (and has no apparent affect with 3.4.5) - or at least in this case the program returns the expected results.