Skip to content

test: reproduce Linux libstdc++ assertion crash in isolation_tree - #142

Merged
tonywu1999 merged 8 commits into
develfrom
test/linux-assertion-repro
Aug 17, 2026
Merged

test: reproduce Linux libstdc++ assertion crash in isolation_tree#142
tonywu1999 merged 8 commits into
develfrom
test/linux-assertion-repro

Conversation

@Rudhik1904

@Rudhik1904 Rudhik1904 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Motivation and context

A Linux libstdc++ assertion can occur in isolation_tree when anomaly-model input contains leading NA or NaN quality metrics. Missing values can corrupt feature bounds during split selection.

This change initializes numeric bounds from valid values and handles missing-only features explicitly. It also adds a regression test to confirm that anomaly modeling completes and produces finite scores.

Changes

  • Updated the duplicate-metrics assertion message.
  • Added separate tracking for valid numeric values and missing values in isolation_tree.
  • Initialized feature bounds from the first non-missing value.
  • Added missing-value splits for features that contain only missing values.
  • Preserved leaf behavior for constant non-missing features without missing values.
  • Preserved probabilistic missing-value split behavior for mixed missing and valid data.
  • Forced a missing-value split when valid values are constant and missing values are present.

Unit tests

  • Added a regression test for leading NA and NaN quality metrics.
  • Verified that anomaly-model execution does not raise an error.
  • Verified that generated anomaly scores are finite.

Coding guidelines

  • No coding-guideline violations were identified from the reviewed changes.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@tonywu1999, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 069a97c1-00ad-438c-9b86-d43d9645dee5

📥 Commits

Reviewing files that changed from the base of the PR and between 0d878f7 and d385da1.

📒 Files selected for processing (2)
  • inst/tinytest/test_utils_anomaly_score.R
  • src/isolation_forest.cpp

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8918c34d-aecd-4e7d-af79-59dabd14a30c

📥 Commits

Reviewing files that changed from the base of the PR and between 964b3c1 and 0d878f7.

📒 Files selected for processing (1)
  • src/isolation_forest.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/isolation_forest.cpp

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The isolation forest now separates valid and missing feature values when initializing bounds and selecting splits. Regression coverage verifies that leading missing quality metrics do not prevent anomaly model execution or produce non-finite scores.

Changes

Anomaly score handling

Layer / File(s) Summary
Isolation forest missing-value handling
src/isolation_forest.cpp
isolation_tree initializes numeric bounds from the first valid value. All-missing features use missing-value splits, mixed data retains missing-split behavior, and constant complete features remain leaves.
Anomaly model regression validation
inst/tinytest/test_utils_anomaly_score.R
The test covers a leading NA/NaN quality metric, verifies successful model execution, and checks finite anomaly scores. The duplicate-metrics assertion message is reformatted.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 0d878

This change is merge-ready after normal checks and review; no actionable merge-blocking risk remains.

Suggested reviewers: devonjkohler, tonywu1999

Poem

A bunny finds a missing grain,
The forest bounds stay clear of pain.
Splits sort the values, scores shine bright,
NA hops through without a fright.
Finite results greet the night.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided, so the required motivation, changes, testing, and checklist sections are missing. Add the required sections and describe the motivation, implementation changes, regression tests, warnings, and dependency status.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies the Linux libstdc++ assertion crash and the affected isolation_tree code, which matches the regression test and fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/linux-assertion-repro

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/isolation_forest.cpp (1)

112-117: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Honor is_missing_split during path scoring.

isolation_tree routes NaN values to the left child when is_missing_split is set, but path_length ignores this and uses only it->second < node->value. Since NaN comparisons are false, scoring traverses the right child instead. Update path_length to route NaN values left and non-missing values right before applying the numeric comparison.

