Error Handling#

The errno Variable#

On error, system calls (and most C library functions)

  • return -1

  • set the global variable errno

#include <fcntl.h>
#include <print>

int main()
{
    int fd = open("/etc/passwd", O_RDWR);
    if (fd == -1) {
        std::println("open failed, errno=={}", errno);
        return 1;
    }

    return 0;
}
$ ./sysprog-errors--return-and-errno
open failed, errno==13

errno Is A Global Variable#

  • errno is global, with all consequences

  • Should read it immediately after failed syscall

#include <fcntl.h>
#include <print>

int main()
{
    int fd = open("/etc/passwd", O_RDWR);
    if (fd == -1) {
        std::println("open failed");
        std::println("errno=={}", errno);              // <-- errno could have changed by previous println()
        return 1;
    }

    return 0;
}

Simplest Stringification: perror()#

  • Advantage: need not mention errno

  • Translates errno into a descriptive string

  • Value of errno not printed though

#include <fcntl.h>
#include <stdio.h>

int main()
{
    int fd = open("/etc/passwd", O_RDWR);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    return 0;
}
$ ./sysprog-errors--perror
open failed: Permission denied

More Stringification: strerror()#

  • Returns a pointer to a descriptive string

  • Does not print anything itself

  • Not thread-safe: pointer might be invalidated by subsequent calls to strerror()

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <print>

int main()
{
    int fd = open("/etc/passwd", O_RDWR);
    if (fd == -1) {
        const char* errstr = strerror(errno);
        std::println("open failed: {} ({})", errstr, errno);
        return 1;
    }

    return 0;
}
$ ./sysprog-errors--strerror
open failed: Permission denied (13)

Thread-Safe Stringification: strerror_r()#

  • _r for “reentrant”

  • User has to supply buffer

  • Buffer might be used by strerror_r()

  • Message might be truncated if buffer too small; always 0-terminated

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <print>

int main()
{
    int fd = open("/etc/passwd", O_RDWR);
    if (fd == -1) {
        char buf[64];                                  // <-- *might* be used
        const char* errstr = strerror_r(errno, buf, sizeof(buf));
        std::println("open failed: {} ({})", errstr, errno);
        return 1;
    }

    return 0;
}
$ ./sysprog-errors--strerror_r
open failed: Permission denied (13)