Skip to content

fix: avoid out-of-bounds read of the SMAPE weight array#753

Open
dnplkndll wants to merge 1 commit into
frePPLe:masterfrom
ledoent:fix/forecast-weight-bounds
Open

fix: avoid out-of-bounds read of the SMAPE weight array#753
dnplkndll wants to merge 1 commit into
frePPLe:masterfrom
ledoent:fix/forecast-weight-bounds

Conversation

@dnplkndll

Copy link
Copy Markdown
Contributor

weight[] (MAXBUCKETS = 500 entries) is indexed weight[count - i] where count is the history-bucket count (~520 weekly / ~3650 daily over the default 10-year horizon), reading past the array and corrupting SMAPE method selection.

Adds a clamping smapeWeight() accessor — behaviour-preserving since weights decay exponentially (weight[>=500] ≈ 0) — fixes a second initializer that filled only 300 of the 500 entries, and adds test/forecast_11 (the overflow is flagged by an AddressSanitizer build).

weight[] has MAXBUCKETS (500) entries but is indexed weight[count - i] where
count is the history-bucket count (~520 weekly / ~3650 daily over the default
10-yr horizon), reading past the array and corrupting SMAPE method selection.
Add a clamping smapeWeight() accessor; weights decay exponentially so
weight[>=500] ~= 0, making the clamp behaviour-preserving. Also fix a second
initializer that filled only 300 of the 500 entries. Adds test/forecast_11
(weekly history >500 buckets; the overflow is flagged by an ASan build).
Comment thread src/forecast/forecast.h
// entries above the old hardcoded bound stay stale when this setter runs.
weight[0] = 1.0;
for (int i = 0; i < 299; ++i)
for (int i = 0; i < MAXBUCKETS - 1; ++i)

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.

This correction is absolutely correct. An oversight when the hardcoded limit was replaced with this constant.

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.

Picked this up f27c268

Comment thread src/forecast/forecast.h
if (idx < 0) idx = 0;
if (idx >= MAXBUCKETS) idx = MAXBUCKETS - 1;
return weight[idx];
}

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.

Not sure whether this change is worth picking up.

  • It's extremely rare we need more than 500 buckets of demand history. You already indicate that the weight of these buckets is close to 0. In functional terms: "what happened 500 time buckets ago has very little impact on the forecast we compute for the next forecast buckets"

  • While the forecast calculations are fast, this will have a (minimal) performance impact.

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