Skip to content

Fix symbol export - #8037

Merged
rapids-bot[bot] merged 4 commits into
NVIDIA:mainfrom
vyasr:fix/symbol_export
May 23, 2026
Merged

Fix symbol export#8037
rapids-bot[bot] merged 4 commits into
NVIDIA:mainfrom
vyasr:fix/symbol_export

Conversation

@vyasr

@vyasr vyasr commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

This PR adds symbol visibility controls to cuml to avoid exporting weak symbols that it shouldn't.

Contributes to https://github.com/rapidsai/build-infra/issues/53

@vyasr vyasr self-assigned this Apr 30, 2026
@vyasr vyasr added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels Apr 30, 2026
@copy-pr-bot

copy-pr-bot Bot commented Apr 30, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@vyasr

vyasr commented Apr 30, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test

@copy-pr-bot

copy-pr-bot Bot commented Apr 30, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@vyasr
vyasr force-pushed the fix/symbol_export branch from 9de013e to 43cc963 Compare April 30, 2026 22:14
@vyasr
vyasr marked this pull request as ready for review April 30, 2026 22:15
@vyasr
vyasr requested review from a team as code owners April 30, 2026 22:15
@vyasr
vyasr force-pushed the fix/symbol_export branch from d616293 to fe5d0c3 Compare April 30, 2026 22:20
@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Applies a new export/visibility header and macro (CUML_EXPORT/CUML_HIDDEN); annotates many namespaces and some macro-generated functions with CUML_EXPORT; marks numerous explicit template instantiations in sources as exported; removes certain default parameters (LARS, SVR); updates a CMake target property and SPDX years.

Changes

