Specifying that the pcre2_memctl block must be at the start of all relevant 
blocks simplifies the code.

diff --git a/src/pcre2_context.c b/src/pcre2_context.c
index 20a9df1..3376ef6 100644
--- a/src/pcre2_context.c
+++ b/src/pcre2_context.c
@@ -73,24 +73,23 @@
 *************************************************/
 
 /* This internal function is called to get a block of memory in which the 
-memory control data is to be stored for future use.
+memory control data is to be stored at the start for future use.
 
 Arguments:
   size        amount of memory required
-  offset      offset in memory block to memctl structure
   memctl      pointer to a memctl block or NULL
   
 Returns:      pointer to memory or NULL on failure
 */   
 
 PCRE2_EXP_DEFN void *
-PRIV(memctl_malloc)(size_t size, size_t offset, pcre2_memctl *memctl)
+PRIV(memctl_malloc)(size_t size, pcre2_memctl *memctl)
 {
 pcre2_memctl *newmemctl;
 void *yield = (memctl == NULL)? malloc(size) :
   memctl->malloc(size, memctl->memory_data);
 if (yield == NULL) return NULL; 
-newmemctl = (pcre2_memctl *)(((uint8_t *)yield) + offset);
+newmemctl = (pcre2_memctl *)yield;
 if (memctl == NULL)
   {
   newmemctl->malloc = default_malloc;
@@ -149,9 +148,7 @@
 pcre2_compile_context_create(pcre2_general_context *gcontext)
 {
 pcre2_compile_context *ccontext = PRIV(memctl_malloc)(
-  sizeof(pcre2_real_compile_context), 
-  offsetof(pcre2_real_compile_context, memctl),
-  &(gcontext->memctl)); 
+  sizeof(pcre2_real_compile_context), (pcre2_memctl *)gcontext); 
 if (ccontext == NULL) return NULL;  
 PRIV(compile_context_init)(ccontext, FALSE);
 return ccontext;
@@ -183,9 +180,7 @@
 pcre2_match_context_create(pcre2_general_context *gcontext)
 {
 pcre2_match_context *mcontext = PRIV(memctl_malloc)(
-  sizeof(pcre2_real_match_context),
-  offsetof(pcre2_real_compile_context, memctl),
-  &(gcontext->memctl));  
+  sizeof(pcre2_real_match_context), (pcre2_memctl *)gcontext);  
 if (mcontext == NULL) return NULL;   
 PRIV(match_context_init)(mcontext, FALSE);
 return mcontext;
diff --git a/src/pcre2_internal.h b/src/pcre2_internal.h
index fd1ee41..2f07c03 100644
--- a/src/pcre2_internal.h
+++ b/src/pcre2_internal.h
@@ -1863,7 +1863,7 @@
                BOOL);
 extern int   _pcre2_jit_get_size(void *);
 extern void  _pcre2_match_context_init(pcre2_match_context *, BOOL);
-extern void  *_pcre2_memctl_malloc(size_t, size_t, pcre2_memctl *);
+extern void  *_pcre2_memctl_malloc(size_t, pcre2_memctl *);
 extern unsigned int _pcre2_ord2utf(uint32_t, PCRE2_UCHAR *);
 extern int   _pcre2_strcmp(PCRE2_SPTR, PCRE2_SPTR);
 extern int   _pcre2_strcmp_c8(PCRE2_SPTR, const char *);
diff --git a/src/pcre2_intmodedep.h b/src/pcre2_intmodedep.h
index 94c7bae..52cecc6 100644
--- a/src/pcre2_intmodedep.h
+++ b/src/pcre2_intmodedep.h
@@ -540,6 +540,9 @@
 
 /* ----------------------- HIDDEN STRUCTURES ----------------------------- */
 
+/* NOTE: All these structures *must* start with a pcre2_memctl structure. The 
+code that uses them is simpler because it assumes this. */
+
 /* The real general context structure. At present it hold only data for custom 
 memory control. */
 
diff --git a/src/pcre2_match_data.c b/src/pcre2_match_data.c
index d162282..f297f64 100644
--- a/src/pcre2_match_data.c
+++ b/src/pcre2_match_data.c
@@ -56,7 +56,7 @@
 {
 pcre2_match_data *yield = PRIV(memctl_malloc)(
   sizeof(pcre2_match_data) + 3*oveccount*sizeof(PCRE2_OFFSET),
-  offsetof(pcre2_real_match_data, memctl), &(gcontext->memctl));
+  (pcre2_memctl *)gcontext);
 yield->oveccount = oveccount;
 return yield;
 }
diff --git a/src/pcre2_substring.c b/src/pcre2_substring.c
index 307ab4f..a69c902 100644
--- a/src/pcre2_substring.c
+++ b/src/pcre2_substring.c
@@ -210,7 +210,7 @@
 right = match_data->ovector[stringnumber*2+1];
 
 block = PRIV(memctl_malloc)(sizeof(pcre2_memctl) + 
-  (right-left+1)*PCRE2_CODE_UNIT_WIDTH, 0, &(match_data->memctl)); 
+  (right-left+1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)match_data); 
 if (block == NULL) return PCRE2_ERROR_NOMEMORY;
 
 yield = (PCRE2_UCHAR *)((char *)block + sizeof(pcre2_memctl));
@@ -346,7 +346,7 @@
 
 for (i = 0; i < count2; i += 2)
    size += sizeof(PCRE2_UCHAR *) + CU2BYTES(ovector[i+1] - ovector[i] + 1);
-memp = PRIV(memctl_malloc)(size, 0, &(match_data->memctl)); 
+memp = PRIV(memctl_malloc)(size, (pcre2_memctl *)match_data); 
 if (memp == NULL) return PCRE2_ERROR_NOMEMORY;
 
 *listptr = listp = (PCRE2_UCHAR **)((char *)memp + sizeof(pcre2_memctl));