More on pointer type-checking

So far, the type checking we have introduced has been approximate; it will sometimes agree that a pointer points to an object of a particular type, even though it doesn't. In particular, two objects of the same size can be confused with each other. For instance, xtype_ptr(int, p) and xntype_ptr(char, sizeof(int), p) will return identical answers.

One solution is to add extra information to allocated memory objects that uniquely identifies its type. The approach shown in this section is to extend the header, and attach this information to the header. The information we add is:

One things to keep in mind: add enough padding at the end of the extended header so that the returned pointer satisfies the alignment requirement of the system. A somewhat portable approach is shown below.


	#include <stddef.h>
	#include <stdlib.h>
	#include <limits.h>

	struct exthdr_ptr {
	  char *	xhp_type_name;
	  unsigned	xhp_number;
	  union {
	    double		xhp_d;
	    unsigned long	xhp_ul;
	    int			xhp_i;
	    void *		xhp_p;
	  } xhp_align;
	};

	#define type_name_exthdr_ptr(_xhp)	((_xhp)->xhp_type_name)
	#define number_exthdr_ptr(_xhp)		((_xhp)->xhp_number)

	#define alloc_exthdr_ptr(_xhp)		\
		((void *)&((_xhp)->xhp_align))

	#define size_exthdr_ptr() \
		offsetof(struct exthdr_ptr, xhp_align);

The xhp_align field is used to ensure that the right amount of padding is added after the extended header. The size_exthdr_ptr() is used to find the total amount of space required for the extra information and the padding.

The appropriate helper functions to allocate memory and checking for correctness are shown below.


	void *
      	do_xalloc(
		unsigned	size,
		char *		type_name,
		unsigned	number
		)
	{
	  struct exthdr_ptr *	hdr = malloc(size + size_exthdr_ptr());

	  type_name_exthdr_ptr(hdr) = type_name;
	  number_exthdr_ptr(hdr) = number;

	  return alloc_exthdr_ptr(hdr);
	}

	void
	do_xfree(
		void *		ptr
		)
	{
	  struct exthdr_ptr *	hdr = get_exthdr_ptr(ptr);

	  free(hdr);
	}


	#define get_exthdr_ptr(_p) \
		((struct exthdr_ptr *)(((unsigned long)(_p))-size_exthdr_ptr()))

	int
	check_exthdr_ptr(
		void *		ptr,
		char *		type_name,
		unsigned	number
		)
	{
	  struct exthdr_ptr *	hdr = get_exthdr_ptr(ptr);

	  if( number != number_exthdr_ptr(hdr) ) {
	    return 0;
	  }

	  if( type_name != type_name_exthdr_ptr(hdr) ) {
	    if( strcmp(type_name, type_name_exthdr_ptr(hdr)) != 0 ) {
	      return 0;
	    }
	    type_name_exthdr_ptr(hdr) = type_name;
	  }

	  return 1;
	}

Finally, we modify the xalloc()/xnalloc() and the xtype_ptr()/xntype_ptr() to enforce the checking


	#define xalloc(_t) \
		((_t*)do_xalloc(sizeof(_t), #_t, UINT_MAX))
	#define xnalloc(_t,_n) \
		((_t*)do_xalloc(sizeof(_t)*(_n), #_t, (_n)))

	#define xtype_ptr(_t, _p) \
		(check_exthdr_ptr(_p, #_t, UINT_MAX))
	#define xntype_ptr(_t, _n, _p) \
		(check_exthdr_ptr(_p, #_t, (_n)))

The only piece of "black-magic" in this approach is the way the string is created. We use #_t to get the name of the type. Hopefully, the string will be the same every time, and we can compare strings simply by comparing pointers. Otherwise, we will have to use strcmp().

The memory image implemented by stack = make_int_stack() is shown below:


	__________
	|   25   |
	|________|
	| 	+---> "struct int_stack"
	|________|	__________
	|UINT_MAX|	|   81   |
	|________|	|________|
stack-->|   16   |	|       +---> "int"
	|________|	|________|
	|    0   |	|   16   |
	|________|	|________|
	|       +----->	|        |
	|________|	|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|        |
			|________|
			|xxxxxxxx|
			|________|

We also have to change xfree()/xnfree() to support this debugging idiom.


	void *
      	do_xfree(
		void *		ptr
		)
	{
	  struct exthdr_ptr *	hdr = get_exthdr_ptr(ptr);
	  type_name_exthdr_ptr(ptr) = 0;
	  number_exthdr_ptr(ptr) = 0;
	  free(ptr);
	}

	#define xfree(_t, _p) \
		( xtype_ptr(_t, _p), \
		  do_xfree(_p) \
		)

	#define xnfree(_t, _n, _p) \
		( xntype_ptr(_t, _n, _p), \
		  do_xfree(_p) \
		)


Next Prev Main Top Feedback