Cohort / File(s) Summary
Build/export infra
cpp/include/cuml/common/export.hpp, cpp/CMakeLists.txt
Add CUML_EXPORT/CUML_HIDDEN macros and set hidden-symbol visibility properties on the cuml_objs target.
Bulk header namespace annotations
cpp/include/cuml/... (e.g. cluster/*, common/*, datasets/*, decomposition/*, ensemble/*, explainer/*, fil/*, forest/*, genetic/*, linear_model/*, manifold/*, matrix/*, metrics/*, neighbors/*, prims/opg/*, solvers/*, svm/*, tree/*, tsa/*)
Most headers now include <cuml/common/export.hpp> and apply CUML_EXPORT to ML/cuml/nested namespaces; SPDX years bumped.
Macro-produced API export changes (FIL)
cpp/include/cuml/fil/detail/specializations/device_initialization_macros.hpp, .../infer_macros.hpp
Macros modified so generated initialize_device/infer declarations include CUML_EXPORT.
Source explicit/template exports
cpp/src/* (examples: glm/*.cu, randomforest/*.cu, svm/*.cu, decisiontree/*.cu, metrics/*.cu, solver/*.cu, lars.cu, kmeans/*.cu)
Many explicit template instantiations and some template/class instantiations changed to template CUML_EXPORT ..., making those symbols exported from the library.
API signature adjustments (LARS, SVR, benchmarks)
cpp/include/cuml/solvers/lars.hpp, cpp/src/solver/lars_impl.cuh, cpp/include/cuml/svm/svr.hpp, cpp/bench/sg/svr.cu, cpp/src/solver/lars.cu
Removed/default-argument changes: LARS larsFit defaults removed (now required params); SVR sample_weight default removed (must pass pointer); benchmark call updated to pass explicit static_cast<D*>(nullptr); corresponding impl/instantiations adjusted.
Selected API exports & refactors
cpp/src/decisiontree/.../quantiles.cuh, cpp/src/matrix/kernel_params.cpp, cpp/src/kmeans/*.cu, cpp/include/cuml/matrix/kernel_params.hpp, many prims/opg/* headers
Marked specific functions/templates (e.g., computeQuantiles) exported; refactored some namespace forms to apply CUML_EXPORT (e.g., ML::matrixML { CUML_EXPORT matrix }); added #pragma once/includes and SPDX updates.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • csadorf
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix symbol export' directly and clearly summarizes the main change—adding symbol visibility controls (CUML_EXPORT annotations) to prevent unwanted weak symbol exports.
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.
Description check ✅ Passed PR description clearly describes the intent (add symbol visibility controls to avoid exporting weak symbols) and relates directly to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (2)
cpp/include/cuml/prims/opg/comm_utils.h (1)

1-10: ⚠️ Potential issue | 🔴 Critical

Restore a self include guard for this header

comm_utils.h contains in-header template definitions without a file-level include guard. This can trigger multiple-definition errors when the header is included in multiple translation units (as occurs here with 10 different .cu files). Add #pragma once at the top of the file.

Suggested fix
 /*
  * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION.
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#pragma once
+
 `#include` <cuml/common/export.hpp>
 
 `#include` <raft/core/comms.hpp>
 `#include` <raft/util/cuda_utils.cuh>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/include/cuml/prims/opg/comm_utils.h` around lines 1 - 10, comm_utils.h
lacks a file-level include guard which causes multiple-definition linker errors
because it defines in-header templates used across many translation units; fix
by adding a header guard such as placing `#pragma` once at the very top of
comm_utils.h so the template definitions (e.g., any templates in this file used
by functions/classes in comm_utils.h) are included only once per translation
unit.
cpp/include/cuml/common/pinned_host_vector.hpp (1)

12-55: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

pinned_host_vector has UB on default destruction and leaks on resize.

data_ and size_ are uninitialized in the default constructor, but the destructor always deallocates them. Also, resize replaces data_ without freeing existing storage.

Suggested fix
 template <typename T>
 class pinned_host_vector {
  public:
-  pinned_host_vector() = default;
+  pinned_host_vector() : data_{nullptr}, size_{0} {}
@@
-  ~pinned_host_vector() { pinned_mr.deallocate_sync(data_, size_ * sizeof(T)); }
+  ~pinned_host_vector()
+  {
+    if (data_ != nullptr) { pinned_mr.deallocate_sync(data_, size_ * sizeof(T)); }
+  }
@@
   void resize(std::size_t n)
   {
-    size_ = n;
-    data_ = static_cast<T*>(pinned_mr.allocate_sync(n * sizeof(T)));
-    std::uninitialized_fill(data_, data_ + n, static_cast<T>(0));
+    if (data_ != nullptr) { pinned_mr.deallocate_sync(data_, size_ * sizeof(T)); }
+    size_ = n;
+    data_ = (n == 0) ? nullptr : static_cast<T*>(pinned_mr.allocate_sync(n * sizeof(T)));
+    if (data_ != nullptr) { std::uninitialized_fill(data_, data_ + n, static_cast<T>(0)); }
   }
@@
  private:
   rmm::mr::pinned_host_memory_resource pinned_mr{};
-  T* data_;
-  std::size_t size_;
+  T* data_;
+  std::size_t size_;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/include/cuml/common/pinned_host_vector.hpp` around lines 12 - 55, The
class has undefined behavior because data_ and size_ are uninitialized and the
destructor unconditionally deallocates them, and resize leaks because it
overwrites data_ without freeing existing memory. Fix by initializing members
(set data_ = nullptr and size_ = 0) in the default constructor (and member
initializers), change the destructor to only call pinned_mr.deallocate_sync if
data_ != nullptr and size_ > 0, and make resize exception-safe by allocating a
new buffer into a temporary pointer, fill it, then swap/set data_ and size_ and
deallocate the old buffer (only if non-null) — reference the class
pinned_host_vector, its constructor, destructor (~pinned_host_vector), resize
method, and members data_ and size_ when applying the changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/include/cuml/linear_model/qn.h`:
- Around line 7-12: The header uses the CUML_EXPORT macro in the namespace
declaration (namespace ML { namespace CUML_EXPORT GLM {) but does not include
its definition; add an `#include` of cuml/common/export.hpp at the top of qn.h so
the CUML_EXPORT macro is defined and the header is self-sufficient and
consistent with other public headers.

In `@cpp/include/cuml/prims/opg/matrix/matrix_utils.hpp`:
- Around line 5-10: The header matrix_utils.hpp is missing an include guard
which causes redeclaration of functions like the randomize(...) overloads; add a
header guard (e.g., wrap the entire file in `#ifndef` SOME_UNIQUE_SYMBOL / `#define`
SOME_UNIQUE_SYMBOL ... `#endif`) or add `#pragma` once at the top of
matrix_utils.hpp so the randomize declarations (and any other symbols) are not
reprocessed on multiple includes.

In `@cpp/include/cuml/svm/svm_model.h`:
- Line 7: The header uses the CUML_EXPORT macro before it's defined; add an
include for the export header so CUML_EXPORT is defined (e.g., include
<cuml/common/export.hpp> near the top of svm_model.h before the namespace/usage
of CUML_EXPORT) so symbols like CUML_EXPORT and the namespace declaration
"namespace CUML_EXPORT ML" compile correctly.

In `@cpp/include/cuml/tree/algo_helper.h`:
- Line 8: The header uses the macro CUML_EXPORT in the namespace declaration but
doesn't include its definition; add an `#include` for the header that defines
CUML_EXPORT (e.g., export.hpp) at the top of cpp/include/cuml/tree/algo_helper.h
before the line with "namespace CUML_EXPORT ML {" so the macro is available when
the namespace is declared and compilation succeeds.

In `@cpp/src/svm/svr.cu`:
- Around line 24-42: The explicit template instantiations for svrFitSparse are
missing the CUML_EXPORT annotation, so add CUML_EXPORT to both
svrFitSparse<float> and svrFitSparse<double> instantiations in svr.cu (matching
how svrFit is exported) to ensure the sparse API symbols are exported for
external linking; locate the svrFitSparse template instantiation blocks in the
file and prepend CUML_EXPORT to each template declaration for float and double.

---

Outside diff comments:
In `@cpp/include/cuml/common/pinned_host_vector.hpp`:
- Around line 12-55: The class has undefined behavior because data_ and size_
are uninitialized and the destructor unconditionally deallocates them, and
resize leaks because it overwrites data_ without freeing existing memory. Fix by
initializing members (set data_ = nullptr and size_ = 0) in the default
constructor (and member initializers), change the destructor to only call
pinned_mr.deallocate_sync if data_ != nullptr and size_ > 0, and make resize
exception-safe by allocating a new buffer into a temporary pointer, fill it,
then swap/set data_ and size_ and deallocate the old buffer (only if non-null) —
reference the class pinned_host_vector, its constructor, destructor
(~pinned_host_vector), resize method, and members data_ and size_ when applying
the changes.

In `@cpp/include/cuml/prims/opg/comm_utils.h`:
- Around line 1-10: comm_utils.h lacks a file-level include guard which causes
multiple-definition linker errors because it defines in-header templates used
across many translation units; fix by adding a header guard such as placing
`#pragma` once at the very top of comm_utils.h so the template definitions (e.g.,
any templates in this file used by functions/classes in comm_utils.h) are
included only once per translation unit.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1464725a-52fd-4012-acbc-d6898aec44b0

📥 Commits

Reviewing files that changed from the base of the PR and between 016840c and 43cc963.

📒 Files selected for processing (108)
  • cpp/CMakeLists.txt
  • cpp/bench/sg/svr.cu
  • cpp/include/cuml/cluster/dbscan.hpp
  • cpp/include/cuml/cluster/hdbscan.hpp
  • cpp/include/cuml/cluster/kmeans.hpp
  • cpp/include/cuml/cluster/kmeans_params.hpp
  • cpp/include/cuml/cluster/linkage.hpp
  • cpp/include/cuml/cluster/spectral_clustering.hpp
  • cpp/include/cuml/common/callback.hpp
  • cpp/include/cuml/common/distance_type.hpp
  • cpp/include/cuml/common/export.hpp
  • cpp/include/cuml/common/logger.hpp
  • cpp/include/cuml/common/pinned_host_vector.hpp
  • cpp/include/cuml/common/utils.hpp
  • cpp/include/cuml/datasets/make_arima.hpp
  • cpp/include/cuml/datasets/make_blobs.hpp
  • cpp/include/cuml/datasets/make_regression.hpp
  • cpp/include/cuml/decomposition/params.hpp
  • cpp/include/cuml/decomposition/pca.hpp
  • cpp/include/cuml/decomposition/pca_mg.hpp
  • cpp/include/cuml/decomposition/sign_flip_mg.hpp
  • cpp/include/cuml/decomposition/tsvd.hpp
  • cpp/include/cuml/decomposition/tsvd_mg.hpp
  • cpp/include/cuml/ensemble/randomforest.hpp
  • cpp/include/cuml/explainer/kernel_shap.hpp
  • cpp/include/cuml/explainer/permutation_shap.hpp
  • cpp/include/cuml/explainer/tree_shap.hpp
  • cpp/include/cuml/fil/constants.hpp
  • cpp/include/cuml/fil/decision_forest.hpp
  • cpp/include/cuml/fil/detail/specializations/device_initialization_macros.hpp
  • cpp/include/cuml/fil/detail/specializations/infer_macros.hpp
  • cpp/include/cuml/fil/exceptions.hpp
  • cpp/include/cuml/fil/forest_model.hpp
  • cpp/include/cuml/fil/infer_kind.hpp
  • cpp/include/cuml/fil/postproc_ops.hpp
  • cpp/include/cuml/fil/tree_layout.hpp
  • cpp/include/cuml/fil/treelite_importer.hpp
  • cpp/include/cuml/forest/exceptions.hpp
  • cpp/include/cuml/forest/integrations/treelite.hpp
  • cpp/include/cuml/forest/traversal/traversal_forest.hpp
  • cpp/include/cuml/forest/traversal/traversal_node.hpp
  • cpp/include/cuml/forest/traversal/traversal_order.hpp
  • cpp/include/cuml/genetic/common.h
  • cpp/include/cuml/genetic/genetic.h
  • cpp/include/cuml/genetic/node.h
  • cpp/include/cuml/genetic/program.h
  • cpp/include/cuml/linear_model/glm.hpp
  • cpp/include/cuml/linear_model/ols_mg.hpp
  • cpp/include/cuml/linear_model/preprocess_mg.hpp
  • cpp/include/cuml/linear_model/qn.h
  • cpp/include/cuml/linear_model/qn_mg.hpp
  • cpp/include/cuml/linear_model/ridge_mg.hpp
  • cpp/include/cuml/manifold/common.hpp
  • cpp/include/cuml/manifold/spectral_embedding.hpp
  • cpp/include/cuml/manifold/tsne.h
  • cpp/include/cuml/manifold/umap.hpp
  • cpp/include/cuml/manifold/umapparams.h
  • cpp/include/cuml/matrix/kernel_params.hpp
  • cpp/include/cuml/metrics/metrics.hpp
  • cpp/include/cuml/neighbors/knn.hpp
  • cpp/include/cuml/neighbors/knn_mg.hpp
  • cpp/include/cuml/neighbors/knn_sparse.hpp
  • cpp/include/cuml/prims/opg/comm_utils.h
  • cpp/include/cuml/prims/opg/linalg/eig.hpp
  • cpp/include/cuml/prims/opg/linalg/gemm.hpp
  • cpp/include/cuml/prims/opg/linalg/lstsq.hpp
  • cpp/include/cuml/prims/opg/linalg/mean_squared_error.hpp
  • cpp/include/cuml/prims/opg/linalg/mm_aTa.hpp
  • cpp/include/cuml/prims/opg/linalg/mv_aTb.hpp
  • cpp/include/cuml/prims/opg/linalg/norm.hpp
  • cpp/include/cuml/prims/opg/linalg/svd.hpp
  • cpp/include/cuml/prims/opg/matrix/data.hpp
  • cpp/include/cuml/prims/opg/matrix/math.hpp
  • cpp/include/cuml/prims/opg/matrix/matrix_utils.hpp
  • cpp/include/cuml/prims/opg/matrix/part_descriptor.hpp
  • cpp/include/cuml/prims/opg/stats/cov.hpp
  • cpp/include/cuml/prims/opg/stats/mean.hpp
  • cpp/include/cuml/prims/opg/stats/mean_center.hpp
  • cpp/include/cuml/prims/opg/stats/stddev.hpp
  • cpp/include/cuml/solvers/cd_mg.hpp
  • cpp/include/cuml/solvers/lars.hpp
  • cpp/include/cuml/solvers/params.hpp
  • cpp/include/cuml/solvers/solver.hpp
  • cpp/include/cuml/svm/linear.hpp
  • cpp/include/cuml/svm/svc.hpp
  • cpp/include/cuml/svm/svm_model.h
  • cpp/include/cuml/svm/svm_parameter.h
  • cpp/include/cuml/svm/svr.hpp
  • cpp/include/cuml/tree/algo_helper.h
  • cpp/include/cuml/tree/decisiontree.hpp
  • cpp/include/cuml/tsa/arima_common.h
  • cpp/include/cuml/tsa/auto_arima.h
  • cpp/include/cuml/tsa/batched_arima.hpp
  • cpp/include/cuml/tsa/batched_kalman.hpp
  • cpp/include/cuml/tsa/holtwinters.h
  • cpp/include/cuml/tsa/holtwinters_params.h
  • cpp/include/cuml/tsa/stationarity.h
  • cpp/src/decisiontree/batched-levelalgo/quantiles.cuh
  • cpp/src/glm/glm.cu
  • cpp/src/kmeans/kmeans_fit.cu
  • cpp/src/kmeans/kmeans_predict.cu
  • cpp/src/kmeans/kmeans_transform.cu
  • cpp/src/matrix/kernel_params.cpp
  • cpp/src/metrics/trustworthiness.cu
  • cpp/src/randomforest/randomforest.cu
  • cpp/src/solver/lars_impl.cuh
  • cpp/src/svm/svc.cu
  • cpp/src/svm/svr.cu

Comment thread cpp/include/cuml/linear_model/qn.h
Comment thread cpp/include/cuml/prims/opg/matrix/matrix_utils.hpp
Comment thread cpp/include/cuml/svm/svm_model.h
Comment thread cpp/include/cuml/tree/algo_helper.h
Comment thread cpp/src/svm/svr.cu
@vyasr

vyasr commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all CodeRabbit feedback:

Inline comments (all fixed):

  • qn.h: Added #include <cuml/common/export.hpp> inside #ifdef __cplusplus
  • matrix_utils.hpp: Added #pragma once
  • svm_model.h: Added #include <cuml/common/export.hpp>
  • algo_helper.h: Added #include <cuml/common/export.hpp>
  • svr.cu: Added CUML_EXPORT to svrFitSparse instantiations

Outside-diff comments:

  • comm_utils.h: Added #pragma once
  • pinned_host_vector.hpp: Fixed UB (uninitialized members in default ctor, missing null check in dtor, leak in resize). Note: this is a pre-existing bug unrelated to visibility changes — just fixing it here since CodeRabbit flagged it. Kept in a separate commit for clarity.

Also added CUML_EXPORT to all remaining explicit template instantiations that were missing it (linear.cu, lars.cu, glm.cu, qn_mg.cu, decisiontree.cu, arima_common.cu) — this was causing the CI undefined symbol failure.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/include/cuml/common/pinned_host_vector.hpp`:
- Around line 34-39: The resize() is not exception-safe because it deallocates
old storage and updates size_ before guaranteeing the new
allocation/initialization succeeds; if allocate_sync() or
std::uninitialized_fill throws you end up with data_ pointing at freed memory.
Fix by allocating to a temporary pointer (e.g., T* new_data = (n==0? nullptr :
static_cast<T*>(pinned_mr.allocate_sync(...)))), perform initialization on
new_data (std::uninitialized_fill) and only after both allocation and
initialization succeed deallocate the old data_ via pinned_mr.deallocate_sync,
update data_ = new_data and size_ = n; if initialization/allocation fails,
ensure new_data is deallocated (or use RAII) so no leaks occur.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 62d15a6c-98b6-4830-adcb-7d871d12295d

📥 Commits

Reviewing files that changed from the base of the PR and between fe5d0c3 and 4258961.

📒 Files selected for processing (13)
  • cpp/include/cuml/common/pinned_host_vector.hpp
  • cpp/include/cuml/linear_model/qn.h
  • cpp/include/cuml/prims/opg/comm_utils.h
  • cpp/include/cuml/prims/opg/matrix/matrix_utils.hpp
  • cpp/include/cuml/svm/svm_model.h
  • cpp/include/cuml/tree/algo_helper.h
  • cpp/src/arima/arima_common.cu
  • cpp/src/decisiontree/decisiontree.cu
  • cpp/src/glm/glm.cu
  • cpp/src/glm/qn_mg.cu
  • cpp/src/solver/lars.cu
  • cpp/src/svm/linear.cu
  • cpp/src/svm/svr.cu
✅ Files skipped from review due to trivial changes (4)
  • cpp/include/cuml/prims/opg/comm_utils.h
  • cpp/include/cuml/prims/opg/matrix/matrix_utils.hpp
  • cpp/include/cuml/tree/algo_helper.h
  • cpp/src/glm/glm.cu
🚧 Files skipped from review as they are similar to previous changes (3)
  • cpp/include/cuml/svm/svm_model.h
  • cpp/include/cuml/linear_model/qn.h
  • cpp/src/svm/svr.cu

Comment thread cpp/include/cuml/common/pinned_host_vector.hpp
@vyasr
vyasr force-pushed the fix/symbol_export branch from 4258961 to c7ac4eb Compare May 1, 2026 02:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
cpp/include/cuml/common/pinned_host_vector.hpp (1)

34-39: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

resize() is still not exception-safe and can double-free on allocation failure.

data_ is deallocated before new allocation/initialization is guaranteed. If allocate_sync() throws, data_ remains a dangling non-null pointer and the destructor can deallocate it again.

Suggested fix
 void resize(std::size_t n)
 {
-  if (data_ != nullptr) { pinned_mr.deallocate_sync(data_, size_ * sizeof(T)); }
-  size_ = n;
-  data_ = (n == 0) ? nullptr : static_cast<T*>(pinned_mr.allocate_sync(n * sizeof(T)));
-  if (data_ != nullptr) { std::uninitialized_fill(data_, data_ + n, static_cast<T>(0)); }
+  T* new_data = (n == 0) ? nullptr : static_cast<T*>(pinned_mr.allocate_sync(n * sizeof(T)));
+  try {
+    if (new_data != nullptr) { std::uninitialized_fill(new_data, new_data + n, static_cast<T>(0)); }
+  } catch (...) {
+    if (new_data != nullptr) { pinned_mr.deallocate_sync(new_data, n * sizeof(T)); }
+    throw;
+  }
+
+  if (data_ != nullptr) { pinned_mr.deallocate_sync(data_, size_ * sizeof(T)); }
+  data_ = new_data;
+  size_ = n;
 }

Based on learnings: "Check for GPU memory leaks in exception paths and ensure cleanup is properly invoked using RAII or try-finally patterns."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/include/cuml/common/pinned_host_vector.hpp` around lines 34 - 39,
resize() currently deallocates data_ before performing the new
allocation/initialization which can leave data_ as a dangling non-null pointer
if pinned_mr.allocate_sync throws; change resize(std::size_t n) to first
allocate into a temporary pointer (e.g. T* new_data = (n==0)? nullptr :
static_cast<T*>(pinned_mr.allocate_sync(...))) and only after allocation and
initialization (use std::uninitialized_fill_n or placement-new loop and catch
exceptions to deallocate new_data) deallocate the old data_ via
pinned_mr.deallocate_sync(data_, size_*sizeof(T)) and then assign data_ =
new_data and size_ = n, ensuring that on allocation or initialization failure
the original data_ remains intact and any partially constructed new_data is
cleaned up to avoid double-free or leaks; reference symbols: resize, data_,
size_, pinned_mr.allocate_sync, pinned_mr.deallocate_sync, and
std::uninitialized_fill.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@cpp/include/cuml/common/pinned_host_vector.hpp`:
- Around line 34-39: resize() currently deallocates data_ before performing the
new allocation/initialization which can leave data_ as a dangling non-null
pointer if pinned_mr.allocate_sync throws; change resize(std::size_t n) to first
allocate into a temporary pointer (e.g. T* new_data = (n==0)? nullptr :
static_cast<T*>(pinned_mr.allocate_sync(...))) and only after allocation and
initialization (use std::uninitialized_fill_n or placement-new loop and catch
exceptions to deallocate new_data) deallocate the old data_ via
pinned_mr.deallocate_sync(data_, size_*sizeof(T)) and then assign data_ =
new_data and size_ = n, ensuring that on allocation or initialization failure
the original data_ remains intact and any partially constructed new_data is
cleaned up to avoid double-free or leaks; reference symbols: resize, data_,
size_, pinned_mr.allocate_sync, pinned_mr.deallocate_sync, and
std::uninitialized_fill.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 076c8764-1f9b-497a-b830-d21a2d85d049

📥 Commits

Reviewing files that changed from the base of the PR and between 4258961 and c7ac4eb.

📒 Files selected for processing (13)
  • cpp/include/cuml/common/pinned_host_vector.hpp
  • cpp/include/cuml/linear_model/qn.h
  • cpp/include/cuml/prims/opg/comm_utils.h
  • cpp/include/cuml/prims/opg/matrix/matrix_utils.hpp
  • cpp/include/cuml/svm/svm_model.h
  • cpp/include/cuml/tree/algo_helper.h
  • cpp/src/arima/arima_common.cu
  • cpp/src/decisiontree/decisiontree.cu
  • cpp/src/glm/glm.cu
  • cpp/src/glm/qn_mg.cu
  • cpp/src/solver/lars.cu
  • cpp/src/svm/linear.cu
  • cpp/src/svm/svr.cu
✅ Files skipped from review due to trivial changes (3)
  • cpp/include/cuml/prims/opg/matrix/matrix_utils.hpp
  • cpp/include/cuml/prims/opg/comm_utils.h
  • cpp/src/glm/qn_mg.cu
🚧 Files skipped from review as they are similar to previous changes (3)
  • cpp/include/cuml/tree/algo_helper.h
  • cpp/include/cuml/linear_model/qn.h
  • cpp/src/solver/lars.cu

@vyasr
vyasr requested a review from a team as a code owner May 1, 2026 23:25
@vyasr
vyasr requested a review from gforsyth May 1, 2026 23:25
@github-actions github-actions Bot added the conda conda issue label May 1, 2026
@vyasr

vyasr commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

487cc16 shows CI mostly passing, including the upstream CUVS and RAFT changes. The only failing tests are due to challenges in propagating the correct NVRTC dependencies all the way downstream in Conda when we build CUVS from source, but that is not critical to demonstrate here. The various other passing tests and examples demonstrate that all of the necessary symbols are being exported, which is the main thing we're concerned about.

@github-actions github-actions Bot removed the conda conda issue label May 3, 2026
Comment thread cpp/include/cuml/common/export.hpp
Comment thread cpp/include/cuml/common/pinned_host_vector.hpp
@csadorf
csadorf removed request for a team and gforsyth May 8, 2026 16:48
@vyasr
vyasr force-pushed the fix/symbol_export branch from 2f99b24 to a5eb314 Compare May 16, 2026 04:52
@vyasr
vyasr requested a review from a team as a code owner May 16, 2026 04:52
@vyasr
vyasr requested a review from viclafargue May 16, 2026 04:52
@github-actions github-actions Bot added conda conda issue Cython / Python Cython or Python issue labels May 16, 2026
@vyasr
vyasr changed the base branch from main to release/26.06 May 16, 2026 05:00
@vyasr
vyasr force-pushed the fix/symbol_export branch from a5eb314 to 0f249c7 Compare May 16, 2026 05:02
@vyasr

vyasr commented May 16, 2026

Copy link
Copy Markdown
Contributor Author

OK, now that we're seeing a seg fault here it's easier to debug. The problem is that the decision we made in NVIDIA/raft#3006 to continue exporting detail functions (see NVIDIA/raft#3006 (comment)) in raft is a problem because now every library that uses header-only components of raft is reexporting the symbols in raft and therefore potentially susceptible to symbol conflicts. It isn't a new problem, but it's explicitly showing up consistently in this PR now. That means that at least for the header-only parts of raft we have to avoid exporting them now to avoid this problem, including the detail bits that we hid before.

@vyasr
vyasr requested a review from a team as a code owner May 19, 2026 21:45
@vyasr
vyasr requested a review from KyleFromNVIDIA May 19, 2026 21:45
@github-actions github-actions Bot added the ci label May 19, 2026
@vyasr
vyasr force-pushed the fix/symbol_export branch from ac8e04e to 2b47273 Compare May 21, 2026 00:19
Set CXX_VISIBILITY_PRESET=hidden and CUDA_VISIBILITY_PRESET=hidden on
cuml_objs so that only symbols explicitly marked CUML_EXPORT are visible
in the shared library. This prevents symbol interposition between
libcuml.so and libcuvs.so when both link raft headers that instantiate
identical template specializations in detail namespaces.

Changes:
- Add cpp/include/cuml/common/export.hpp defining CUML_EXPORT macro
- Set hidden visibility presets on cuml_objs target in CMakeLists.txt
- Annotate all public API declarations in cpp/include/cuml/ with CUML_EXPORT
- Wrap implementation details in cpp/src/ with anonymous namespaces
- Exclude export.hpp from Doxygen
@vyasr
vyasr force-pushed the fix/symbol_export branch from 2b47273 to 2d26c61 Compare May 21, 2026 00:41
@vyasr

vyasr commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

https://github.com/rapidsai/cuml/actions/runs/26194638861?pr=8037 shows enough CI passing with the artifacts from NVIDIA/cuvs#2101 and NVIDIA/raft#3019 (there are some unrelated failures in tests but all symbol handling looks fine).

@vyasr
vyasr changed the base branch from release/26.06 to main May 21, 2026 00:48
vyasr added 3 commits May 22, 2026 11:46
# Conflicts:
#	cpp/include/cuml/fil/constants.hpp
#	cpp/include/cuml/fil/decision_forest.hpp
#	cpp/include/cuml/fil/detail/specializations/device_initialization_macros.hpp
#	cpp/include/cuml/fil/detail/specializations/infer_macros.hpp
#	cpp/include/cuml/fil/exceptions.hpp
#	cpp/include/cuml/fil/forest_model.hpp
#	cpp/include/cuml/fil/infer_kind.hpp
#	cpp/include/cuml/fil/postproc_ops.hpp
#	cpp/include/cuml/fil/tree_layout.hpp
#	cpp/include/cuml/fil/treelite_importer.hpp
#	cpp/include/cuml/forest/exceptions.hpp
#	cpp/include/cuml/forest/integrations/treelite.hpp
#	cpp/include/cuml/forest/traversal/traversal_forest.hpp
#	cpp/include/cuml/forest/traversal/traversal_node.hpp
#	cpp/include/cuml/forest/traversal/traversal_order.hpp
@vyasr
vyasr removed request for a team, KyleFromNVIDIA and viclafargue May 22, 2026 21:40
@vyasr

vyasr commented May 23, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit e8898ff into NVIDIA:main May 23, 2026
102 checks passed
@vyasr
vyasr deleted the fix/symbol_export branch May 23, 2026 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CMake conda conda issue CUDA/C++ Cython / Python Cython or Python issue improvement Improvement / enhancement to an existing function non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants