Nullpointer
Nullpointer

Reputation: 1086

extern with function call inside main

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

Answers (2)

Klas Lindb&#228;ck
Klas Lindb&#228;ck

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

Andrew Henle
Andrew Henle

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() and sbrk(): the malloc(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

Related Questions