@@ -133,6 +133,17 @@ def is_string_pointer(c_type: str) -> bool:
133133 return t in ("char *" , "char**" , "char *const *" , "const char *" )
134134
135135
136+ def is_borrowed_string (c_type : str ) -> bool :
137+ """A ``const char *`` return the caller does not own.
138+
139+ The Utf8 string marshaller frees what it is handed back, which is right for
140+ the ``char *`` MEOS mallocs for the caller and fatal for the ``const char *``
141+ it returns out of a static table — ``interptype_name`` hands back an element
142+ of ``MEOS_INTERPTYPE_NAMES``. A borrowed return comes back as the pointer
143+ itself and is read without a free."""
144+ return " " .join (c_type .split ()).startswith ("const char *" )
145+
146+
136147def csharp_type_for (canonical : str ) -> str :
137148 """Translate a libclang-canonical C type to a C# type for LibraryImport signatures."""
138149 t = canonical .strip ()
@@ -155,6 +166,8 @@ def csharp_param_type(c_type: str, canonical: str) -> str:
155166
156167
157168def csharp_return_type (c_type : str , canonical : str ) -> str :
169+ if is_borrowed_string (c_type ):
170+ return "IntPtr"
158171 if is_string_pointer (c_type ):
159172 return "string"
160173 return csharp_type_for (canonical )
@@ -472,6 +485,12 @@ def _copy(indent: str) -> list[str]:
472485def _emit_simple_passthrough (f : dict , ext_params : str , ext_args : str , default_rt : str | None = None ) -> list [str ]:
473486 name = f ["name" ]
474487 rt = default_rt or csharp_return_type (f ["returnType" ]["c" ], f ["returnType" ]["canonical" ])
488+ if default_rt is None and is_borrowed_string (f ["returnType" ]["c" ]):
489+ return [
490+ f" public static string? { name } ({ ext_params } )" ,
491+ f" => Marshal.PtrToStringUTF8("
492+ f"SafeExecution<IntPtr>(() => MEOSExternalFunctions.{ name } ({ ext_args } )));" ,
493+ ]
475494 if rt == "void" :
476495 return [
477496 f" public static void { name } ({ ext_params } )" ,
0 commit comments