Add the first rough draft of memcheck stuff in bcl

This is to help me catch bugs in client code while using bcl.

Signed-off-by: Gavin D. Howard <gavin@gavinhoward.com>
diff --git a/include/library.h b/include/library.h
index df94f1f..fa1d7b7 100644
--- a/include/library.h
+++ b/include/library.h
@@ -47,6 +47,147 @@
 #include <num.h>
 #include <vm.h>
 
+#if BC_ENABLE_MEMCHECK
+
+/**
+ * A typedef for Valgrind builds. This is to add a generation index for error
+ * checking.
+ */
+typedef struct BclNum
+{
+	/// The number.
+	BcNum n;
+
+	/// The generation index.
+	size_t gen_idx;
+
+} BclNum;
+
+/**
+ * Clears the generation byte in a BclNumber and returns the value.
+ * @param n  The BclNumber.
+ * @return   The value of the index.
+ */
+#define BCL_NO_GEN(n) \
+	((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)))
+
+/**
+ * Gets the generation index in a BclNumber.
+ * @param n  The BclNumber.
+ * @return   The generation index.
+ */
+#define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT))
+
+/**
+ * Turns a BclNumber into a BcNum.
+ * @param c  The context.
+ * @param n  The BclNumber.
+ */
+#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n)))
+
+/**
+ * Clears the generation index top byte in the BclNumber.
+ * @param n  The BclNumber.
+ */
+#define BCL_CLEAR_GEN(n)                                                        \
+	do                                                                         \
+	{                                                                          \
+		(n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \
+	}                                                                          \
+	while (0)
+
+#define BCL_CHECK_NUM_GEN(c, bn)         \
+	do                                   \
+	{                                    \
+		size_t gen_ = BCL_GET_GEN(bn);   \
+		BclNum* ptr_ = BCL_NUM(c, bn);   \
+		if (BCL_NUM_ARRAY(ptr_) == NULL) \
+		{                                \
+			bcl_nonexistentNum();        \
+		}                                \
+		if (gen_ != ptr_->gen_idx)       \
+		{                                \
+			bcl_invalidGeneration();     \
+		}                                \
+	}                                    \
+	while (0)
+
+
+#define BCL_CHECK_NUM_VALID(c, bn)       \
+	do                                   \
+	{                                    \
+		size_t idx_ = BCL_NO_GEN(bn);    \
+		if ((c)->nums.len <= idx_)       \
+		{                                \
+			bcl_numIdxOutOfRange();      \
+		}                                \
+		BCL_CHECK_NUM_GEN(c, bn);        \
+	}                                    \
+	while (0)
+
+/**
+ * Returns the limb array of the number.
+ * @param bn  The number.
+ * @return    The limb array.
+ */
+#define BCL_NUM_ARRAY(bn) ((bn)->n.num)
+
+/**
+ * Returns the limb array of the number for a non-pointer.
+ * @param bn  The number.
+ * @return    The limb array.
+ */
+#define BCL_NUM_ARRAY_NP(bn) ((bn).n.num)
+
+/**
+ * Returns the BcNum pointer.
+ * @param bn  The number.
+ * @return    The BcNum pointer.
+ */
+#define BCL_NUM_NUM(bn) (&(bn)->n)
+
+/**
+ * Returns the BcNum pointer for a non-pointer.
+ * @param bn  The number.
+ * @return    The BcNum pointer.
+ */
+#define BCL_NUM_NUM_NP(bn) (&(bn).n)
+
+// These functions only abort. They exist to give developers some idea of what
+// went wrong when bugs are found, if they look at the Valgrind stack trace.
+
+BC_NORETURN void
+bcl_invalidGeneration(void);
+
+BC_NORETURN void
+bcl_nonexistentNum(void);
+
+BC_NORETURN void
+bcl_numIdxOutOfRange(void);
+
+#else // BC_ENABLE_MEMCHECK
+
+/**
+ * A typedef for non-Valgrind builds.
+ */
+typedef BcNum BclNum;
+
+#define BCL_NO_GEN(n) (n)
+#define BCL_GET_GEN(n) (n)
+#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, (n).i))
+#define BCL_CLEAR_GEN(n) ((void) (n))
+
+#define BCL_CHECK_NUM_GEN(c, bn)
+#define BCL_CHECK_NUM_VALID(c, n)
+
+#define BCL_NUM_ARRAY(n) ((bn)->num)
+#define BCL_NUM_ARRAY_NP(bn) ((bn).num)
+
+#define BCL_NUM_NUM(bn) (bn)
+#define BCL_NUM_NUM_NP(bn) (&(bn))
+
+#endif // BC_ENABLE_MEMCHECK
+
 /**
  * A header that sets a jump.
  * @param vm  The thread data.
@@ -88,19 +229,19 @@
  * idx.
  * @param c    The context.
  * @param e    The error.
- * @param n    The number.
+ * @param bn   The number.
  * @param idx  The idx to set as the return value.
  */
-#define BC_MAYBE_SETUP(c, e, n, idx)                \
-	do                                              \
-	{                                               \
-		if (BC_ERR((e) != BCL_ERROR_NONE))          \
-		{                                           \
-			if ((n).num != NULL) bc_num_free(&(n)); \
-			idx.i = 0 - (size_t) (e);               \
-		}                                           \
-		else idx = bcl_num_insert(c, &(n));         \
-	}                                               \
+#define BC_MAYBE_SETUP(c, e, bn, idx)                                          \
+	do                                                                         \
+	{                                                                          \
+		if (BC_ERR((e) != BCL_ERROR_NONE))                                     \
+		{                                                                      \
+			if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \
+			idx.i = 0 - (size_t) (e);                                          \
+		}                                                                      \
+		else idx = bcl_num_insert(c, &(bn));                                   \
+	}                                                                          \
 	while (0)
 
 /**
@@ -162,11 +303,12 @@
 			if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
 			else                                                   \
 			{                                                      \
-				BclNumber n_num;                                   \
-				n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM;      \
-				return n_num;                                      \
+				BclNumber n_num_;                                  \
+				n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM;     \
+				return n_num_;                                     \
 			}                                                      \
 		}                                                          \
+		BCL_CHECK_NUM_GEN(c, n);                                   \
 	}                                                              \
 	while (0)
 
@@ -189,26 +331,24 @@
 			}                                          \
 			else return BCL_ERROR_INVALID_NUM;         \
 		}                                              \
+		BCL_CHECK_NUM_GEN(c, n);                       \
 	}                                                  \
 	while (0)
 
 //clang-format on
 
 /**
- * Turns a BclNumber into a BcNum.
+ * Grows the context's nums array if necessary.
  * @param c  The context.
- * @param n  The BclNumber.
  */
-#define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i))
-
-#define BC_GROW_NUMS(ctxt)                   \
-	do                                       \
-	{                                        \
-		if ((ctxt)->free_nums.len == 0)      \
-		{                                    \
-			bc_vec_grow(&((ctxt)->nums), 1); \
-		}                                    \
-	}                                        \
+#define BCL_GROW_NUMS(c)                  \
+	do                                    \
+	{                                     \
+		if ((c)->free_nums.len == 0)      \
+		{                                 \
+			bc_vec_grow(&((c)->nums), 1); \
+		}                                 \
+	}                                     \
 	while (0)
 
 /**
diff --git a/src/library.c b/src/library.c
index 47e114e..71f3554 100644
--- a/src/library.c
+++ b/src/library.c
@@ -60,6 +60,28 @@
 // cannot assume that allocation failures are fatal. So we have to reset the
 // jumps every time to ensure that the locals will be correct after jumping.
 
+#if BC_ENABLE_MEMCHECK
+
+BC_NORETURN void
+bcl_invalidGeneration(void)
+{
+	abort();
+}
+
+BC_NORETURN void
+bcl_nonexistentNum(void)
+{
+	abort();
+}
+
+BC_NORETURN void
+bcl_numIdxOutOfRange(void)
+{
+	abort();
+}
+
+#endif // BC_ENABLE_MEMCHECK
+
 static BclTls* tls = NULL;
 static BclTls tls_real;
 
@@ -364,7 +386,7 @@
 	// malloc() is appropriate here.
 	ctxt = bc_vm_malloc(sizeof(BclCtxt));
 
-	bc_vec_init(&ctxt->nums, sizeof(BcNum), BC_DTOR_BCL_NUM);
+	bc_vec_init(&ctxt->nums, sizeof(BclNum), BC_DTOR_BCL_NUM);
 	bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE);
 
 	ctxt->scale = 0;
@@ -446,6 +468,10 @@
 
 	BC_CHECK_CTXT_ERR(vm, ctxt);
 
+	// We need to clear the top byte in memcheck mode. We can do this because
+	// the parameter is a copy.
+	BCL_CLEAR_GEN(n);
+
 	// Errors are encoded as (0 - error_code). If the index is in that range, it
 	// is an encoded error.
 	if (n.i >= ctxt->nums.len)
@@ -463,14 +489,14 @@
  * @return      The resulting BclNumber from the insert.
  */
 static BclNumber
-bcl_num_insert(BclContext ctxt, BcNum* restrict n)
+bcl_num_insert(BclContext ctxt, BclNum* restrict n)
 {
 	BclNumber idx;
 
 	// If there is a free spot...
 	if (ctxt->free_nums.len)
 	{
-		BcNum* ptr;
+		BclNum* ptr;
 
 		// Get the index of the free spot and remove it.
 		idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
@@ -478,10 +504,28 @@
 
 		// Copy the number into the spot.
 		ptr = bc_vec_item(&ctxt->nums, idx.i);
-		memcpy(ptr, n, sizeof(BcNum));
+
+		memcpy(BCL_NUM_NUM(ptr), n, sizeof(BcNum));
+
+#if BC_ENABLE_MEMCHECK
+
+		ptr->gen_idx += 1;
+
+		if (ptr->gen_idx == UCHAR_MAX)
+		{
+			ptr->gen_idx = 0;
+		}
+
+		idx.i |= (ptr->gen_idx << ((sizeof(size_t) - 1) * CHAR_BIT));
+
+#endif // BC_ENABLE_MEMCHECK
 	}
 	else
 	{
+#if BC_ENABLE_MEMCHECK
+		n->gen_idx = 0;
+#endif // BC_ENABLE_MEMCHECK
+
 		// Just push the number onto the vector.
 		idx.i = ctxt->nums.len;
 		bc_vec_push(&ctxt->nums, n);
@@ -494,7 +538,7 @@
 bcl_num_create(void)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum n;
+	BclNum n;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -503,9 +547,9 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
-	bc_num_init(&n, BC_NUM_DEF_SIZE);
+	bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
 
 err:
 
@@ -522,26 +566,34 @@
  * @param num   The number to destroy.
  */
 static void
-bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum* restrict num)
+bcl_num_dtor(BclContext ctxt, BclNumber n, BclNum* restrict num)
 {
-	assert(num != NULL && num->num != NULL);
+	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
+
+	BCL_CLEAR_GEN(n);
 
 	bcl_num_destruct(num);
 	bc_vec_push(&ctxt->free_nums, &n);
+
+#if BC_ENABLE_MEMCHECK
+	num->n.num = NULL;
+#endif // BC_ENABLE_MEMCHECK
 }
 
 void
 bcl_num_free(BclNumber n)
 {
-	BcNum* num;
+	BclNum* num;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
-	assert(n.i < ctxt->nums.len);
+	BCL_CHECK_NUM_VALID(ctxt, n);
 
-	num = BC_NUM(ctxt, n);
+	assert(BCL_NO_GEN(n) < ctxt->nums.len);
+
+	num = BCL_NUM(ctxt, n);
 
 	bcl_num_dtor(ctxt, n, num);
 }
@@ -550,24 +602,28 @@
 bcl_copy(BclNumber d, BclNumber s)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* dest;
-	BcNum* src;
+	BclNum* dest;
+	BclNum* src;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ERR(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, d);
+	BCL_CHECK_NUM_VALID(ctxt, s);
+
 	BC_FUNC_HEADER(vm, err);
 
-	assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len);
+	assert(BCL_NO_GEN(d) < ctxt->nums.len);
+	assert(BCL_NO_GEN(s) < ctxt->nums.len);
 
-	dest = BC_NUM(ctxt, d);
-	src = BC_NUM(ctxt, s);
+	dest = BCL_NUM(ctxt, d);
+	src = BCL_NUM(ctxt, s);
 
 	assert(dest != NULL && src != NULL);
-	assert(dest->num != NULL && src->num != NULL);
+	assert(BCL_NUM_ARRAY(dest) != NULL && BCL_NUM_ARRAY(src) != NULL);
 
-	bc_num_copy(dest, src);
+	bc_num_copy(BCL_NUM_NUM(dest), BCL_NUM_NUM(src));
 
 err:
 
@@ -580,26 +636,28 @@
 bcl_dup(BclNumber s)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum *src, dest;
+	BclNum *src, dest;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, s);
+
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
-	assert(s.i < ctxt->nums.len);
+	assert(BCL_NO_GEN(s) < ctxt->nums.len);
 
-	src = BC_NUM(ctxt, s);
+	src = BCL_NUM(ctxt, s);
 
-	assert(src != NULL && src->num != NULL);
+	assert(src != NULL && BCL_NUM_NUM(src) != NULL);
 
 	// Copy the number.
-	bc_num_clear(&dest);
-	bc_num_createCopy(&dest, src);
+	bc_num_clear(BCL_NUM_NUM(&dest));
+	bc_num_createCopy(BCL_NUM_NUM(&dest), BCL_NUM_NUM(src));
 
 err:
 
@@ -612,75 +670,81 @@
 void
 bcl_num_destruct(void* num)
 {
-	BcNum* n = (BcNum*) num;
+	BclNum* n = (BclNum*) num;
 
 	assert(n != NULL);
 
-	if (n->num == NULL) return;
+	if (BCL_NUM_ARRAY(n) == NULL) return;
 
-	bc_num_free(num);
-	bc_num_clear(num);
+	bc_num_free(BCL_NUM_NUM(n));
+	bc_num_clear(BCL_NUM_NUM(n));
 }
 
 bool
 bcl_num_neg(BclNumber n)
 {
-	BcNum* num;
+	BclNum* num;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	assert(n.i < ctxt->nums.len);
 
-	num = BC_NUM(ctxt, n);
+	num = BCL_NUM(ctxt, n);
 
-	assert(num != NULL && num->num != NULL);
+	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
 
-	return BC_NUM_NEG(num) != 0;
+	return BC_NUM_NEG(BCL_NUM_NUM(num)) != 0;
 }
 
 void
 bcl_num_setNeg(BclNumber n, bool neg)
 {
-	BcNum* num;
+	BclNum* num;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	assert(n.i < ctxt->nums.len);
 
-	num = BC_NUM(ctxt, n);
+	num = BCL_NUM(ctxt, n);
 
-	assert(num != NULL && num->num != NULL);
+	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
 
-	num->rdx = BC_NUM_NEG_VAL(num, neg);
+	BCL_NUM_NUM(num)->rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM(num), neg);
 }
 
 size_t
 bcl_num_scale(BclNumber n)
 {
-	BcNum* num;
+	BclNum* num;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	assert(n.i < ctxt->nums.len);
 
-	num = BC_NUM(ctxt, n);
+	num = BCL_NUM(ctxt, n);
 
-	assert(num != NULL && num->num != NULL);
+	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
 
-	return bc_num_scale(num);
+	return bc_num_scale(BCL_NUM_NUM(num));
 }
 
 BclError
 bcl_num_setScale(BclNumber n, size_t scale)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* nptr;
