Reputation: 1086
While reading Unix System Design by Maurice Bach I came across below code snippet.
#include < signal.h>
char *cp;
int callno;
main() {
char *sbrk();
extern catcher();
signal(SIGSEGV, catcher);
cp = sbrk(O);
printf("original brk value %u\n", cp);
for (;;)
*cp++ = 1;
}
catcher(signo) {
int signo;
callno++;
printf("caught sig %d %dth call at addr %u\n", signo, callno, cp);
sbrk(256);
signal(SIGSEGV, catcher);
}
I got confused with two statements within main method
char *sbrk();
extern catcher();
I understand how extern
works and I also know what sbrk()
does but I couldn't understand why have they written extern
before catcher()
and also why is char*
written before sbrk()
call?
I got compilation error on gcc-4.8.4 on Ubuntu when compiling this code but code compiles without any errors in Mac. Why is this happening?
Upvotes: 1
Views: 143
Reputation: 33273
char *sbrk();
extern catcher();
These are function declarations, not function calls. The code you are reading is old style (pre-ANSI), and in subsequent (c99 or newer) C standards they are no longer valid.
You should add an explicit return type to the declaration of catcher()
. The current implicit declaration means it has an int
return type. However, the correct signature for a signal handler specifies no return value. When we add an explicit return type, the extern
keyword is no longer needed and it can be removed.
sbrk
is actually declared in a regular header, so remove the declaration and #include <unistd.h>
. However, sbrk
is BSD (and part of SUSv2) and not a standard C function, so you need to activate the declaration with #define _BSD_SOURCE
or #define _XOPEN_SOURCE=500
before you include unistd.h
.
Printf
is declared in stdio.h
, so let's include it. %u
is used to print unsigned int
. Pointers should be printed with the %p
format specifier.
So, after some modernisation of the code:
#define _BSD_SOURCE
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void catcher();
char *cp;
int callno;
int main(void) {
signal(SIGSEGV, catcher);
cp = sbrk(O); // You sure this should be an O and not a 0?
printf("original brk value %u\n", cp);
for (;;)
*cp++ = 1;
}
void catcher(int signo) {
callno++;
printf("caught sig %d %dth call at addr %p\n", signo, callno, cp);
sbrk(256);
signal(SIGSEGV, catcher);
}
Please note that you should avoid calling printf
from within a signal handler. See for example How to avoid using printf in a signal handler or Signal Handlers and Async-Signal Safety
Upvotes: 5
Reputation: 1
In addition to @Klas Lindbäck's answer, there are other problems with this code under the current C and POSIX standards:
#include < signal.h>
char *cp;
int callno;
main() {
char *sbrk();
extern catcher();
signal(SIGSEGV, catcher);
cp = sbrk(O);
printf("original brk value %u\n", cp);
for (;;)
*cp++ = 1;
}
catcher(signo) {
int signo;
callno++;
printf("caught sig %d %dth call at addr %u\n", signo, callno, cp);
sbrk(256);
signal(SIGSEGV, catcher);
}
Don't use sbrk()
sbrk()
has been removed from the POSIX standard. It's no longer safe to use directly. From the Linux man page:
Avoid using
brk()
andsbrk()
: themalloc(3)
memory allocation package is the portable and comfortable way of allocating memory.
Why? Because numerous C library functions often use malloc()
/calloc()
/realloc()
/... internally, and mixing malloc()
and brk()
/sbrk()
calls in the same process is unsafe. malloc()
implementations often use brk()
/sbrk()
internally, so using sbrk()
in your own code might very well corrupt your heap.
Don't use signal()
signal()
has significant issues. It's not consistent at all. Use sigaction()
instead.
Upvotes: 0