bounds()

One big source of bugs in C is out-of-bounds accesses to arrays. We can add bounds checking using the following macro:


	/* usually put in some project wide common header file */
	#define bounds(_i, _n)	(assert((unsigned)(_i) < (_n)), (_i))

To use this, index arrays using the following idiom:


	array[bounds(i, ARRAY_SIZE)]

First, the index (i) is compared against the array bound (ARRAY_SIZE); then the value of the index is returned. If the index is negative, then the use of the unsigned causes it to be a very large number, and will also cause the bounds check to fail. If assertions are turned off (i.e. NDEBUG is defined), then bounds() just returns the index.

We incorporate the bounds() macro into accessor macros. For instance:


	#define	x_val_int_stack(_s,_i)	\
		x_vals_int_stack(_s)[bounds(_i,x_len_int_stack(_s)-1)]
	#define val_int_stack(_s, _i)	((void)0,x_val_int_stack(_s,_i))

These indexing-accessor macros should be used in place of indexing an accessor macro. Thus:


	void
	pop_int_stack(
		int_stack	stack
		)
	{
	  VERIFY_INT_STACK(stack);

	  #if( CHECKSUM_INT_STACK )
	  {
	    int	len = len_int_stack(stack);

	    x_chksum_int_stack(stack) ^= (unsigned)len;
	    len--;
	    x_chksum_int_stack(stack) ^= 
	    	(unsigned)val_int_stack(stack, len);
	    x_chksum_int_stack(stack) ^= (unsigned)len;
	  }
	  #endif

	  x_len_int_stack(stack)--;

	  VERIFY_INT_STACK(stack);
	}

Of course, this is only used as an example. It doesn't do any additional error checking, since VERIFY_INT_STACK(stack) would already have checked for len being within bounds.


Next Prev Main Top Feedback