+	BclNum* nptr;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
@@ -688,16 +752,24 @@
 
 	BC_CHECK_NUM_ERR(ctxt, n);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	BC_FUNC_HEADER(vm, err);
 
 	assert(n.i < ctxt->nums.len);
 
-	nptr = BC_NUM(ctxt, n);
+	nptr = BCL_NUM(ctxt, n);
 
-	assert(nptr != NULL && nptr->num != NULL);
+	assert(nptr != NULL && BCL_NUM_ARRAY(nptr) != NULL);
 
-	if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale);
-	else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale);
+	if (scale > BCL_NUM_NUM(nptr)->scale)
+	{
+		bc_num_extend(BCL_NUM_NUM(nptr), scale - BCL_NUM_NUM(nptr)->scale);
+	}
+	else if (scale < BCL_NUM_NUM(nptr)->scale)
+	{
+		bc_num_truncate(BCL_NUM_NUM(nptr), BCL_NUM_NUM(nptr)->scale - scale);
+	}
 
 err:
 
@@ -709,41 +781,45 @@
 size_t
 bcl_num_len(BclNumber n)
 {
-	BcNum* num;
+	BclNum* num;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	assert(n.i < ctxt->nums.len);
 
-	num = BC_NUM(ctxt, n);
+	num = BCL_NUM(ctxt, n);
 
-	assert(num != NULL && num->num != NULL);
+	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
 
-	return bc_num_len(num);
+	return bc_num_len(BCL_NUM_NUM(num));
 }
 
 BclError
 bcl_bigdig(BclNumber n, BclBigDig* result)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* num;
+	BclNum* num;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ERR(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	BC_FUNC_HEADER(vm, err);
 
 	assert(n.i < ctxt->nums.len);
 	assert(result != NULL);
 
-	num = BC_NUM(ctxt, n);
+	num = BCL_NUM(ctxt, n);
 
-	assert(num != NULL && num->num != NULL);
+	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
 
-	*result = bc_num_bigdig(num);
+	*result = bc_num_bigdig(BCL_NUM_NUM(num));
 
 err:
 
@@ -757,7 +833,7 @@
 bcl_bigdig2num(BclBigDig val)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum n;
+	BclNum n;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -766,9 +842,9 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
-	bc_num_createFromBigdig(&n, val);
+	bc_num_createFromBigdig(BCL_NUM_NUM_NP(n), val);
 
 err:
 
@@ -791,9 +867,9 @@
            const BcNumBinaryOpReq req)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* aptr;
-	BcNum* bptr;
-	BcNum c;
+	BclNum* aptr;
+	BclNum* bptr;
+	BclNum c;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -805,21 +881,22 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
 
-	aptr = BC_NUM(ctxt, a);
-	bptr = BC_NUM(ctxt, b);
+	aptr = BCL_NUM(ctxt, a);
+	bptr = BCL_NUM(ctxt, b);
 
 	assert(aptr != NULL && bptr != NULL);
