Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SGen/Tarjan] Handle edge case with node heaviness changing due to deduplication #113044

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

filipnavara
Copy link
Member

@filipnavara filipnavara commented Mar 2, 2025

This code path can introduce duplicates into the color->other_colors array:

// Maybe we should make sure we are not adding duplicates here. It is not really a problem
// since we will get rid of duplicates before submitting the SCCs to the client in gather_xrefs
if (color_data)
add_other_colors (color_data, &other->xrefs);

Then we get to the code that counts xref_count:

// Eliminate non-visible SCCs from the SCC list and redistribute xrefs
for (cur = root_color_bucket; cur; cur = cur->next) {
ColorData *cd;
for (cd = &cur->data [0]; cd < cur->next_data; ++cd) {
if (!color_visible_to_client (cd))
continue;
color_merge_array_empty ();
gather_xrefs (cd);
reset_xrefs (cd);
dyn_array_ptr_set_all (&cd->other_colors, &color_merge_array);
xref_count += dyn_array_ptr_size (&cd->other_colors);
}
}

It uses the color_visible_to_client helper method which in turn calls bridgeless_color_is_heavy:

static gboolean
bridgeless_color_is_heavy (ColorData *data) {
if (disable_non_bridge_scc)
return FALSE;
int fanin = data->incoming_colors;
int fanout = dyn_array_ptr_size (&data->other_colors);
return fanin > HEAVY_REFS_MIN && fanout > HEAVY_REFS_MIN
&& fanin*fanout >= HEAVY_COMBINED_REFS_MIN;
}

The fanout metric is computed from the count of other_colors which contain duplicates. Once the references are gathered with gather_xrefs they get deduplicated. This can change the number of fanout nodes just enough that it no longer satisfies the "heavy" property. We still increase the xref_count but in the second loop that iterates over the same data it will get skipped and result in a mismatch:

for (cur = root_color_bucket; cur; cur = cur->next) {
ColorData *src;
for (src = &cur->data [0]; src < cur->next_data; ++src) {
if (!color_visible_to_client (src))
continue;

Repro: https://github.com/user-attachments/files/19044193/Archive.zip

Fixes #106410

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 2, 2025
@filipnavara
Copy link
Member Author

FYI @AaronRobinsonMSFT

@filipnavara
Copy link
Member Author

filipnavara commented Mar 2, 2025

The fix is incomplete, we would likely report incorrect SCCs now instead of hitting the assert, and previous XREFs would likely be wrong too.

I'm keeping this as draft until I come up with a fix.

@filipnavara filipnavara closed this Mar 2, 2025
@filipnavara
Copy link
Member Author

The fix needs to be done differently. We basically have three options:

  1. Get rid of the duplicates early. This may be not be too costly if done right.
  2. Lock it the heaviness at certain point and report the nodes anyway even if they are not really heavy in the end.
  3. Do the deduplication late, possibly at the beginning of processing_build_callback_data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-GC-mono community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Android] App crashing with condition `xref_count == xref_index' not met
1 participant