Skip to content

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

Open
Rudhik1904 wants to merge 6 commits into
develfrom
test/linux-assertion-repro
Open

test: reproduce Linux libstdc++ assertion crash in isolation_tree#142
Rudhik1904 wants to merge 6 commits into
develfrom
test/linux-assertion-repro

Conversation

@Rudhik1904

@Rudhik1904 Rudhik1904 commented Aug 5, 2026

Copy link
Copy Markdown

Motivation and context

This testing-only PR reproduces a Linux libstdc++ assertion crash in isolation_tree. It forwards worker stderr and enables runtime assertions during the dry-run build. It also prevents NA and NaN values from corrupting isolation-tree split bounds. The PR must not be merged.

Changes

  • Added a temporary workflow step in .github/workflows/dry-run-build.yml.
  • Configured ~/.R/Makevars to undefine NDEBUG and enable libstdc++ runtime assertions.
  • Forwarded parallel worker stdout and stderr from .runAnomalyModel.
  • Updated the duplicate-metrics assertion message.
  • Initialized isolation-tree numeric bounds from valid non-missing values.
  • Added handling for features that contain only missing values.
  • Preserved missing-value split behavior for mixed missing and valid data.
  • Kept constant valid features without missing values as leaf nodes.
  • Added no exported or public entities.

Tests

  • Added regression coverage in inst/tinytest/test_utils_anomaly_score.R.
  • Covered leading NA and NaN quality metrics.
  • Verified that anomaly model execution completes without an error.
  • Verified that generated anomaly scores are finite.

Coding guideline violations

  • The PR is intentionally temporary and must not be merged.
  • No other guideline violations are identified from the available changes.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request fixes missing-value handling in isolation forest tree construction. It adds regression coverage for leading missing quality metrics, forwards worker diagnostics, and enables libstdc++ assertions in the Linux dry-run build.

Changes

Anomaly score handling

Layer / File(s) Summary
Isolation forest missing-value handling
src/isolation_forest.cpp
isolation_tree initializes bounds from valid values and handles all-missing and mixed features with missing-value splits. Constant complete features remain leaf nodes.
Anomaly model regression validation
inst/tinytest/test_utils_anomaly_score.R
The test covers leading NA/NaN quality metrics and verifies finite anomaly scores. The duplicate-metrics assertion message is reformatted.
Diagnostic build output
R/utils_anomaly_score.R, .github/workflows/dry-run-build.yml
Parallel worker output is forwarded to the master process. The workflow enables libstdc++ assertions before build and check steps.

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

Possibly related PRs

  • Vitek-Lab/MSstatsConvert#119: Both PRs modify anomaly-model missing-value handling in R/utils_anomaly_score.R and src/isolation_forest.cpp.

Suggested reviewers: tonywu1999

Poem

A rabbit finds a missing leaf,
And bounds stay clear of hidden grief.
Scores remain finite and bright,
Workers share their logs in flight.
CI checks the forest right.

🚥 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 a description that covers the motivation, detailed changes, regression tests, and completed checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly identifies the Linux libstdc++ assertion crash reproduction in isolation_tree, which is the primary purpose of the changes.
✨ 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
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.

1 participant