-	assert(aptr->num != NULL && bptr->num != NULL);
+	assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
 
 	// Clear and initialize the result.
-	bc_num_clear(&c);
-	bc_num_init(&c, req(aptr, bptr, ctxt->scale));
+	bc_num_clear(BCL_NUM_NUM_NP(c));
+	bc_num_init(BCL_NUM_NUM_NP(c),
+	            req(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale));
 
-	op(aptr, bptr, &c, ctxt->scale);
+	op(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(c), ctxt->scale);
 
 err:
 
@@ -885,8 +962,8 @@
 bcl_sqrt(BclNumber a)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* aptr;
-	BcNum b;
+	BclNum* aptr;
+	BclNum b;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -897,13 +974,13 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	assert(a.i < ctxt->nums.len);
 
-	aptr = BC_NUM(ctxt, a);
+	aptr = BCL_NUM(ctxt, a);
 
-	bc_num_sqrt(aptr, &b, ctxt->scale);
+	bc_num_sqrt(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), ctxt->scale);
 
 err:
 
@@ -919,9 +996,9 @@
 {
 	BclError e = BCL_ERROR_NONE;
 	size_t req;
-	BcNum* aptr;
-	BcNum* bptr;
-	BcNum cnum, dnum;
+	BclNum* aptr;
+	BclNum* bptr;
+	BclNum cnum, dnum;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
@@ -932,28 +1009,29 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	assert(c != NULL && d != NULL);
 
-	aptr = BC_NUM(ctxt, a);
-	bptr = BC_NUM(ctxt, b);
+	aptr = BCL_NUM(ctxt, a);
+	bptr = BCL_NUM(ctxt, b);
 
 	assert(aptr != NULL && bptr != NULL);
-	assert(aptr->num != NULL && bptr->num != NULL);
+	assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
 
-	bc_num_clear(&cnum);
-	bc_num_clear(&dnum);
+	bc_num_clear(BCL_NUM_NUM_NP(cnum));
+	bc_num_clear(BCL_NUM_NUM_NP(dnum));
 
-	req = bc_num_divReq(aptr, bptr, ctxt->scale);
+	req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale);
 
 	// Initialize the numbers.
