Skip to content

Fix memory leaks from mono_type_full_name in marshal-shared.c error paths#125616

Open
Copilot wants to merge 4 commits intomainfrom
copilot/fix-memory-leak-mono-type
Open

Fix memory leaks from mono_type_full_name in marshal-shared.c error paths#125616
Copilot wants to merge 4 commits intomainfrom
copilot/fix-memory-leak-mono-type

Conversation

Copy link
Contributor

Copilot AI commented Mar 16, 2026

mono_type_full_name() returns a heap-allocated string, but several call sites in marshal-shared.c passed the result directly into g_strdup_printf without freeing it — leaking on every hit. These paths can fire repeatedly during AOT compilation against assemblies with many invalid marshal configurations.

Description

Store each mono_type_full_name() result in a local, use it, then g_free it:

// Before
char *msg = g_strdup_printf("Type %s ...", mono_type_full_name(m_class_get_byval_arg(klass)));

// After
char *type_name = mono_type_full_name(m_class_get_byval_arg(klass));
char *msg = g_strdup_printf("Type %s ...", type_name);
g_free(type_name);

Fixed sites:

  • Auto-layout checkg_strdup_printf with single mono_type_full_name; result stored, used, and freed
  • Explicit-layout g_error path — left as-is (inline mono_type_full_name call); g_error is fatal and never returns, and in DISABLE_ASSERT_MESSAGES builds its variadic args are discarded entirely — introducing a local variable causes an unused-variable build error in WASM/WASI configurations
  • Generic type marshal checkg_strdup_printf with single mono_type_full_name; result stored, used, and freed
  • Struct field type checkg_strdup_printf with two mono_type_full_name calls; both results stored, used, and freed

Customer Impact

Cumulative memory growth during AOT compilation of assemblies containing types with invalid marshal configurations (auto-layout structs, non-blittable generic fields, reference-typed struct fields).

Regression

No — pre-existing leak, not a regression.

Testing

Validated by code inspection and CI. These are error paths with no dedicated test infrastructure in the repo; the fix is mechanical and low-risk.

Risk

Very low. Changes are confined to error paths that emit a marshal exception. No logic changes — only introduction of local variables and paired g_free calls before strings go out of scope. The g_error path is intentionally left unchanged to avoid a -Werror,-Wunused-variable build failure in WASM/WASI configurations where g_error discards its variadic arguments.

Package authoring no longer needed in .NET 9

IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.

Original prompt

This section details on the original issue you should resolve

<issue_title>Memory leaks from mono_type_full_name in marshal-shared.c error paths</issue_title>
<issue_description>## Description

mono_type_full_name() returns an allocated string, but several call sites in src/mono/mono/metadata/marshal-shared.c pass it directly into g_strdup_printf or g_error without freeing the intermediate allocation:

  • Line 778: g_strdup_printf("Type %s ...", mono_type_full_name(...))
  • Line 816: g_error("Type %s ...", mono_type_full_name(...))
  • Line 866: g_strdup_printf("Generic type %s ...", mono_type_full_name(...))
  • Lines 912-913: g_strdup_printf("Type %s with field type %s ...", mono_type_full_name(...), mono_type_full_name(...))

Each leaks the string returned by mono_type_full_name(). While these are error paths, they can fire repeatedly during AOT compilation (e.g., when processing assemblies with many invalid marshal configurations), causing cumulative memory growth.

Fix

Store the result in a temporary, use it in the format string, then g_free it:

char *type_name = mono_type_full_name(m_class_get_byval_arg(klass));
char *msg = g_strdup_printf("Type %s ...", type_name);
g_free(type_name);
mono_marshal_shared_mb_emit_exception_marshal_directive(mb, msg);

This pattern should be applied to all call sites in the file.</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI and others added 2 commits March 16, 2026 14:28
…aths

Co-authored-by: lewing <24063+lewing@users.noreply.github.com>
…red.c

Co-authored-by: lewing <24063+lewing@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix memory leaks from mono_type_full_name in marshal-shared.c Fix memory leaks from mono_type_full_name in marshal-shared.c error paths Mar 16, 2026
Copilot AI requested a review from lewing March 16, 2026 14:38
@lewing
Copy link
Member

lewing commented Mar 16, 2026

@copilot take a look at the failures

…inline form

Co-authored-by: lewing <24063+lewing@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 16, 2026

@copilot take a look at the failures

The build was failing with unused variable 'type_name' [-Werror,-Wunused-variable] in WASM/WASI builds (commit 3ef96fb).

Root cause: when DISABLE_ASSERT_MESSAGES is defined (used in WASM/WASI builds), g_error(...) expands to g_log_disabled(domain, level, file, line); eg_unreachable() — the variadic arguments are discarded entirely, so the local type_name variable was never actually used.

Fixed in commit 56129333: reverted the g_error call site back to the original inline mono_type_full_name() form. Since g_error is fatal and aborts the process, the transient memory leak is irrelevant. The other three g_strdup_printf sites (the real leaks) remain fixed.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh gh pr list --head copilot/fix-memory-leak-mono-type --json number,title,url (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh pr checks 125616 --repo dotnet/runtime (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@lewing lewing marked this pull request as ready for review March 16, 2026 19:38
Copilot AI review requested due to automatic review settings March 16, 2026 19:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes repeated heap leaks in Mono marshaling error paths by ensuring mono_type_full_name() results are freed after being used to format exception messages during IL generation (notably during AOT compilation when many invalid marshal configurations are encountered).

Changes:

  • Store mono_type_full_name(...) results into locals before g_strdup_printf(...) and g_free(...) them afterward.
  • Apply the pattern to the auto-layout struct check, non-blittable generic field check, and struct field type check (two type-name allocations).

You can also share your feedback on Copilot code review. Take the survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leaks from mono_type_full_name in marshal-shared.c error paths

3 participants