Error Handling

All functions in this project use a common scheme for return codes and error handling.

All functions, except for getters and setters, return the type osd_result. A return code of OSD_OK indicates a successful function call, any other return value indicates an error. The error types are given as one of the OSD_ERROR_*.

Use OSD_SUCCEEDED to check if a function call was successful, and OSD_FAILED to check if it failed.

Use of assertions

Using assertions within libosd causes the application using libosd to crash. A crash can be a good way to fail early, however, it may be used only for non-recoverable errors or programming errors. In consequence, libosd makes use of assertions to check for internal errors (i.e. bugs in libosd), or to check for violated API calling conventions. However, assertions are not used to check for invalid or missing input data from known-to-be-unreliable sources (e.g. from the network, from a user or from the file system).

Assertions are used in the following cases:

  • API calling conventions are not followed.
  • Violoated pre- or postconditions: the internal state when entering or exiting a function isn’t what was expected.

Assertions are not used in in the following scenarios:

  • User input to a function is not valid.
  • Unexpected data was received from the network, from the file system, or similar sources.
  • The communication broke down.

Handling memory allocation errors

In general, out of memory errors returned from malloc() and similar functions are fatal, i.e. cause the program using libosd to crash. This is motivated by the fact that these errors occur very rarely and the associated error handling path is rarely executed and tested.

In some cases where larger memory allocations are required, especially contiguous chunks of memory, error handling is implemented and fallback paths are used.

Example

#include <osd/osd.h>
#include <assert.h>

osd_result rv;

// common case: pass error on to calling function
rv = osd_some_call();
if (OSD_FAILED(rv)) {
  return rv;
}

// check for a successful call
rv = osd_another_call();
if (OSD_SUCCEEDED(rv)) {
  printf("Call successful!\n");
}

// A failing call may not happen and hence is a bug in OSD: use assert()
rv = osd_must_succeed_call();
assert(OSD_SUCCEEDED(rv));

// fatal malloc: assert if the memory allocation failed
char* some_data = malloc(sizeof(char) * 100));
assert(some_data);

Public Interface

typedef int osd_result

Standard return type

OSD_OK

Return code: The operation was successful

OSD_ERROR_FAILURE

Return code: Generic (unknown) failure

OSD_ERROR_DEVICE_ERROR

Return code: debug system returned a failure

OSD_ERROR_DEVICE_INVALID_DATA

Return code: received invalid or malformed data from device

OSD_ERROR_COM

Return code: failed to communicate with device

OSD_ERROR_TIMEDOUT

Return code: operation timed out

OSD_ERROR_NOT_CONNECTED

Return code: not connected to the device

OSD_ERROR_PARTIAL_RESULT

Return code: this is a partial result, not all requested data was obtained

OSD_ERROR_ABORTED

Return code: operation aborted

OSD_ERROR_CONNECTION_FAILED

Return code: connection failed

OSD_ERROR_OOM

Return code: Out of memory

OSD_ERROR_FILE

Return code: file operation failed

OSD_ERROR_MEM_VERIFY_FAILED

Return code: memory verification failed

OSD_ERROR_WRONG_MODULE

Return code: unexpected module type

OSD_FAILED(rv)

Return true if |rv| is an error code

OSD_SUCCEEDED(rv)

Return true if |rv| is a successful return code