Skip to content

Commit 8c8f6ea

Browse files
mstrathmanclaude
andcommitted
fix: resolve open CodeQL alerts (float widening, workflow permissions)
Two high alerts (cpp/integer-multiplication-cast-to-long): forest serving multiplied f->lr (float) by a float tree value before widening to the double accumulator, so the product could overflow to infinity, and under x87 excess precision vary by platform, before the widening. Promote to double before the multiply in both spots, matching the trainer (predict-train.c already does). Two medium alerts (actions/missing-workflow-permissions): wheels.yml had no permissions block, so the build jobs got the default token scopes. Default the workflow token to contents:read; the publish job keeps its id-token:write override for PyPI OIDC. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d99caf8 commit 8c8f6ea

3 files changed

Lines changed: 20 additions & 2 deletions

File tree

‎.github/workflows/wheels.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ on:
55
tags: ["v*"]
66
workflow_dispatch:
77

8+
# Default the GITHUB_TOKEN to read-only; the publish job opts into
9+
# id-token: write for PyPI OIDC and nothing else needs write.
10+
permissions:
11+
contents: read
12+
813
# Builds the Python wheels (`pip install sqlite-predict`). Each wheel bundles the
914
# zero-dependency loadable compiled for its platform. Staging runs `make
1015
# python-src` on the host to drop the amalgamation + SQLite ext headers into the

‎CHANGELOG.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- **Forest prediction accumulates the learning-rate product in double**, matching
12+
the trainer. The serving path computed `float * float` before widening to the
13+
`double` accumulator, which could overflow to infinity (and, under x87 excess
14+
precision, differ by platform) before the widening. Predictions are computed
15+
consistently in double now; served values may shift in their least-significant
16+
digits.
17+
918
## [0.2.0] - 2026-07-31
1019

1120
### Changed

‎predict-student.c‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,10 @@ int predict0_forest_predict_row(const Forest *f, const f32 *x, f64 *scbuf, char
276276
if (f->task == 1) {
277277
f64 s = f->init[0];
278278
for (int j = 0; j < f->n_trees; j++)
279-
s += f->lr * forest_tree_value(f, j, x);
279+
/* (f64) before the multiply: keep the product in double, matching the
280+
* trainer (predict-train.c), so a float*float never overflows or picks up
281+
* platform-dependent excess precision before it reaches the accumulator. */
282+
s += (f64)f->lr * forest_tree_value(f, j, x);
280283
*has_conf = 0;
281284
*pred = sqlite3_mprintf("%.17g", s);
282285
return *pred ? SQLITE_OK : SQLITE_NOMEM;
@@ -285,7 +288,8 @@ int predict0_forest_predict_row(const Forest *f, const f32 *x, f64 *scbuf, char
285288
scbuf[c] = f->init[c];
286289
for (int r = 0; r < f->n_rounds; r++)
287290
for (int s = 0; s < f->n_score; s++)
288-
scbuf[s] += f->lr * forest_tree_value(f, r * f->n_score + s, x);
291+
/* (f64) before the multiply, as above and in the trainer */
292+
scbuf[s] += (f64)f->lr * forest_tree_value(f, r * f->n_score + s, x);
289293
f64 mx = scbuf[0];
290294
int arg = 0;
291295
for (int c = 1; c < f->n_score; c++)

0 commit comments

Comments
 (0)