Errors

"Errors"

what are

?

"Errors"

what are

?

How are errors reported in code?

What behavior is considered erroneous? 

"Errors"

what are

?

"a function couldn’t do what it advertised"

What behavior is considered erroneous? 

arguments

state

do the job

side effects

result value

function

"Errors"

what are

?

What behavior is considered erroneous? 

arguments

state

do the job

side effects

result value

function

arguments

do the job

result value

pure function

"Errors"

what are

?

What behavior is considered erroneous? 

arguments

state

do the job

side effects

result value

function

Invalid Operation
Invalid Argument
Runtime Error
Out of Memory

"Errors"

what are

?

What behavior is considered erroneous? 

Implementation Error

arguments

state

do the job

side effects

result value

Invalid Operation
Invalid Argument

arguments

state

do the job

side effects

result value

Invalid Operation
Invalid Argument

"Errors"

what are

?

What behavior is considered erroneous? 

Runtime Error
Out of Memory
Runtime Error
Out of Memory
Implementation Error
Implementation Error

"Errors"

what are

?

What behavior is considered erroneous? 

Invalid Operation
Invalid Argument
Runtime Error
Out of Memory
Implementation Error

out of bounds access, null pointer dereference, division by zero

pop from empty stack, write to immutable object, race condition

heap exhaustion

stack overflow, hardware failure, cannot open file, operating system complaint

not yet implemented, bug

"Errors"

what are

?

How are errors reported in code?

What behavior is considered erroneous? 

"Errors"

what are

?

How are errors reported in code?

Termination

UB

abort
 assert
Invalid Operation
Invalid Argument
Implementation Error
Out of Memory
Runtime Error

Error codes

Exceptions

errno
error_code
std::exception
try, throw, catch
noexcept
Out of Memory
Runtime Error
*Invalid Operation
*Invalid Argument

"Errors"

c#

  1. Exception
  2. InvalidOperationException
  3. ArgumentException
  4. IndexOutOfRangeException
  5. NullReferenceException
  6. StackOverflowException
  7. OutOfMemeoryException
  8. DivideByZeroException
  • Do not use error codes
  • Use exceptions
  • Termination (for fatal error)
  • Optional return (for performance)
  • Document all throwable exceptions
  • Mind performance, but use exceptions

"Errors"

c++

  1. exception
  2. UB or logic_error
  3. UB, assert, logic_error
  4. UB, assert, logic_error
  5. UB, assert, logic_error
  6. UB
  7. UB, bad_alloc
  8. UB, assert
  • Some use error codes
  • Some use exceptions
  • Termination  (for fatal error)
  • Optional return (not for errors)
  • noexcept if doesn't throw
  • DESIRE PERFORMANCE

Undefined behavior

ill-formed

ill-formed; no diagnostic required (NDR)

undefined behavior (UB)

implementation defined behavior

unspecified behavior

Compile-time

Run-time

Undefined behavior

bool p;
if (p)
{
  std::cout << "p";
}
if (!p)
{
  std::cout << "!p";
}
bool will_increment_overflow(int x)
{
  if (x + 1 < x)
  {
    return true;
  }
  return false;
}
bool will_increment_overflow(int x)
{
  return false;
}
  p!p
bool p = init_val();
if (p)
{
  std::cout << "p";
}
if (!p)
{
  std::cout << "!p";
}
bool will_increment_overflow(int x)
{
  return x == std::numeric_limits<int>::max();
}

assertions

assert(condition)
static_assert(condition, message)
static_assert(condition)
  • preconditions
  • postconditions
  • invariants
condition
Invalid Operation
Invalid Argument
Implementation Error

Termination

std::exit
std::quick_exit
std::_Exit
std::terminate
std::abort
std::atexit
std::at_quick_exit
-
std::terminate_handler
std::signal
-
-
-
std::abort()
-

function

handler

default handler

Exit Codes

  • EXIT_SUCCESS
  • EXIT_FAILURE
<cstdlib>
<cstdlib>
<cstdlib>
<cstdlib>
<exception>
<cstdlib>
[[noreturn]]
[[noreturn]] void Panic(std::string msg)
{
  std::cerr << "Fatal error occured: " << msg;
  std::abort();
}
Out of Memory
Runtime Error

error codes

void try_process_names()
{
  file_t f;
  int err = try_open_file("names.txt", &f);
  if (err == FILE_ERROR)
  {
    std::cerr << "Cannot open file";
  }
  else
  {
    process(f);
  }
}
int try_open_file(const char* path, file_t* t)
{
  os_file_t* native_file = os_open_file(path);
  if (os_file_t)
  {
    (*t) = wrap_native_file(native_file);
    return NO_ERROR;
  }
  else
  {
    return FILE_ERROR;
  }
}

error codes

errorCodeType readFile {
    initialize errorCode = 0;
    
    open the file;
    if (theFileIsOpen) {
        determine the length of the file;
        if (gotTheFileLength) {
            allocate that much memory;
            if (gotEnoughMemory) {
                read the file into memory;
                if (readFailed) {
                    errorCode = -1;
                }
            } else {
                errorCode = -2;
            }
        } else {
            errorCode = -3;
        }
        close the file;
        if (theFileDidntClose && errorCode == 0) {
            errorCode = -4;
        } else {
            errorCode = errorCode and -4;
        }
    } else {
        errorCode = -5;
    }
    return errorCode;
}
readFile {
    try {
        open the file;
        determine its size;
        allocate that much memory;
        read the file into memory;
        close the file;
    } catch (fileOpenFailed) {
       doSomething;
    } catch (sizeDeterminationFailed) {
        doSomething;
    } catch (memoryAllocationFailed) {
        doSomething;
    } catch (readFailed) {
        doSomething;
    } catch (fileCloseFailed) {
        doSomething;
    }
}

Exceptions

errorCodeType readFile {
    initialize errorCode = 0;
    
    open the file;
    if (theFileIsOpen) {
        determine the length of the file;
        if (gotTheFileLength) {
            allocate that much memory;
            if (gotEnoughMemory) {
                read the file into memory;
                if (readFailed) {
                    errorCode = -1;
                }
            } else {
                errorCode = -2;
            }
        } else {
            errorCode = -3;
        }
        close the file;
        if (theFileDidntClose && errorCode == 0) {
            errorCode = -4;
        } else {
            errorCode = errorCode and -4;
        }
    } else {
        errorCode = -5;
    }
    return errorCode;
}
readFile {
    try {
        open the file;
        determine its size;
        allocate that much memory;
        read the file into memory;
        close the file;
    } catch (fileOpenFailed) {
       doSomething;
    } catch (sizeDeterminationFailed) {
        doSomething;
    } catch (memoryAllocationFailed) {
        doSomething;
    } catch (readFailed) {
        doSomething;
    } catch (fileCloseFailed) {
        doSomething;
    }
}

Exceptions

void process_names()
{
  try 
  {
    file f = open_file("names.txt");
    process(f);
  }
  catch(const std::exception& e)
  {
    std::cerr << e.what();
  }
}
file_t open_file(const char* path)
{
  os_file_t* native_file = os_open_file(path);
  if (os_file_t)
  {
    return wrap_native_file(native_file);
  }
  else
  {
    throw std::runtime_error("Cannot open file");
  }
}

Exceptions

void f() {
  throw std::runtime_error();
}

void g() { f(); }
void h() { f(); }
void i() {
  try {
    h();
  }
  catch(const std::runtime_error& e) {
    ...
  }
}
throw std::runtime_error();
throw 5;
throw "Hello world";

catch(...) {}
throw;
void f()
try {

}
catch (...) {

}
void f() {
  try {

  }
  catch (const std::ios_base::failure& e) {

  }
  catch (const std::runtime_error& e) {

  }
  catch (const std::exception& e) {

  }
  catch (...) {

  }
}

Exceptions

Exceptions vs error codes

Returning values or nothing

Database

entry

find(key)

Returning values or nothing

entry* find(const std::string& key) noexcept;

bool find(const std::string& key, entry& out) noexcept;

entry find(const std::string& key); // throw if not found

entry find(const std::string& key) noexcept; // assume that key is valid, ub if not found

struct result_t
{
  entry result;
  bool has_result;
}
result_t find(const std::string& key) noexcept;

Returning values or nothing

#include <optional>

std::optional<entry> find(const std::string& key) noexcept;
void useFind() {
   auto result = find("Bob");
   if (result) {
     std::cout << "Bob has been found!";
     std::cout << "Bob's data is" << *result;
   }
   if (result.has_value()) {
     std::cout << "Bob has been found!";
     std::cout << "Bob's data is" << result.value();
   }
   if (!result) {
     std::cout << *result; // UB
     std::cout << result.value(); // throw std::bad_optional_access
   }
   if (result == std::nullopt) {
     std::cout << result.value_or("Bob not found");
   }
}

Other error mechanisms

  • signals
  • floating point environment exceptions
  • etc.

Errors

Errors

By Jan Bielak

Errors

A presentation about compilation errors, the as-if rule, undefined behavior, implementation defined behavior, error codes, std::optional, std::abort, exceptions. It is presented here: https://www.youtube.com/watch?v=ASOc73uTsdo .

  • 586