Thanks to visit codestin.com
Credit goes to github.com

Skip to content

FIX linear.cpp: avoid out-of-bound read in n_iter for crammer_singer - #34273

Merged
virchan merged 3 commits into
scikit-learn:mainfrom
jakevdp:linear-oob-write
Jul 14, 2026
Merged

FIX linear.cpp: avoid out-of-bound read in n_iter for crammer_singer#34273
virchan merged 3 commits into
scikit-learn:mainfrom
jakevdp:linear-oob-write

Conversation

@jakevdp

@jakevdp jakevdp commented Jun 12, 2026

Copy link
Copy Markdown
Member

Following up on #34256, I ran some of the SVM tests in ASAN mode and discovered an out-of-bound read in linear.cpp. Here's a Python script that hits this (run in sklearn v1.9.0, but the issue predates this):

import numpy as np
from sklearn import svm

# Toy dataset with 3 classes
X = np.array([[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5]], dtype=np.float64)
y = np.array([0, 0, 1, 1, 2, 2])

n_iter_values = set()

for i in range(100):
  clf = svm.LinearSVC(multi_class="crammer_singer", random_state=42)
  clf.fit(X, y)
  n_iter_values.add(clf.n_iter_)

print(n_iter_values)

The expectation is that clf.n_iter_ would be deterministic, such that n_iter_values would always contain a single entry. But this non-deterministically returns 2 or more entries:

$ python repro.py
{446}
$ python repro.py
{251081824, 446}

ASAN shows that the culprit is an out-of-bound read at line 2949 here:

void get_n_iter(const model *model_, int* n_iter)
{
int labels;
labels = model_->nr_class;
if (labels == 2)
labels = 1;
if (model_->n_iter != NULL)
for(int i=0;i<labels;i++)
n_iter[i] = model_->n_iter[i];
}

The issue is the condition in lines 2943-2955: it assumes that the length of n_iter is nr_class, except in the case that nr_class == 2. Looking through the file for where n_iter is allocated, this logic is correct except in the case that solver_type == MCSVM_CS here:

if(param->solver_type == MCSVM_CS)
{
model_->w=Malloc(double, n*nr_class);
model_->n_iter=Malloc(int, 1);

Here the length of n_iter is 1, while the associated nr_class is an arbitrary non-negative integer representing the number of classes:
model_->nr_class=nr_class;

The net result of this is that line 2949 is an out-of-bound-read under the following conditions:

  • LinearSVC with multi_class="crammer_singer"
  • The number of classes is 3 or more

The fix here is to specifically check the solver_type to use the correct length for n_iter in this read.

AI usage disclosure

I used AI to execute tests in ASAN mode and to locate the root cause of this issue. I made the code changes and wrote the PR description manually.

@lorentzenchr lorentzenchr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@jakevdp thanks for this fix (I am wondering if upstream liblinear fixed those issues in newer versions)

@lorentzenchr lorentzenchr added Bug Quick Review For PRs that are quick to review Waiting for Second Reviewer First reviewer is done, need a second one! labels Jun 22, 2026
@lorentzenchr lorentzenchr changed the title linear.cpp: avoid out-of-bound read in n_iter for crammer_singer FOX linear.cpp: avoid out-of-bound read in n_iter for crammer_singer Jun 22, 2026
@betatim betatim changed the title FOX linear.cpp: avoid out-of-bound read in n_iter for crammer_singer FIX linear.cpp: avoid out-of-bound read in n_iter for crammer_singer Jun 22, 2026
@jakevdp

jakevdp commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

I am wondering if upstream liblinear fixed those issues in newer versions

It's possible: scikit-learn's bundled liblinear was forked from the source 15 years ago!

@lorentzenchr

lorentzenchr commented Jun 22, 2026

Copy link
Copy Markdown
Member

Do you want to add a whatsnew entry?

@virchan virchan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM! Thanks, @jakevdp!

I can merge this once the changelog has been added.

@jakevdp
jakevdp force-pushed the linear-oob-write branch from 391b4b6 to 8d902dc Compare July 13, 2026 16:16
@jakevdp

jakevdp commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

I added the whats_new entry – thanks!

@virchan
virchan merged commit 02dbd4b into scikit-learn:main Jul 14, 2026
38 checks passed
@jakevdp
jakevdp deleted the linear-oob-write branch July 14, 2026 03:46
@jeremiedbb jeremiedbb mentioned this pull request Sep 8, 2026
14 tasks
jeremiedbb pushed a commit to jeremiedbb/scikit-learn that referenced this pull request Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug module:svm Quick Review For PRs that are quick to review Waiting for Second Reviewer First reviewer is done, need a second one!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants