Skip to content

Fix Blob::offset lower-bound checks guarding the dim instead of the index#7107

Open
Chessing234 wants to merge 1 commit intoBVLC:masterfrom
Chessing234:fix/blob-offset-wrong-variable-in-lower-bounds
Open

Fix Blob::offset lower-bound checks guarding the dim instead of the index#7107
Chessing234 wants to merge 1 commit intoBVLC:masterfrom
Chessing234:fix/blob-offset-wrong-variable-in-lower-bounds

Conversation

@Chessing234
Copy link
Copy Markdown

Issue #6391 (complements #7102, which fixes the upper bounds).

Bug

In include/caffe/blob.hpp, the four-argument Blob::offset(n, c, h, w) writes its lower-bound guards as:

CHECK_GE(n, 0);
CHECK_LE(n, num());
CHECK_GE(channels(), 0);
CHECK_LE(c, channels());
CHECK_GE(height(), 0);
CHECK_LE(h, height());
CHECK_GE(width(), 0);
CHECK_LE(w, width());

Only the first CHECK_GE(n, 0) actually checks the index. The next three CHECK_GE calls check the dimensions of the blob (channels(), height(), width()), not the indices c, h, w. For any constructed blob those dims are structurally non-negative, so the asserts are vacuous — a negative c/h/w is accepted and then fed into

return ((n * channels() + c) * height() + h) * width() + w;

which addresses memory outside the buffer.

Root cause

Almost certainly a copy-paste slip when this legacy-accessor overload was written. The sibling vector overload immediately below shows the intended pattern:

CHECK_GE(indices[i], 0);
CHECK_LT(indices[i], shape(i));

— guarding the index, not the dimension.

Fix

Point the three CHECK_GE calls at c, h, w (the actual indices) so the legacy overload enforces the same [0, dim) contract as the vector overload:

-    CHECK_GE(channels(), 0);
+    CHECK_GE(c, 0);
     CHECK_LE(c, channels());
-    CHECK_GE(height(), 0);
+    CHECK_GE(h, 0);
     CHECK_LE(h, height());
-    CHECK_GE(width(), 0);
+    CHECK_GE(w, 0);
     CHECK_LE(w, width());

Scope is intentionally limited to the lower-bound variable mistake. Upper-bound hardening (CHECK_LECHECK_LT) is handled separately by #7102; the two PRs touch disjoint lines in the same function and can land in either order without conflict.

…ndex

Issue BVLC#6391.

The four-argument Blob::offset(n, c, h, w) has lower-bound guards of the
form:

    CHECK_GE(n, 0);
    CHECK_GE(channels(), 0);
    CHECK_GE(height(), 0);
    CHECK_GE(width(), 0);

Only the first line checks the index. The other three check the *dimensions*
of the blob (channels(), height(), width()), which for any constructed blob
are structurally non-negative -- these are vacuous asserts that fire only
if the blob itself is malformed, and never guard the index the caller passed
in. A negative c/h/w is silently accepted and then used to compute

    ((n * channels() + c) * height() + h) * width() + w

pointing outside the buffer.

The vector overload a few lines below already gets this right:

    CHECK_GE(indices[i], 0);
    CHECK_LT(indices[i], shape(i));

This change only touches the three misnamed CHECK_GE calls so the lower
bounds match the vector overload and the bounds the call actually needs.
Upper-bound hardening (CHECK_LE -> CHECK_LT) is out of scope; it is
handled separately by BVLC#7102.
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