Proposed fix
-    if (it->second < node->value) {
+    if (node->is_missing_split) {
+        if (std::isnan(it->second)) {
+            return path_length(node->left.get(), obs, depth + 1);
+        }
+        return path_length(node->right.get(), obs, depth + 1);
+    }
+    if (it->second < node->value) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/isolation_forest.cpp` around lines 112 - 117, Update path_length to honor
is_missing_split when routing split values: detect NaN inputs and traverse the
left child, while non-missing inputs traverse the right child before applying
the existing numeric comparison. Keep the current comparison-based routing for
ordinary numeric splits.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@R/utils_anomaly_score.R`:
- Line 214: In .runAnomalyModel, register cleanup immediately after
parallel::makeCluster(cores, outfile = "") by adding an on.exit handler that
calls parallel::stopCluster(cl) with add = TRUE, ensuring the cluster is stopped
on normal returns and errors.

In `@src/isolation_forest.cpp`:
- Around line 108-112: Update the feature-selection and partition logic around
has_valid and is_missing_split so a selected feature with !has_valid is never
used for a non-partitioning split. Select another feature that can produce two
non-empty children, or terminate by returning a leaf when none exists; ensure
recursion never proceeds with an unchanged dataset and an empty right_data.

---

Outside diff comments:
In `@src/isolation_forest.cpp`:
- Around line 112-117: Update path_length to honor is_missing_split when routing
split values: detect NaN inputs and traverse the left child, while non-missing
inputs traverse the right child before applying the existing numeric comparison.
Keep the current comparison-based routing for ordinary numeric splits.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e2f8937-fb6b-43d5-9696-25883d250667

📥 Commits

Reviewing files that changed from the base of the PR and between ad2a00b and 964b3c1.

📒 Files selected for processing (3)
  • .github/workflows/dry-run-build.yml
  • R/utils_anomaly_score.R
  • src/isolation_forest.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/dry-run-build.yml

Comment thread R/utils_anomaly_score.R Outdated
# native C++ assertion/abort messages) to the master process instead of
# discarding it, to confirm the exact crash text on Linux CI. Revert
# once confirmed.
cl = parallel::makeCluster(cores, outfile = "")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files matching utils_anomaly_score.R:\n'
fd -a 'utils_anomaly_score\.R$' . || true

if [ -f R/utils_anomaly_score.R ]; then
  printf '\nRelevant source section:\n'
  sed -n '180,255p' R/utils_anomaly_score.R | nl -ba -v180
fi

printf '\nSearch for stopCluster and .runAnomalyModel:\n'
rg -n "stopCluster|makeCluster|\.runAnomalyModel|parLapply|clusterExport" -S .

Repository: Vitek-Lab/MSstatsConvert

Length of output: 369


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Relevant source section R/utils_anomaly_score.R:\n'
awk 'NR>=180 && NR<=255 { printf "%5d\t%s\n", NR, $0 }' R/utils_anomaly_score.R

printf '\nSearch for stopCluster and parallel/cluster calls:\n'
rg -n "stopCluster|makeCluster|\.runAnomalyModel|parLapply\(|clusterExport\(" -S .

printf '\nOn.exit occurrences in target file:\n'
rg -n "on\.exit|tryCatch|try\(" R/utils_anomaly_score.R || true

Repository: Vitek-Lab/MSstatsConvert

Length of output: 3744


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Continue relevant source section R/utils_anomaly_score.R:\n'
awk 'NR>=255 && NR<=320 { printf "%5d\t%s\n", NR, $0 }' R/utils_anomaly_score.R

printf '\nCheck whether .runAnomalyModel has any later return path or cleanup:\n'
python3 - <<'PY'
from pathlib import Path
p = Path('R/utils_anomaly_score.R')
text = p.read_text().splitlines()
for i, line in enumerate(text, start=1):
    if 'clusterExport' in line or 'parLapply' in line or 'makeCluster' in line or 'stopCluster' in line or line.strip().startswith('on.exit'):
        print(f"{i}: {line.strip()}")
PY

Repository: Vitek-Lab/MSstatsConvert

Length of output: 578


Stop the parallel cluster before returning.

.runAnomalyModel creates the cluster but never calls parallel::stopCluster(cl); add on.exit(parallel::stopCluster(cl), add = TRUE) after makeCluster(). This stops workers on both normal return and error paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@R/utils_anomaly_score.R` at line 214, In .runAnomalyModel, register cleanup
immediately after parallel::makeCluster(cores, outfile = "") by adding an
on.exit handler that calls parallel::stopCluster(cl) with add = TRUE, ensuring
the cluster is stopped on normal returns and errors.

Comment thread src/isolation_forest.cpp Outdated
@tonywu1999
tonywu1999 force-pushed the test/linux-assertion-repro branch from 0d878f7 to 1db738a Compare August 17, 2026 20:55
@tonywu1999
tonywu1999 merged commit 8fd3bc2 into devel Aug 17, 2026
2 checks passed
@tonywu1999
tonywu1999 deleted the test/linux-assertion-repro branch August 17, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants