@@ -146,13 +146,25 @@ UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRecord)
146146 }
147147 }
148148
149- /* Use internal API to avoid redundant GObject ref/unref/type-check overhead */
149+ /*
150+ * Use internal API to avoid the LIBMSI_IS_QUERY / LIBMSI_IS_RECORD
151+ * type-check macros in the public wrapper, but keep the same
152+ * g_object_ref/unref bracketing that the public API provides.
153+ * The protective ref ensures the query (and record) remain alive
154+ * even if a view operation callback indirectly drops a reference.
155+ */
150156 libmsi_global_lock ();
151157
158+ g_object_ref (query );
159+ if (rec ) g_object_ref (rec );
160+
152161 unsigned r = _libmsi_query_execute (query , rec );
153162
154- g_object_unref (query );
155- if (rec ) g_object_unref (rec );
163+ g_object_unref (query ); /* drop protective ref */
164+ if (rec ) g_object_unref (rec ); /* drop protective ref */
165+
166+ g_object_unref (query ); /* drop handle_table_get_typed ref */
167+ if (rec ) g_object_unref (rec ); /* drop handle_table_get_typed ref */
156168
157169 libmsi_global_unlock ();
158170
@@ -178,16 +190,20 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *phRecord)
178190 /*
179191 * Call the internal _libmsi_query_fetch directly instead of the public
180192 * libmsi_query_fetch wrapper. The public API does g_return_val_if_fail
181- * (LIBMSI_IS_QUERY) which dereferences GObject class pointers and an
182- * extra g_object_ref/unref cycle -- both unnecessary since we already
183- * hold a valid ref from handle_table_get_typed. Bypassing the public
184- * wrapper avoids potential issues with the GObject type-check machinery .
193+ * (LIBMSI_IS_QUERY) which dereferences GObject class pointers -- bypassing
194+ * the public wrapper avoids potential issues with the GObject type-check
195+ * machinery. We add a protective g_object_ref/unref to match the public
196+ * API's bracketing, keeping the query alive during the fetch operation .
185197 */
186198 libmsi_global_lock ();
187199
200+ g_object_ref (query ); /* protective ref (matches public API) */
201+
188202 LibmsiRecord * rec = NULL ;
189203 unsigned ret = _libmsi_query_fetch (query , & rec );
190- g_object_unref (query );
204+
205+ g_object_unref (query ); /* drop protective ref */
206+ g_object_unref (query ); /* drop handle_table_get_typed ref */
191207
192208 if (ret == NO_MORE_ITEMS ) {
193209 libmsi_global_unlock ();
@@ -339,12 +355,20 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO eColumnInfo, MSIHAN
339355 if (!query )
340356 return ERROR_INVALID_HANDLE ;
341357
342- /* Use internal API to avoid redundant GObject ref/unref/type-check overhead */
358+ /*
359+ * Use internal API to avoid the LIBMSI_IS_QUERY type-check macro in the
360+ * public wrapper. Add a protective ref to match the public API's
361+ * g_object_ref/unref bracketing.
362+ */
343363 libmsi_global_lock ();
344364
365+ g_object_ref (query ); /* protective ref (matches public API) */
366+
345367 LibmsiRecord * rec = NULL ;
346368 unsigned r = _libmsi_query_get_column_info (query , (LibmsiColInfo )eColumnInfo , & rec );
347- g_object_unref (query );
369+
370+ g_object_unref (query ); /* drop protective ref */
371+ g_object_unref (query ); /* drop handle_table_get_typed ref */
348372
349373 if (r != LIBMSI_RESULT_SUCCESS || !rec ) {
350374 libmsi_global_unlock ();
@@ -373,18 +397,25 @@ UINT WINAPI MsiViewClose(MSIHANDLE hView)
373397 if (!query )
374398 return ERROR_INVALID_HANDLE ;
375399
376- /* Call the view's close operation directly instead of libmsi_query_close,
400+ /*
401+ * Call the view's close operation directly instead of libmsi_query_close,
377402 * which has a ref-count leak bug on early-return error paths (it does
378403 * g_object_ref but returns without g_object_unref when view is NULL or
379- * view->ops->close is NULL). */
404+ * view->ops->close is NULL). We add a protective ref/unref to match the
405+ * public API's bracketing on the success path, keeping the query alive
406+ * during the close operation.
407+ */
380408 libmsi_global_lock ();
381409
410+ g_object_ref (query ); /* protective ref (matches public API) */
411+
382412 LibmsiView * view = query -> view ;
383413 unsigned r = LIBMSI_RESULT_SUCCESS ;
384414 if (view && view -> ops && view -> ops -> close )
385415 r = view -> ops -> close (view );
386416
387- g_object_unref (query );
417+ g_object_unref (query ); /* drop protective ref */
418+ g_object_unref (query ); /* drop handle_table_get_typed ref */
388419
389420 libmsi_global_unlock ();
390421
0 commit comments