mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 18:40:43 +03:00
fix: Shift exponent too large
Undefined operation is reported by running ztest (or zloop) compiled with GCC UndefinedBehaviorSanitizer. Error only happens on top level of dnode indirection with large enough offset values. Logically, left shift operation would work, but bit shift semantics in C, and limitation of uint64_t, do not produce desired result. Issue #5059, #4883 Signed-off-by: Gvozden Neskovic <neskovic@gmail.com>
This commit is contained in:
committed by
Brian Behlendorf
parent
0b78aeae92
commit
031d7c2fe6
+17
-2
@@ -1612,6 +1612,8 @@ dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, boolean_t have_read)
|
||||
sz <= blkid && sz >= dn->dn_nblkptr; sz <<= epbs)
|
||||
new_nlevels++;
|
||||
|
||||
ASSERT3U(new_nlevels, <=, DN_MAX_LEVELS);
|
||||
|
||||
if (new_nlevels > dn->dn_nlevels) {
|
||||
int old_nlevels = dn->dn_nlevels;
|
||||
dmu_buf_impl_t *db;
|
||||
@@ -2073,7 +2075,14 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
|
||||
else
|
||||
minfill++;
|
||||
|
||||
*offset = *offset >> span;
|
||||
if (span >= 8 * sizeof (*offset)) {
|
||||
/* This only happens on the highest indirection level */
|
||||
ASSERT3U((lvl - 1), ==, dn->dn_phys->dn_nlevels - 1);
|
||||
*offset = 0;
|
||||
} else {
|
||||
*offset = *offset >> span;
|
||||
}
|
||||
|
||||
for (i = BF64_GET(*offset, 0, epbs);
|
||||
i >= 0 && i < epb; i += inc) {
|
||||
if (BP_GET_FILL(&bp[i]) >= minfill &&
|
||||
@@ -2083,7 +2092,13 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
|
||||
if (inc > 0 || *offset > 0)
|
||||
*offset += inc;
|
||||
}
|
||||
*offset = *offset << span;
|
||||
|
||||
if (span >= 8 * sizeof (*offset)) {
|
||||
*offset = start;
|
||||
} else {
|
||||
*offset = *offset << span;
|
||||
}
|
||||
|
||||
if (inc < 0) {
|
||||
/* traversing backwards; position offset at the end */
|
||||
ASSERT3U(*offset, <=, start);
|
||||
|
||||
Reference in New Issue
Block a user