diff --git a/api/GenApi.py b/api/GenApi.py
index 44eccd308eaad0917e03549c3527762988b305f3..f292e8184f2c27a84cb1e16c49d965f730c9e7da 100644
--- a/api/GenApi.py
+++ b/api/GenApi.py
@@ -487,6 +487,7 @@ def ostring(name, value=None, python_value=None, julia_value=None):
     a.fortran_types = ["character(len=:), allocatable, intent(out)"]
     a.fortran_c_api = ["character(kind=c_char), dimension(*)"]
     a.fortran_c_args = [api_name]
+    # TODO: Does this need to be C deallocated?
     return a
 
 
@@ -1490,6 +1491,8 @@ module gmsh
   integer, parameter, public :: {2}_API_MAX_STR_LEN = 512
   character(len=100), parameter, public :: {2}_API_VERSION = "{4}.{5}.{6}"
 
+  public :: gmshFree
+
   type cstr_t
     character(len=:), allocatable :: s
   end type cstr_t
@@ -1501,6 +1504,22 @@ module gmsh
 """
 
 fortran_footer = """
+  ! ----------------------------------------------------------------------------
+  ! GMSH C memory management tools
+  ! ----------------------------------------------------------------------------
+
+  !> Callback to C to free any reserved memory
+  subroutine gmshFree(p)
+    interface
+      subroutine C_API(ptr) bind(C, name="gmshFree")
+        use, intrinsic :: iso_c_binding
+        type(c_ptr), value :: ptr
+      end subroutine C_API
+    end interface
+    type(c_ptr) :: p
+    call C_API(p)
+  end subroutine gmshFree
+
   ! ----------------------------------------------------------------------------
   ! Input routines from Fortran to C
   ! ----------------------------------------------------------------------------
@@ -1598,37 +1617,37 @@ fortran_footer = """
   ! ----------------------------------------------------------------------------
 
   function ovectorint_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable :: v(:)
     integer(c_int), pointer :: v_(:)
     call c_f_pointer(cptr, v_, [n])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectorint_
 
   function ovectorsize_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     integer(c_size_t), allocatable :: v(:)
     integer(c_size_t), pointer :: v_(:)
     call c_f_pointer(cptr, v_, [n])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectorsize_
 
   function ovectordouble_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     real(c_double), allocatable :: v(:)
     real(c_double), pointer :: v_(:)
     call c_f_pointer(cptr, v_, [n])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectordouble_
 
   function ovectorstring_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     character(len=GMSH_API_MAX_STR_LEN), allocatable :: v(:)
 
@@ -1644,20 +1663,21 @@ fortran_footer = """
         lenstr = cstrlen(fptr)
         v(i) = transfer(fptr(1:lenstr), v(i))
     end do
+    call gmshFree(cptr)
   end function ovectorstring_
 
   function ovectorpair_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable :: v(:,:)
     integer(c_int), pointer :: v_(:,:)
     call c_f_pointer(cptr, v_, [2_c_size_t, n / 2_c_size_t])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectorpair_
 
   subroutine ovectorvectorint_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable, intent(out) :: v(:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -1667,11 +1687,12 @@ fortran_footer = """
     call c_f_pointer(cptr1, v_, [sum(dims)])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectorint_
 
   subroutine ovectorvectorsize_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     integer(c_size_t), allocatable, intent(out) :: v(:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -1681,11 +1702,12 @@ fortran_footer = """
     call c_f_pointer(cptr1, v_, [sum(dims)])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectorsize_
 
   subroutine ovectorvectordouble_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     real(c_double), allocatable, intent(out) :: v(:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -1695,11 +1717,12 @@ fortran_footer = """
     call c_f_pointer(cptr1, v_, [sum(dims)])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectordouble_
 
   subroutine ovectorvectorpair_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable, intent(out) :: v(:,:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -1709,7 +1732,8 @@ fortran_footer = """
     call c_f_pointer(cptr1, v_, [sum(dims), 2_c_size_t])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectorpair_
 
   !> Calculates the length of a C string.
@@ -2211,6 +2235,8 @@ class API:
                 arg_list = ""
                 for arg in args:
                     for t, a in zip(arg.fortran_types, arg.fortran_args):
+                        # if arg.value:
+                        #     t += ", optional" # TODO: add optional to ierr
                         arg_list += f"{indent}{t} :: {a}\n"
                 arg_list += f"{indent}integer(c_int), intent(out) :: ierr\n"
                 return arg_list
diff --git a/api/gmsh.f90 b/api/gmsh.f90
index 59124d421e6b61349acca7d6ce321307c6f2149d..1f6b1f49d9cd1c8f1f30ecf54332171176498aae 100644
--- a/api/gmsh.f90
+++ b/api/gmsh.f90
@@ -33,6 +33,8 @@ module gmsh
   integer, parameter, public :: GMSH_API_MAX_STR_LEN = 512
   character(len=100), parameter, public :: GMSH_API_VERSION = "4.10.4"
 
+  public :: gmshFree
+
   type cstr_t
     character(len=:), allocatable :: s
   end type cstr_t
@@ -10202,6 +10204,22 @@ module gmsh
     ! Post processing
   end subroutine gmshLoggerGetLastError
 
+  ! ----------------------------------------------------------------------------
+  ! GMSH C memory management tools
+  ! ----------------------------------------------------------------------------
+
+  !> Callback to C to free any reserved memory
+  subroutine gmshFree(p)
+    interface
+      subroutine C_API(ptr) bind(C, name="gmshFree")
+        use, intrinsic :: iso_c_binding
+        type(c_ptr), value :: ptr
+      end subroutine C_API
+    end interface
+    type(c_ptr) :: p
+    call C_API(p)
+  end subroutine gmshFree
+
   ! ----------------------------------------------------------------------------
   ! Input routines from Fortran to C
   ! ----------------------------------------------------------------------------
@@ -10299,37 +10317,37 @@ module gmsh
   ! ----------------------------------------------------------------------------
 
   function ovectorint_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable :: v(:)
     integer(c_int), pointer :: v_(:)
     call c_f_pointer(cptr, v_, [n])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectorint_
 
   function ovectorsize_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     integer(c_size_t), allocatable :: v(:)
     integer(c_size_t), pointer :: v_(:)
     call c_f_pointer(cptr, v_, [n])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectorsize_
 
   function ovectordouble_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     real(c_double), allocatable :: v(:)
     real(c_double), pointer :: v_(:)
     call c_f_pointer(cptr, v_, [n])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectordouble_
 
   function ovectorstring_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     character(len=GMSH_API_MAX_STR_LEN), allocatable :: v(:)
 
@@ -10345,20 +10363,21 @@ module gmsh
         lenstr = cstrlen(fptr)
         v(i) = transfer(fptr(1:lenstr), v(i))
     end do
+    call gmshFree(cptr)
   end function ovectorstring_
 
   function ovectorpair_(cptr, n) result(v)
-    type(c_ptr), intent(in) :: cptr
+    type(c_ptr), intent(inout) :: cptr
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable :: v(:,:)
     integer(c_int), pointer :: v_(:,:)
     call c_f_pointer(cptr, v_, [2_c_size_t, n / 2_c_size_t])
     allocate(v, source=v_)
-    deallocate(v_)
+    call gmshFree(cptr)
   end function ovectorpair_
 
   subroutine ovectorvectorint_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable, intent(out) :: v(:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -10368,11 +10387,12 @@ module gmsh
     call c_f_pointer(cptr1, v_, [sum(dims)])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectorint_
 
   subroutine ovectorvectorsize_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     integer(c_size_t), allocatable, intent(out) :: v(:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -10382,11 +10402,12 @@ module gmsh
     call c_f_pointer(cptr1, v_, [sum(dims)])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectorsize_
 
   subroutine ovectorvectordouble_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     real(c_double), allocatable, intent(out) :: v(:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -10396,11 +10417,12 @@ module gmsh
     call c_f_pointer(cptr1, v_, [sum(dims)])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectordouble_
 
   subroutine ovectorvectorpair_(cptr1, cptr2, n, v, dims)
-    type(c_ptr), intent(in) :: cptr1, cptr2
+    type(c_ptr), intent(inout) :: cptr1, cptr2
     integer(c_size_t), intent(in) :: n
     integer(c_int), allocatable, intent(out) :: v(:,:)
     integer(c_size_t), allocatable, intent(out) :: dims(:)
@@ -10410,7 +10432,8 @@ module gmsh
     call c_f_pointer(cptr1, v_, [sum(dims), 2_c_size_t])
     allocate(dims, source=dims_)
     allocate(v, source=v_)
-    deallocate(v_, dims_)
+    call gmshFree(cptr1)
+    call gmshFree(cptr2)
   end subroutine ovectorvectorpair_
 
   !> Calculates the length of a C string.