-	bc_num_init(&cnum, req);
+	bc_num_init(BCL_NUM_NUM_NP(cnum), req);
 	BC_UNSETJMP(vm);
 	BC_SETJMP(vm, err);
-	bc_num_init(&dnum, req);
+	bc_num_init(BCL_NUM_NUM_NP(dnum), req);
 
-	bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale);
+	bc_num_divmod(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(cnum),
+	              BCL_NUM_NUM_NP(dnum), ctxt->scale);
 
 err:
 
@@ -965,8 +1043,8 @@
 	if (BC_ERR(vm->err))
 	{
 		// Free the results.
-		if (cnum.num != NULL) bc_num_free(&cnum);
-		if (dnum.num != NULL) bc_num_free(&dnum);
+		if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&cnum);
+		if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&dnum);
 
 		// Make sure the return values are invalid.
 		c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
@@ -991,10 +1069,10 @@
 {
 	BclError e = BCL_ERROR_NONE;
 	size_t req;
-	BcNum* aptr;
-	BcNum* bptr;
-	BcNum* cptr;
-	BcNum d;
+	BclNum* aptr;
+	BclNum* bptr;
+	BclNum* cptr;
+	BclNum d;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -1007,27 +1085,29 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
 	assert(c.i < ctxt->nums.len);
 
-	aptr = BC_NUM(ctxt, a);
-	bptr = BC_NUM(ctxt, b);
-	cptr = BC_NUM(ctxt, c);
+	aptr = BCL_NUM(ctxt, a);
+	bptr = BCL_NUM(ctxt, b);
+	cptr = BCL_NUM(ctxt, c);
 
 	assert(aptr != NULL && bptr != NULL && cptr != NULL);
-	assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL);
+	assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr) != NULL &&
+	       BCL_NUM_NUM(cptr) != NULL);
 
 	// Prepare the result.
-	bc_num_clear(&d);
+	bc_num_clear(BCL_NUM_NUM_NP(d));
 
-	req = bc_num_divReq(aptr, cptr, 0);
+	req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(cptr), 0);
 
 	// Initialize the result.
-	bc_num_init(&d, req);
+	bc_num_init(BCL_NUM_NUM_NP(d), req);
 
