gdb debugger quits prematurely on popen(), 'signal SIGTRAP, Trace/breakpoint trap'? - c++

The following code works in stand alone (non-debugging) mode. However gdb debugging stops when I tried to step over popen(), meaning a breakpoint at the fgets() can never be reached.
#include <stdio.h>
int main()
{
char buff[10];
FILE *f = popen("echo blah", "r");
// program and debugger exit before this line
// so that fgets() and printf() were never called
fgets(buff, 5, f);
printf("%s\n", buff);
}
GDB reports Program terminated with signal SIGTRAP, Trace/breakpoint trap. I dug into glibc's popen() and this is where it quits,
// internal-signal.h
/* Block all signals, including internal glibc ones. */
static inline void
__libc_signal_block_all (sigset_t *set)
{
INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &sigall_set, set,
__NSIG_BYTES);
}
Does anyone knows what is going on here? thanks!

Turned out to be a kernel issue, at least when I reverted back from 5.15.x to 5.14.x, the issue went away. I thought kernel update were never meant to break userspace.

Related

Destructor of stack allocated object does not get called when program is killed from the terminal [duplicate]

I have a class with a user-defined destructor. If the class was instantiated initially, and then SIGINT is issued (using CTRL+C in unix) while the program is running, will the destructor be called? What is the behaviour for SIGSTP (CTRL + Z in unix)?
No, by default, most signals cause an immediate, abnormal exit of your program.
However, you can easily change the default behavior for most signals.
This code shows how to make a signal exit your program normally, including calling all the usual destructors:
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cstring>
#include <atomic>
std::atomic<bool> quit(false); // signal flag
void got_signal(int)
{
// Signal handler function.
// Set the flag and return.
// Never do real work inside this function.
// See also: man 7 signal-safety
quit.store(true);
}
class Foo
{
public:
~Foo() { std::cout << "destructor\n"; }
};
int main(void)
{
struct sigaction sa;
memset( &sa, 0, sizeof(sa) );
sa.sa_handler = got_signal;
sigfillset(&sa.sa_mask);
sigaction(SIGINT,&sa,NULL);
Foo foo; // needs destruction before exit
while (true)
{
// do real work here...
sleep(1);
if( quit.load() ) break; // exit normally after SIGINT
}
return 0;
}
If you run this program and press control-C, you should see the word "destructor" printed.
Be aware that your signal handler function (got_signal) should rarely do any work, other than setting a flag and returning quietly, unless you really know what you are doing. See also: https://man7.org/linux/man-pages/man7/signal-safety.7.html
Most signals are catchable as shown above, but not SIGKILL, you have no control over it because SIGKILL is a last-ditch method for killing a runaway process, and not SIGSTOP which allows a user to freeze a process cold. Note that you can catch SIGTSTP (control-Z) if desired, but you don't need to if your only interest in signals is destructor behavior, because eventually after a control-Z the process will be woken up, will continue running, and will exit normally with all the destructors in effect.
If you do not handle these signals yourself, then, no, the destructors are not called. However, the operating system will reclaim any resources your program used when it terminates.
If you wish to handle signals yourself, then consider checking out the sigaction standard library function.
Let's try it:
#include <stdio.h>
#include <unistd.h>
class Foo {
public:
Foo() {};
~Foo() { printf("Yay!\n"); }
} bar;
int main(int argc, char **argv) {
sleep(5);
}
And then:
$ g++ -o test ./test.cc
$ ./test
^C
$ ./test
Yay!
So I'm afraid not, you'll have to catch it.
As for SIGSTOP, it cannot be caught, and pauses the process until a SIGCONT is sent.

How to run odaslive program from c file

So I am trying to call a program from within a c file I am making but the only way I've been able to do that is by using the system() function which causes error on its own. To run the program in terminal I use;
~/odas/bin/odaslive -vc ~/odas/config/odaslive/matrix_creator.cfg
This is what I am currently trying to use to run that same program, it compiles and will run in terminal but nothing happens.
pid_t pid=fork();
if (pid==0){
//static char *argv[] ={"echo","-vc ~/odas/config/odaslive/matrix_creator.cfg", NULL};
execl("~/odas/bin", "~/odas/bin/odaslive", "-vc", "~/odas/config/odaslive/matrix_creator.cfg", (char *)NULL);
exit(127);
} else {
waitpid(pid,0,0);
}
execl requires file path in the first argument.
It doesn't expand ~ with the home for path. The full path must be supplied.
Check a returned value and errno. It will inform you about a failure reason if any.
int ret = execl("/home/username/odas/bin/odaslive", "/home/username/odas/bin/odaslive", "-vc", "/home/username/odas/config/odaslive/matrix_creator.cfg", (char *)NULL);

Ctrl + C interrupt event handling in Linux

I am developing an application that uses C++ and compiles using Linux GNU C Compiler.
I want to invoke a function as the user interrupts the script using Ctrl + C keys.
What should I do? Any answers would be much appreciated.
When you press Ctr + C, the operating system sends a signal to the process. There are many signals and one of them is SIGINT. The SIGINT ("program interrupt") is one of the Termination Signals.
There are a few more kinds of Termination Signals, but the interesting thing about SIGINT is that it can be handled (caught) by your program. The default action of SIGINT is program termination. That is, if your program doesn't specifically handle this signal, when you press Ctr + C your program terminates as the default action.
To change the default action of a signal you have to register the signal to be caught. To register a signal in a C program (at least under POSIX systems) there are two functions
signal(int signum, sighandler_t handler);
sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);.
These functions require the header signal.h to be included in your C code. I have provide a simple example of the signal function below with comments.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h> // our new library
volatile sig_atomic_t flag = 0;
void my_function(int sig){ // can be called asynchronously
flag = 1; // set flag
}
int main(){
// Register signals
signal(SIGINT, my_function);
// ^ ^
// Which-Signal |-- which user defined function registered
while(1)
if(flag){ // my action when signal set it 1
printf("\n Signal caught!\n");
printf("\n default action it not termination!\n");
flag = 0;
}
return 0;
}
Note: you should only call safe/authorized functions in signal handler. For example avoid calling printf in signal handler.
You can compile this code with gcc and execute it from the shell. There is an infinite loop in the code and it will run until you send a SIGINT signal by pressing Ctr + C.
Typing CtrlC normally causes the shell to send SIGINT to your program. Add a handler for that signal (via signal(2) or sigaction(2)), and you can do what you like when CtrlC is pressed.
Alternately, if you only care about doing cleanup before your program exits, setting up an exit handler via atexit(3) might be more appropriate.
You can use the signal macro.
Here is an example of how to deal with it:
#include <signal.h>
#include <stdio.h>
void sigint(int a)
{
printf("^C caught\n");
}
int main()
{
signal(SIGINT, sigint);
for (;;) {}
}
Sample output:
Ethans-MacBook-Pro:~ phyrrus9$ ./a.out
^C^C caught
^C^C caught
^C^C caught
^C^C caught
^C^C caught

Is destructor called if SIGINT or SIGSTP issued?

I have a class with a user-defined destructor. If the class was instantiated initially, and then SIGINT is issued (using CTRL+C in unix) while the program is running, will the destructor be called? What is the behaviour for SIGSTP (CTRL + Z in unix)?
No, by default, most signals cause an immediate, abnormal exit of your program.
However, you can easily change the default behavior for most signals.
This code shows how to make a signal exit your program normally, including calling all the usual destructors:
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cstring>
#include <atomic>
std::atomic<bool> quit(false); // signal flag
void got_signal(int)
{
// Signal handler function.
// Set the flag and return.
// Never do real work inside this function.
// See also: man 7 signal-safety
quit.store(true);
}
class Foo
{
public:
~Foo() { std::cout << "destructor\n"; }
};
int main(void)
{
struct sigaction sa;
memset( &sa, 0, sizeof(sa) );
sa.sa_handler = got_signal;
sigfillset(&sa.sa_mask);
sigaction(SIGINT,&sa,NULL);
Foo foo; // needs destruction before exit
while (true)
{
// do real work here...
sleep(1);
if( quit.load() ) break; // exit normally after SIGINT
}
return 0;
}
If you run this program and press control-C, you should see the word "destructor" printed.
Be aware that your signal handler function (got_signal) should rarely do any work, other than setting a flag and returning quietly, unless you really know what you are doing. See also: https://man7.org/linux/man-pages/man7/signal-safety.7.html
Most signals are catchable as shown above, but not SIGKILL, you have no control over it because SIGKILL is a last-ditch method for killing a runaway process, and not SIGSTOP which allows a user to freeze a process cold. Note that you can catch SIGTSTP (control-Z) if desired, but you don't need to if your only interest in signals is destructor behavior, because eventually after a control-Z the process will be woken up, will continue running, and will exit normally with all the destructors in effect.
If you do not handle these signals yourself, then, no, the destructors are not called. However, the operating system will reclaim any resources your program used when it terminates.
If you wish to handle signals yourself, then consider checking out the sigaction standard library function.
Let's try it:
#include <stdio.h>
#include <unistd.h>
class Foo {
public:
Foo() {};
~Foo() { printf("Yay!\n"); }
} bar;
int main(int argc, char **argv) {
sleep(5);
}
And then:
$ g++ -o test ./test.cc
$ ./test
^C
$ ./test
Yay!
So I'm afraid not, you'll have to catch it.
As for SIGSTOP, it cannot be caught, and pauses the process until a SIGCONT is sent.

avoiding abort in libgmp

I have some code that uses libgmp. At some point the user may request a factorial of a very large number. Unfortunately, this results in libgmp raising an abort signal.
For example the following code:
#include <cmath>
#include <gmp.h>
#include <iostream>
int main() {
mpz_t result;
mpz_init(result);
mpz_fac_ui(result, 20922789888000);
std::cout << mpz_get_si(result) << std::endl;
}
Results in:
$ ./test
gmp: overflow in mpz type
Aborted
Apparently, the number produced is REALLY big. Is there anyway to handle the error more gracefully than an abort. This is a GUI based application and it aborting is pretty much the least desirable way to handle this sort of issue.
It would appear that you are out of luck, based on the code in mpz/realloc.c and mpz/realloc2.c. If too much memory was requested, it just does this:
if (UNLIKELY (new_alloc > INT_MAX))
{
fprintf (stderr, "gmp: overflow in mpz type\n");
abort ();
}
The best way to handle these errors gracefully in your application is probably to fork off a helper process to perform the GMP calculations. If the helper process is killed by SIGABRT, your parent process can detect that and report an error to the user.
(The below is my original answer, which has "undefined results" according to the GMP documentation - it is left here for completeness).
You can catch the error if you install a signal handler for SIGABRT that uses longjmp():
jmp_buf abort_jb;
void abort_handler(int x)
{
longjmp(abort_jb, 1);
}
int dofac(unsigned long n)
{
signal(SIGABRT, abort_handler);
if (setjmp(abort_jb))
goto error;
mpz_t result;
mpz_init(result);
mpz_fac_ui(result, 20922789888000);
std::cout << mpz_get_si(result) << std::endl;
signal(SIGABRT, SIG_DFL);
return 0;
error:
signal(SIGABRT, SIG_DFL);
std::cerr << "Caught SIGABRT from GMP.\n";
return 1;
}
Overwrite abort() with LD_PRELOAD.
What is the LD_PRELOAD trick?
Edit: To make the answer more self-contained, I copy the text of that answer here:
If you set LD_PRELOAD to the path of a shared object, that file will be loaded before any other library (including the C runtime, libc.so). So to run ls with a your special malloc() implementation, do this:
$ LD_PRELOAD=/path/to/my/malloc.so /bin/ls
Credits to JesperE.