magic_numbers revision 767d29c43d98bae8ea95f0ccd2b9653cbcd43310
Magic Numbers
A number of data structures in the ISC and DNS libraries have an unsigned int
magic number as the first field. The purpose of the magic number is
principally to validate that a pointer a subroutine has gotten really points
to the type it claims to be. This helps detect problems caused by resources
being freed prematurely, that have been corrupted, or that have not been
properly initalized. It can also be handy in debugging.
Magic numbers should always be the first field. They never require locking
to access. As to the actual value to be used, something mnemonic is good:
#define TASK_MAGIC 0x5441534BU /* TASK. */
#define VALID_TASK(t) ((t) != NULL && \
(t)->magic == TASK_MAGIC)
#define TASK_MANAGER_MAGIC 0x54534B4DU /* TSKM. */
#define VALID_MANAGER(m) ((m) != NULL && \
(m)->magic ==
TASK_MANAGER_MAGIC)
Unless the memory cost is critical, most objects should have a magic number.
The magic number should be the last field set in a creation routine, so that
an object will never be stamped with a magic number unless it is valid.
The magic number should be set to zero immediately before the object is
freed.
Magic values are generally private to the implementation of the type. I.e.
they are defined in the .c file, not the .h file.
Validation of magic numbers is done by routines that manipulate the type,
not by users of the type. Indeed, user validation is usually not possible
because the magic number is not public.
Magic number checking may become a build option in a future release. E.g.
struct foo {
ISC_MAGIC_DECLARATION
/* ... */
}
foo_create() {
/* ... */
ISC_MAGIC_SET(value);
}
foo_destroy() {
/* ... */
ISC_MAGIC_CLEAR(value);
}
#define FOO_MAGIC 0x00010203U
#define VALID_FOO(f) ISC_MAGIC_VALIDATE(f, FOO_MAGIC)
foo_dosomething(foo *f) {
REQUIRE(VALID_FOO(f));
}