-	bc_num_modexp(aptr, bptr, cptr, &d);
+	bc_num_modexp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM(cptr),
+	              BCL_NUM_NUM_NP(d));
 
 err:
 
@@ -1045,65 +1125,72 @@
 ssize_t
 bcl_cmp(BclNumber a, BclNumber b)
 {
-	BcNum* aptr;
-	BcNum* bptr;
+	BclNum* aptr;
+	BclNum* bptr;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, a);
+	BCL_CHECK_NUM_VALID(ctxt, b);
+
 	assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
 
-	aptr = BC_NUM(ctxt, a);
-	bptr = BC_NUM(ctxt, b);
+	aptr = BCL_NUM(ctxt, a);
+	bptr = BCL_NUM(ctxt, b);
 
 	assert(aptr != NULL && bptr != NULL);
-	assert(aptr->num != NULL && bptr->num != NULL);
+	assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr));
 
-	return bc_num_cmp(aptr, bptr);
+	return bc_num_cmp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr));
 }
 
 void
 bcl_zero(BclNumber n)
 {
-	BcNum* nptr;
+	BclNum* nptr;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	assert(n.i < ctxt->nums.len);
 
-	nptr = BC_NUM(ctxt, n);
+	nptr = BCL_NUM(ctxt, n);
 
-	assert(nptr != NULL && nptr->num != NULL);
+	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
 
-	bc_num_zero(nptr);
+	bc_num_zero(BCL_NUM_NUM(nptr));
 }
 
 void
 bcl_one(BclNumber n)
 {
-	BcNum* nptr;
+	BclNum* nptr;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	assert(n.i < ctxt->nums.len);
 
-	nptr = BC_NUM(ctxt, n);
+	nptr = BCL_NUM(ctxt, n);
 
-	assert(nptr != NULL && nptr->num != NULL);
+	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
 
-	bc_num_one(nptr);
+	bc_num_one(BCL_NUM_NUM(nptr));
 }
 
 BclNumber
 bcl_parse(const char* restrict val)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum n;
+	BclNum n;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -1113,7 +1200,7 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	assert(val != NULL);
 
@@ -1130,13 +1217,17 @@
 	}
 
 	// Clear and initialize the number.
-	bc_num_clear(&n);
-	bc_num_init(&n, BC_NUM_DEF_SIZE);
+	bc_num_clear(BCL_NUM_NUM_NP(n));
+	bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
 
-	bc_num_parse(&n, val, (BcBigDig) ctxt->ibase);
+	bc_num_parse(BCL_NUM_NUM_NP(n), val, (BcBigDig) ctxt->ibase);
 
 	// Set the negative.
+#if BC_ENABLE_MEMCHECK
+	n.n.rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM_NP(n), neg);
+#else // BC_ENABLE_MEMCHECK
 	n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
+#endif // BC_ENABLE_MEMCHECK
 
 err:
 
@@ -1149,28 +1240,30 @@
 char*
 bcl_string(BclNumber n)
 {
-	BcNum* nptr;
+	BclNum* nptr;
 	char* str = NULL;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
 	BC_CHECK_CTXT_ASSERT(vm, ctxt);
 
+	BCL_CHECK_NUM_VALID(ctxt, n);
+
 	if (BC_ERR(n.i >= ctxt->nums.len)) return str;
 
 	BC_FUNC_HEADER(vm, err);
 
 	assert(n.i < ctxt->nums.len);
 
-	nptr = BC_NUM(ctxt, n);
+	nptr = BCL_NUM(ctxt, n);
 
-	assert(nptr != NULL && nptr->num != NULL);
+	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
 
 	// Clear the buffer.
 	bc_vec_popAll(&vm->out);
 
 	// Print to the buffer.
-	bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
+	bc_num_print(BCL_NUM_NUM(nptr), (BcBigDig) ctxt->obase, false);
 	bc_vec_pushByte(&vm->out, '\0');
 
 	// Just dup the string; the caller is responsible for it.
@@ -1190,8 +1283,8 @@
 bcl_irand(BclNumber a)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* aptr;
-	BcNum b;
+	BclNum* aptr;
+	BclNum b;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -1202,19 +1295,19 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	assert(a.i < ctxt->nums.len);
 
-	aptr = BC_NUM(ctxt, a);
+	aptr = BCL_NUM(ctxt, a);
 
-	assert(aptr != NULL && aptr->num != NULL);
+	assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
 
 	// Clear and initialize the result.
-	bc_num_clear(&b);
-	bc_num_init(&b, BC_NUM_DEF_SIZE);
+	bc_num_clear(BCL_NUM_NUM_NP(b));
+	bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE);
 
