I'm working on a test and i'm asked how to make a "read" sleep or a "write" stop a process"
For the latter I don't understand why my sigpipe is, indeed raised, but isn't stopping the process:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#define READING 0
#define WRITING 1
#define DESCRIPTOR_COUNT 2
void signal_handler(int signal){
printf("sigpipe received\n");
}
int main(void)
{
int tube[DESCRIPTOR_COUNT];
pipe(tube);
// signal(SIGPIPE, signal_handler);
close(tube[READING]);
if(write(tube[WRITING], "message", 8)<0)
if(errno==EPIPE)
printf("EPIPE returned\n");
printf("123");
return EXIT_SUCCESS;
}
Without signal() (quoted)
With signal() (unquoted)
SIGPIPE is indeed received, but in the case I don't handle it the process should stop, but since I can write "123" this means the process wasn't stopped.
Why?
Also I'm on Fedora 28, i'm using codeblocks 17.12.
Was SIGPIPE ignored...? Reason?
SOLUTION ?
struct sigaction action;
action.sa_handler = SIG_DFL;
sigaction(SIGPIPE, &action, 0);
Replacing signal() with this will have the default behaviour as expected!
EDIT I've now changed the title from "SIGPIPE doesn't stop process" to "Why was default SIGPIPE handler changed?"
======================================================
Answer
After talking with the guys from codeblocks, codeblocks uses wxWidgets, and on linux (fedora 28 here) wxWidgets uses gtk library, as explained by Mark Plotnick in the comments, gtk changes the signal handler for SIGPIPE, since codeblocks runs codes using a fork or an exec, the code run through codeblocks is influenced by gtk library.
The behaviour you are reporting is consistent with the Code::Blocks IDE setting, implicitly or explicitly, the SIGPIPE behaviour to SIG_IGN. This is readily inherited. It isn't what I'd expect — I'd expect your program to be launched with SIGPIPE (and, indeed, all other signals) set to SIG_DFL, the default signal behaviour. If this turns out to be the problem, you have the basis for a bug report to the developers of Code::Blocks. If it turns out not to be the problem, then we've got some hard thinking ahead to work out what actually is happening*.
You could demonstrate whether this is what's happening with Code::Blocks by paying attention to the return value from signal(), or by using sigaction() to interrogate the signal handling mode without modifying it.
For example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#define READING 0
#define WRITING 1
#define DESCRIPTOR_COUNT 2
static void signal_handler(int signum)
{
// Lazy; normally, I'd format the signal number into the string, carefully
(void)signum;
write(STDOUT_FILENO, "sigpipe received\n", sizeof("sigpipe received\n")-1);
}
int main(void)
{
void (*handler)(int) = signal(SIGPIPE, signal_handler);
if (handler == SIG_DFL)
printf("old handler was SIG_DFL\n");
else if (handler == SIG_IGN)
{
printf("old handler was SIG_IGN\n");
(void)signal(SIGPIPE, SIG_IGN);
}
else
{
// Standard C does not allow a cast from function pointer to object pointer
//printf("there was a non-standard handler installed (%p)\n", (void *)handler);
printf("there was a non-standard handler installed\n");
}
int tube[DESCRIPTOR_COUNT];
pipe(tube);
close(tube[READING]);
if (write(tube[WRITING], "message", 8) < 0)
{
if (errno == EPIPE)
printf("EPIPE returned\n");
else
printf("errno = %d\n", errno);
}
printf("123\n");
return EXIT_SUCCESS;
}
Note that the standard idiom for setting a signal handler using signal() in a program was:
if (signal(signum, SIG_IGN) != SIG_IGN)
signal(signum, signal_handler);
This means that if a program was protected from signals, it stays protected. If it was handling signals (by default, or perhaps explicitly by a prior call to signal()), then you install your own signal handler. Equivalent code using sigaction() would be:
struct sigaction sa;
if (sigaction(signum, 0, &sa) == 0 && sa.sa_handler != SIG_IGN)
{
sa.sa_handler = signal_handler;
sa.sa_flag &= ~SA_SIGINFO;
sigaction(signum, sa, 0);
}
(One advantage of this: the structure is initialized by the call to sigaction(), so there's no need to fiddle with the masks. The tweak to the flags ensures that the basic handler, not the extended handler, is used.)
When I compile the source code (pipe13.c) into program pipe13 and run it, I get:
$ make pipe13
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes pipe13.c -o pipe13
$ pipe13
old handler was SIG_DFL
sigpipe received
EPIPE returned
123
$ (trap '' 13; pipe13)
old handler was SIG_IGN
EPIPE returned
123
$
This variant uses sigaction() to interrogate the signal handling:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#define READING 0
#define WRITING 1
#define DESCRIPTOR_COUNT 2
int main(void)
{
struct sigaction sa;
if (sigaction(SIGPIPE, 0, &sa) != 0)
fprintf(stderr, "siagaction() failed\n");
else if (sa.sa_handler == SIG_DFL)
printf("old handler was SIG_DFL\n");
else if (sa.sa_handler == SIG_IGN)
printf("old handler was SIG_IGN\n");
else
printf("there was a non-standard handler installed\n");
int tube[DESCRIPTOR_COUNT];
pipe(tube);
close(tube[READING]);
if (write(tube[WRITING], "message", 8) < 0)
{
if (errno == EPIPE)
printf("EPIPE returned\n");
else
printf("errno = %d\n", errno);
}
printf("123\n");
return EXIT_SUCCESS;
}
When run (program pipe83), I get:
$ pipe83
old handler was SIG_DFL
$ echo $?
141
$ (trap '' 13; pipe83)
old handler was SIG_IGN
EPIPE returned
123
$
Note that with the default signal handling, the program terminates before printing 123. POSIX shells encode 'child died from signal N' by reporting the exit status as 128 + N; SIGPIPE is 13, so 141 indicates that the shell died from a SIGPIPE signal. (Yes, modern youngsters would probably write (trap '' PIPE; pipe83) and it works — such niceties weren't available when I learned shell programming.)
It would not be all that hard to generalize the code to test whether Code::Blocks sets any other signals to other than the default handling. It can be a little fiddly, though, if you want to adapt to which signals are available on a machine.
* In chat, we established that the program is run in a VMware image running Fedora 28, hosted on a Windows 10 machine. Because of this, there are enough possible places for there to be trouble that it is not clear that the problem is necessarily in Code::Blocks — it is simply not clear where the problem originates. However, the problem does indeed seem to be that the test program is started with SIGPIPE handling set to SIG_IGN instead of SIG_DFL when it is run from Code::Blocks.
Code::Blocks is not a compiler, just an IDE. It (probably) runs the GCC compiler. And the GCC compiler don't matter much for signal handling. Read signal(7) and signal-safety(7) for more (calling printf inside a signal handler is forbidden because printf is not async-signal-safe so your printf("sigpipe received\n"); inside a signal handler is undefined behavior). Signal handling is done mostly by the Linux kernel (see its source code on kernel.org) with a small bit of it handled by your C standard library, probably GNU glibc.
It seems codeblocks changes the default signal handler for SIGPIPE
This is very unlikely (and almost certainly false). You could use strace(1) on your program to understand what system calls it is doing.
printf("123");
You forgot a \n. Remember that stdout is usually line-buffered. Or you should call fflush(3).
When you run a program from inside Code::Blocks it could run without a terminal. I strongly recommend running your program inside a terminal emulator (see tty(4) and pty(7)). The C standard library is permitted to use something like isatty(3) to behave differently when stdout is or is not a tty (in particular, buffering is done differently, see setvbuf(3)). Read the tty demystified and termios(3).
You could also try to run your program by redirecting its stdin, stdout, stderr to a file or a pipe (perhaps using |& cat or |& less with bash or zsh), or anything which is not a tty.
BTW, Code::Blocks is free software. You can study its source code to understand what it is doing.
Consider also using stdbuf(1) to run your program with different buffering operations.
Related
This is my program code:
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/types.h>
void function() {
srand(time(NULL));
while(1) {
int n = rand();
printf("%d ", n);
//sleep(1);
}
}
int main() {
pid_t pid;
pid = fork();
if (pid == 0) {
function();
}
}
With the sleep line commented out (as in the code above) the program works fine (i.e. it prints a bunch of random numbers too fast to even see if they are actually random), but if I remove the comment the program doesn't print anything and exits (not even the first time, before it gets to the sleep), even though it compiles without warnings or errors with or without the comment.
but if I remove the comment the program doesn't print anything and exits
It does not print, but it does not really exit either. It will still be running a process in the background. And that process runs your infinite while loop.
Using your code in p.c:
$ gcc p.c
$ ./a.out
$ ps -A | grep a.out
267282 pts/0 00:00:00 a.out
$ killall a.out
$ killall a.out
a.out: no process found
The problem is that printf does not really print. It only sends data to the output buffer. In order to force the output buffer to be printed, invoke fflush(stdout)
If you're not flushing, then you just rely on the behavior of the terminal you're using. It's very common for terminals to flush when you write a newline character to the output stream. That's one reason why it's preferable to use printf("data\n") instead of printf("\ndata"). See this question for more info: https://softwareengineering.stackexchange.com/q/381711/283695
I'd suspect that if you just leave your program running, it will eventually print. It makes sense that it has a finite buffer and that it flushes when it gets full. But that's just an (educated) guess, and it depends on your terminal.
it prints a bunch of random numbers too fast to even see if they are actually random
How do you see if a sequence of numbers is random? (Playing the devils advocate)
I believe you need to call fflush(3) from time to time. See also setvbuf(3) and stdio(3) and sysconf(3).
I guess that if you coded:
while(1) {
int n = rand();
printf("%d ", n);
if (n % 4 == 0)
fflush(NULL);
sleep(1);
}
The behavior of your program might be more user friendly. The buffer of stdout might have several dozens of kilobytes at least.
BTW, I could be wrong. Check by reading a recent C draft standard (perhaps n2176).
At the very least, see this C reference website then syscalls(2), fork(2) and sleep(3).
You need to call waitpid(2) or a similar function for every successful fork(2).
If on Linux, read also Advanced Linux Programming and use both strace(1) and gdb(1) to understand the behavior of your program. With GCC don't forget to compile it as gcc -Wall -Wextra -g to get all warnings and debug info.
Consider also using the Clang static analyzer.
Here is my code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
pthread_t ntid;void
printids(const char *s) {
printf("%s \n", s);
}
void *
thr_fn(void *arg) {
printids("new thread: ");
return((void *)0);
}
int
main(void) {
pthread_create(&ntid, NULL, thr_fn, NULL);
printids("main thread:");
}
I'm running it on Red Hat Enterprise Linux Workstation release 6.5 .
Here is my compiling command
gcc -ansi -g -std=c99 -Wall -DLINUX -D_GNU_SOURCE threadid.c -o threadid -pthread -lrt -lbsd
Here is the output:
main thread:
new thread:
new thread:
Why "new thread" has been printed twice?
I doubt this may related to buffering mechanism in Linux. But after I added fflush(stdout) and fsync(1) in the end of each function. The output is almost the same.
If you run the program several times. The output differs:
main thread:
new thread:
or
main thread:
new thread:
new thread:
Or
main thread:
Most libc libraries do buffer the output as you mentioned. And at the end of the program (when the main thread exits), they flush all the buffers and exit.
There is a slight possibility that your new thread has flushed the output but before it could update the state of the buffer, the main program exited and the cleanup code flushed the same buffer again. Since these buffers are local to the thread I am sure they won't have concurrency mechanism. But because of this rare case it might get messed up.
You can try
err = pthread_create(&ntid, NULL, thr_fn, NULL);
printids("main thread:");
pthread_join(ntid, NULL);
At the end of the main function and check if the problem is solved.
This will cause your main function to wait till the new thread is finished (including the flushing operation it does).
Double output is possible on glibc-based linux systems due to a nasty bug in glibc: if the FILE lock is already held at the time exit tries to flush, the lock is simply ignored and the buffer access is performed with no synchronization. This would be a great test case to report to glibc to pressure them to fix it, if you can reproduce it reliably.
I am a beginner of multi-threaded programming, and now I know that when a signal was sent while waiting with pthead_cond_wait(), the result depends on the OS.
Can somebody tell me how to know how the call was interrupted, and how to write portable code?
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
void
sigusr1_handler(int sig)
{
printf("signal called\n");
}
int
main()
{
int n;
pthread_mutex_t mut;
pthread_cond_t cond;
struct timespec ts;
signal(SIGUSR1, sigusr1_handler);
pthread_mutex_init(&mut, NULL);
pthread_cond_init(&cond, NULL);
pthread_mutex_lock(&mut);
printf("before cond_wait\n");
n = pthread_cond_wait(&cond, &mut);
printf("after pthread_cond_wait : %d\n", n);
perror("error pthread_cond_wait:");
pthread_mutex_unlock(&mut);
return 0;
}
MacOS X 10.11.4
cc -o condwait condwait.c -lpthread
Linux 2.6.32-642.3.1.el6.x86_64
gcc -o condwait condwait.c -lpthread
Solaris11 5.11 11.2
cc -D_POSIX_C_SOURCE -D_REENTRANT -mt -o condwait condwait.c -lpthread
MacOS X
$ ./condwait &
[1] xxxxx
$ kill -USR1 %1
signal called
after pthread_cond_wait : 0
error pthread_cond_wait:: Unknown error: 260
Solaris
$ ./condwait &
[1] xxxxx
$ kill -USR1 %1
signal called
after pthread_cond_wait : 0
error pthread_cond_wait : Error 0
Linux
$ ./condwait &
[1] xxxxx
$ kill -USR1 %1
signal called
$ jobs
[1]+ Running
When using Solaris native cond_wait(), it returns EINTR as documented.
Is there any idea how to know that pthread_cond_wait() was interrupted?
POSIX specifies that this function will never return EINTR. For portability to legacy OSes you can check for it anyway, it doesn't hurt
More importantly, you should be prepared for spurious wakeups. The function can return zero at any time for any reason wiith the condition not being met. The mutex will be locked. You have to check the condition and, if not met, go back to pthread_cond_wait.
I read the Linux pthread_cond_wait's man manual, it says:
If a signal is delivered to a thread waiting for a condition variable, upon return from the signal handler the thread resumes waiting for the condition variable as if it was not interrupted, or it shall return zero due to spurious wakeup.
I guess other OS's also have manuals to help you figure it out.
Thank you very much for everyone.
Now I know that with using signal to stop long waiting condition do not work.
pthread_cond_wait() resume waiting for the condition as if it was not interrupted, or it returns zero due to spurious wakeup.
Then I want to do that, I will need a second lock like
pthread_mutex_lock(&mut);
while(condition_is_false) {
n = pthread_cond_timedwait();
if (n == ETIMEDOUT) {
pthread_mutex_lock(&mut2);
if (condition2_is_true) {
pthread_mutex_unlock(&mut2);
pthread_mutex_unlock(&mut);
return STOPPED;
}
pthread_mutex_unlock(&mut2);
}
}
pthread_mutex_unlock(&mut);
return 0;
Regards,
Consider the following program (vul.c) with buffer overflow vulnerability.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[10];
strcpy(buf, argv[1]);
printf("%s\n", buf);
return 0;
}
Above program compiled using gcc -o vul vul.c and executed on arch linux - linux 4.4.16-1-lts x86-64 gave following output when executed in terminal with ./vul $(perl -e 'print "A"x100') command:
AAAAAAAAAAA...A
Segmentation fault (core dumped)
Then checking the program status using echo $? command gave 139 output.
Following program (exp.c) (for crashing the above program)
#include <stdlib.h>
int main(void)
{
printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
return 0;
}
compiled using gcc -o exp exp.c when executed with ./exp command on same system gave following output:
AAAAAAAAAAAA...A
139
I have two questions:
Why no error message was generated by 2nd program? and,
I need to compile the program with -fstack-protector flag to enable the *** stack smashing detected *** error messages in arch linux but not in Ubuntu. In Ubuntu, it might be that this flag is include by default in gcc or is there any other reason?
As I pointed out in my comment,system returns an int with the programs's return value, which is normally it's error code (0 if successful).
If you want to print the error as a nice looking message, you can probably use strerror.
According to #rht's comment (see my next edit) and the answers to the question referenced in that comment, the returned value will be 0 on success and on error it will be error | 0x80. To get the original error code, use 128 - err_code.
try this:
#include <stdlib.h>
#include <errno.h>
int main(void)
{
int tmp = system("./vul $(perl -e 'print \"A\"x100)");
if(tmp < 0)
error("Couldn't run system command");
else if(tmp >0)
printf(stderr, "System command returned error: %s", strerror(128 - tmp));
else
; // nothing
return 0;
}
The fact that vul.c does (or does not) print an error message should be irrelevant for your exp.c program, since it depends on vul.c's compile flags values and any default compiler flags - things exp.c can't control.
EDIT(2) - in answer to the comment.
It could be that the error message returned isn't an errno value, but a signal trap value.
These are sometimes hard to differentiate and I have no good advice about how you can tell which one it is without using memcmp against the answer.
In this case you know vul.c will never return it's errno value, which leaves you only with signal trap errors, so you can use strsignal to print the error message.
As pointed out in #rht's comment, which references this question:
Passing tmp to strsignal generates the same error message: "unknown signal 139". The reason is that there is no signal with this signal number. /usr/include/bits/signum.h contains all the signals with their signal numbers. Passing tmp-128 to strsignal works.
i.e.
#include <stdlib.h>
#include <string>
int main(void)
{
int tmp = system("./vul $(perl -e 'print \"A\"x100)");
if(tmp < 0)
error("Couldn't run system command");
else if(tmp >0)
printf(stderr, "System command returned error: %s", strsignal(tmp - 128));
else
; // nothing
return 0;
}
EDIT
The question was edited because it's code was mis-copied. I altered the answer to reflect that change.
From my comment to #Myst 's answer for "passing tmp-128 to strsignal()" function, after experimenting a little I found that it does not work in situations where the program exited normally but returned status other than 0.
Following are the contents of my /usr/include/bits/waitstatus.h:
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
/* If WIFSIGNALED(STATUS), the terminating signal. */
#define __WTERMSIG(status) ((status) & 0x7f)
/* Nonzero if STATUS indicates normal termination. */
#define __WIFEXITED(status) (__WTERMSIG(status) == 0)
/* Nonzero if STATUS indicates termination by a signal. */
#define __WIFSIGNALED(status) \
(((signed char) (((status) & 0x7f) + 1) >> 1) > 0)
Above code show that, exit status of a program is a 16bit number, the high order 8 bits of which are the status that the program returned and some/all of the remaining bits are set if the program exited because of a signal, 7 bits of which denote the signal that caused the program to exit. That's why subtracting 128 from the exit status returned by system() will not work in the situation as described above.
System()'s source code
Since system() function too uses fork() to create a new process and waits for the termination of the process, the same method of checking a child process's status in parent process can also be applied here. Following program demonstrates this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
int status = system("prg_name");
if (WIFEXITED(status))
printf("Exited Normally, status = %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("Killed by Signal %d which was %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
return 0;
}
Answering my own 2nd question.
gcc -Q -v vul.c command displayed the options passed to the gcc. The options in Ubuntu included -fstack-protector-strong flag but not in arch-linux. So in Ubuntu, the flag is passed by default to gcc.
There exists two problems in your vul.c and exp.c.
In vul.c,
char buf[10];
10 is not sufficient in this case, since the argv[1], i.e., $(perl -e 'print "A"x100', is larger than the buffer to be allocated. Enlarge the buf size should fix the segmentation fault.
In exp.c, you're missing one single quote, and should be modified as followed:
printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
I'm trying to use the signal function (I know it's deprecated and there are a lot of problems with its portability but I can't use sigaction).
I also need to compile with -ansi and -D_POSIX_C_SOURCE=200112L
If I compile with one of these flags, signal only works one time.
How can I get the same behavior with these flags without using sigaction please ?
#include <signal.h>
#include <stdio.h>
static void signal_handler(int nbr)
{
(void)nbr;
puts("\nHi ! ");
}
int main(void)
{
signal(SIGINT, signal_handler);
puts("Hi ! ");
while (42);
return (0);
}
Be aware, the above code contains an infinite loop.
Thanks :)
Looks like your system has the Unix/System V signal mechanism, which resets the signal action to SIG_DFL after the first signal.
So you have to reinstall the handler in the signal handler itself:
static void signal_handler(int nbr)
{
signal(SIGINT, signal_handler);
(void)nbr;
puts("\nHi ! ");
}
From signal linux man:
* On glibc 2 and later, if the _BSD_SOURCE feature test macro is not
defined, then signal() provides System V semantics. (The default
implicit definition of _BSD_SOURCE is not provided if one invokes
gcc(1) in one of its standard modes (-std=xxx or -ansi) or defines
various other feature test macros such as _POSIX_SOURCE,
_XOPEN_SOURCE, or _SVID_SOURCE; see feature_test_macros(7).)
I tried just at random and compiled with -D_BSD_SOURCE and on Ubuntu it works as intended.