picow-http 0.12.1-4-g9d4fd13
HTTP server for the Raspberry Pi PicoW
Assertions and type checking

Macros

#define PICOW_HTTP_ASSERT(c)
 Assert that a condition is true. More...
 
#define AZ(x)   do { PICOW_HTTP_ASSERT((x) == 0); } while (0)
 Assert that a value is zero or NULL More...
 
#define AN(x)   do { PICOW_HTTP_ASSERT((x) != 0); } while (0)
 Assert that a value is not zero, or not NULL More...
 
#define ZERO_OBJ(to, sz)
 Set an object to all zero. More...
 
#define INIT_OBJ(to, type_magic)
 Initialize an object with its magic number. More...
 
#define FINI_OBJ(to)
 Finalize an object. More...
 
#define VALID_OBJ(ptr, type_magic)    ((ptr) != NULL && (ptr)->magic == (type_magic))
 Return true if an object is valid for its type. More...
 
#define CHECK_OBJ(ptr, type_magic)
 Assert that an object is valid for its type. More...
 
#define CHECK_OBJ_NOTNULL(ptr, type_magic)
 Assert that a pointer is not NULL, and points to an object that is valid for its type. More...
 
#define CHECK_OBJ_ORNULL(ptr, type_magic)
 Assert that a pointer is either NULL, or it points to an object that is valid for its type. More...
 
#define CAST_OBJ(to, from, type_magic)
 Cast a pointer, and if not NULL, assert that it points to an object that is valid for its type. More...
 
#define CAST_OBJ_NOTNULL(to, from, type_magic)
 Cast a pointer, and assert that it it is not NULL and points to an object that is valid for its type. More...
 

Detailed Description

picow-http uses a set of macros to implement assertions that check against a variety of "must not ever happen" errors in debug builds, as well as some common operations for pointers to struct types. The assertions primarily check for "wild pointer" errors – NULL dereferences or other invalid pointer values; but they can be used to check any boolean condition. Violations of an assertion cause a panic when NDEBUG is not defined, as is the case for the CMake Debug build type. When NDEBUG is defined, as for CMake Release builds, the assertions are no-ops. The intent is that errors lead to hard and fast failures during development and debugging, and then the overhead of assertions is removed when debugging is done. Since these mechanisms are sufficiently general and may be relevant for application code, they are provided in the public API.

Many of the assertions check a "magic number", the value of a struct member named magic. The idiom is that magic is the first member of the struct (thus at offset 0 from the struct's starting address), set to an unsigned 32-bit value specific to the struct type:

struct foo {
unsigned magic;
#define FOO_MAGIC (0x47110815)
// ... additional member declarations ...
};

The value of a magic number is best chosen at random, and must be different for every struct type to be checked. To use the type checking code:

If the magic number doesn't match, then the pointer is definitely of the wrong type. If it matches, then it's almost certainly the right type.

This code was inspired by (and much of it copied from) the Varnish cache project (see miniobj.h and the VAS interface).

Macro Definition Documentation

◆ AN

#define AN (   x)    do { PICOW_HTTP_ASSERT((x) != 0); } while (0)

If NDEBUG is not defined, panic if x is zero or NULL. No-op if NDEBUG is defined.

Example:

// Or picow_http/http.h, which includes assertion.h
// In a debugging build, panic if the pointer is NULL
AN(ptr);
#define AN(x)
Assert that a value is not zero, or not NULL
Definition: assertion.h:141
Parameters
[in]xany expression. If x is a pointer, this is a check expecting non-NULL.

◆ AZ

#define AZ (   x)    do { PICOW_HTTP_ASSERT((x) == 0); } while (0)

If NDEBUG is not defined, panic unless x is zero or NULL. No-op if NDEBUG is defined.

Example:

// Or picow_http/http.h, which includes assertion.h
// In a debugging build, panic unless the pointer is NULL
AZ(ptr);
#define AZ(x)
Assert that a value is zero or NULL
Definition: assertion.h:118
Parameters
[in]xany expression. If x is a pointer, this is a check expecting NULL.

◆ CAST_OBJ

#define CAST_OBJ (   to,
  from,
  type_magic 
)
Value:
do { \
(to) = (from); \
if ((to) != NULL) \
CHECK_OBJ((to), (type_magic)); \
} while (0)

Assign from to to, and if NDEBUG is not defined and the pointers are not NULL, then panic if to points to a struct whose magic member is not equal to type_magic.

Example:

// Or picow_http/http.h, which includes assertion.h
struct hndl {
unsigned magic;
#define HNDL_MAGIC (0xee0f1e3a)
// ... additional member declarations ...
};
err_t
hndl_func(void *priv)
{
struct hndl *hndl;
if (priv == NULL) {
hndl = malloc(sizeof(*hndl));
// ...
}
else
// Assert that the non-NULL priv pointer points to a
// valid hndl object.
CAST_OBJ(hndl, priv, HNDL_MAGIC));
// ...
}
#define CAST_OBJ(to, from, type_magic)
Cast a pointer, and if not NULL, assert that it points to an object that is valid for its type.
Definition: assertion.h:459
Parameters
[in]topointer to a struct type for which a magic number has been defined
[in]frompointer
[in]type_magictype-specific magic number constant

◆ CAST_OBJ_NOTNULL

#define CAST_OBJ_NOTNULL (   to,
  from,
  type_magic 
)
Value:
do { \
(to) = (from); \
AN((to)); \
CHECK_OBJ((to), (type_magic)); \
} while (0)

Assign from to to, and if NDEBUG is not defined, then panic if the pointer is NULL, or if after the cast, to points to a struct whose magic member is not equal to type_magic.

Example:

// Or picow_http/http.h, which includes assertion.h
struct hndlr_priv {
unsigned magic;
#define HNDLR_PRIV_MAGIC (0xc71adcbb)
// ... additional member declarations ...
};
err_t
my_hndlr(struct http *http, void *priv)
{
struct hndlr_priv *hndlr_priv;
// Assert that priv is not NULL and points to a valid
// hndlr_priv object.
CAST_OBJ_NOTNULL(hndlr_priv, priv, HNDLR_PRIV_MAGIC));
// ...
}
#define CAST_OBJ_NOTNULL(to, from, type_magic)
Cast a pointer, and assert that it it is not NULL and points to an object that is valid for its type.
Definition: assertion.h:506
Current HTTP connection, request and response.
Parameters
[in]topointer to a struct type for which a magic number has been defined
[in]frompointer
[in]type_magictype-specific magic number constant

◆ CHECK_OBJ

#define CHECK_OBJ (   ptr,
  type_magic 
)
Value:
do { \
PICOW_HTTP_ASSERT((ptr)->magic == type_magic); \
} while (0)

If NDEBUG is not defined, panic if ptr points to a struct whose magic member is not equal to type_magic. No-op if NDEBUG is defined.

Example:

// Or picow_http/http.h, which includes assertion.h
struct quux {
unsigned magic;
#define QUUX_MAGIC (0x39ee7191)
// ... additional member declarations ...
};
err_t
quux_func(struct quux *quux)
{
// Return an error status if the object is NULL
if (quux == NULL)
return ERR_ARG;
// Assert that the object is valid
CHECK_OBJ(quux, QUUX_MAGIC));
// ...
}
#define CHECK_OBJ(ptr, type_magic)
Assert that an object is valid for its type.
Definition: assertion.h:321
Parameters
[in]ptrpointer to a struct type for which a magic number has been defined. MAY NOT be NULL
[in]type_magictype-specific magic number constant

◆ CHECK_OBJ_NOTNULL

#define CHECK_OBJ_NOTNULL (   ptr,
  type_magic 
)
Value:
do { \
PICOW_HTTP_ASSERT((ptr) != NULL); \
PICOW_HTTP_ASSERT((ptr)->magic == type_magic); \
} while (0)

If NDEBUG is not defined, panic if ptr is NULL, or points to a struct whose magic member is not equal to type_magic. No-op if NDEBUG is defined.

Example:

// Or picow_http/http.h, which includes assertion.h
struct foobar {
unsigned magic;
#define FOOBAR_MAGIC (0xf0000ba4)
// ... additional member declarations ...
};
err_t
foobar_func(struct foobar *foobar)
{
// Assert that the pointer is non-NULL and the object is valid
CHECK_OBJ_NOTNULL(foobar, FOOBAR_MAGIC));
// ...
}
#define CHECK_OBJ_NOTNULL(ptr, type_magic)
Assert that a pointer is not NULL, and points to an object that is valid for its type.
Definition: assertion.h:362
Parameters
[in]ptrpointer to a struct type for which a magic number has been defined
[in]type_magictype-specific magic number constant

◆ CHECK_OBJ_ORNULL

#define CHECK_OBJ_ORNULL (   ptr,
  type_magic 
)
Value:
do { \
if ((ptr) != NULL) \
PICOW_HTTP_ASSERT((ptr)->magic == type_magic); \
} while (0)

If NDEBUG is not defined and ptr is not NULL, then panic if ptr points to a struct whose magic member is not equal to type_magic. No-op if NDEBUG is defined.

Example:

// Or picow_http/http.h, which includes assertion.h
struct bazquux {
unsigned magic;
#define BAZQUUX_MAGIC (0x6c0d60cd)
// ... additional member declarations ...
};
err_t
bazquux_func(struct bazquux *bazquux)
{
// If the pointer is non-NULL, assert that the object is valid
CHECK_OBJ_ORNULL(bazquux, BAZQUUX_MAGIC));
if (bazquux == NULL) {
bazquux = malloc(sizeof(*bazquux));
// ...
}
// ...
}
#define CHECK_OBJ_ORNULL(ptr, type_magic)
Assert that a pointer is either NULL, or it points to an object that is valid for its type.
Definition: assertion.h:408
Parameters
[in]ptrpointer to a struct type for which a magic number has been defined
[in]type_magictype-specific magic number constant

◆ FINI_OBJ

#define FINI_OBJ (   to)
Value:
do { \
ZERO_OBJ(&(to)->magic, sizeof (to)->magic); \
to = NULL; \
} while (0)

Set the magic member of the object pointed to by to to 0, and set to to NULL. This ensures that checks will fail if the code subsequently attempts to access the object.

// Or picow_http/http.h, which includes assertion.h
struct bar {
unsigned magic;
#define BAR_MAGIC (0xf000baa4)
// ... additional member declarations ...
};
void
myfunc()
{
struct bar mybar;
INIT_OBJ(&bar, BAR_MAGIC);
// ... use the object locally in the function ...
// Finalize the object, so that subsequent accesses will fail.
FINI_OBJ(&bar);
}
#define FINI_OBJ(to)
Finalize an object.
Definition: assertion.h:240
#define INIT_OBJ(to, type_magic)
Initialize an object with its magic number.
Definition: assertion.h:200
Parameters
[in]topointer to a struct type for which the magic member has been defined

◆ INIT_OBJ

#define INIT_OBJ (   to,
  type_magic 
)
Value:
do { \
ZERO_OBJ(to, sizeof *(to)); \
(to)->magic = (type_magic); \
} while (0)

Set the magic member of the object pointed to by to to type_magic, and all other members to 0.

// Or picow_http/http.h, which includes assertion.h
struct foo {
unsigned magic;
#define FOO_MAGIC (0x47110815)
// ... additional member declarations ...
};
struct foo myfoo;
INIT_OBJ(&myfoo, FOO_MAGIC);
Parameters
[in]topointer to a struct type for which a magic number has been defined
[in]type_magictype-specific magic number constant

◆ PICOW_HTTP_ASSERT

#define PICOW_HTTP_ASSERT (   c)
Value:
do { \
if (!(c)) \
panic("%s(): " #c " false", __func__); \
} while (0)

If NDEBUG is not defined, panic unless c is true (i.e panic if c evaluates to zero). If NDEBUG is defined, PICOW_HTTP_ASSERT is a no-op.

Example:

// Or picow_http/http.h, which includes assertion.h
// In a debugging build, panic unless an expected value is set
PICOW_HTTP_ASSERT(foo == 4711);
#define PICOW_HTTP_ASSERT(c)
Assert that a condition is true.
Definition: assertion.h:91
Parameters
[in]ca boolean expression

◆ VALID_OBJ

#define VALID_OBJ (   ptr,
  type_magic 
)     ((ptr) != NULL && (ptr)->magic == (type_magic))

Example:

// Or picow_http/http.h, which includes assertion.h
struct baz {
unsigned magic;
#define BAZ_MAGIC (0x8c60c6e9)
// ... additional member declarations ...
};
err_t
baz_func(struct baz *baz)
{
// Return an error status if baz is not properly initialized
if (!VALID_OBJ(baz, BAZ_MAGIC))
return ERR_ARG;
// ...
}
#define VALID_OBJ(ptr, type_magic)
Return true if an object is valid for its type.
Definition: assertion.h:280
Parameters
[in]ptrpointer to a struct type for which a magic number has been defined
[in]type_magictype-specific magic number constant
Returns
true if ptr is not NULL and the value of its magic member is type_magic

◆ ZERO_OBJ

#define ZERO_OBJ (   to,
  sz 
)
Value:
do { \
void *(*volatile z_obj)(void *, int, size_t) = memset; \
(void)z_obj(to, 0, sz); \
} while (0)

Set sz bytes starting at address to to 0.

// Or picow_http/http.h, which includes assertion.h
struct foo myfoo;
ZERO_OBJ(&myfoo, sizeof(*myfoo));
#define ZERO_OBJ(to, sz)
Set an object to all zero.
Definition: assertion.h:167
Parameters
[in]toa pointer
[in]sznumber of bytes (commonly from sizeof())