-	bc_num_irand(aptr, &b, &vm->rng);
+	bc_num_irand(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), &vm->rng);
 
 err:
 
@@ -1275,7 +1368,7 @@
 bcl_frand(size_t places)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum n;
+	BclNum n;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -1284,13 +1377,13 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	// Clear and initialize the number.
-	bc_num_clear(&n);
-	bc_num_init(&n, BC_NUM_DEF_SIZE);
+	bc_num_clear(BCL_NUM_NUM_NP(n));
+	bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
 
-	bcl_frandHelper(&n, places);
+	bcl_frandHelper(BCL_NUM_NUM_NP(n), places);
 
 err:
 
@@ -1339,8 +1432,8 @@
 bcl_ifrand(BclNumber a, size_t places)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* aptr;
-	BcNum b;
+	BclNum* aptr;
+	BclNum b;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -1350,19 +1443,19 @@
 
 	BC_FUNC_HEADER(vm, err);
 
-	BC_GROW_NUMS(ctxt);
+	BCL_GROW_NUMS(ctxt);
 
 	assert(a.i < ctxt->nums.len);
 
-	aptr = BC_NUM(ctxt, a);
+	aptr = BCL_NUM(ctxt, a);
 
-	assert(aptr != NULL && aptr->num != NULL);
+	assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
 
 	// Clear and initialize the number.
-	bc_num_clear(&b);
-	bc_num_init(&b, BC_NUM_DEF_SIZE);
+	bc_num_clear(BCL_NUM_NUM_NP(b));
+	bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE);
 
-	bcl_ifrandHelper(aptr, &b, places);
+	bcl_ifrandHelper(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), places);
 
 err:
 
@@ -1379,7 +1472,7 @@
 bcl_rand_seedWithNum(BclNumber n)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum* nptr;
+	BclNum* nptr;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
 
@@ -1390,11 +1483,11 @@
 
 	assert(n.i < ctxt->nums.len);
 
-	nptr = BC_NUM(ctxt, n);
+	nptr = BCL_NUM(ctxt, n);
 
-	assert(nptr != NULL && nptr->num != NULL);
+	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
 
-	bc_num_rng(nptr, &vm->rng);
+	bc_num_rng(BCL_NUM_NUM(nptr), &vm->rng);
 
 err:
 
@@ -1442,7 +1535,7 @@
 bcl_rand_seed2num(void)
 {
 	BclError e = BCL_ERROR_NONE;
-	BcNum n;
+	BclNum n;
 	BclNumber idx;
 	BclContext ctxt;
 	BcVm* vm = bcl_getspecific();
@@ -1452,10 +1545,10 @@
 	BC_FUNC_HEADER(vm, err);
 
 	// Clear and initialize the number.
-	bc_num_clear(&n);
-	bc_num_init(&n, BC_NUM_DEF_SIZE);
+	bc_num_clear(BCL_NUM_NUM_NP(n));
+	bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
 
-	bc_num_createFromRNG(&n, &vm->rng);
+	bc_num_createFromRNG(BCL_NUM_NUM_NP(n), &vm->rng);
 
 err: