Opened 6 years ago

Closed 5 years ago

Last modified 5 years ago

#869 closed defect (fixed)

CommonBits::zeroLowerBits undefined behavior

Reported by: goatbar Owned by: geos-devel@…
Priority: minor Milestone: 3.6.4
Component: Default Version: 3.6.2
Severity: Unassigned Keywords: UndefinedBehavior
Cc:

Description

It is possible to get nBits to be a shift larger than 1 << 63

I don't have a cleaned up test case for this issue. I will try to add one to this issue soon.

This is probably not the right fix...

/*static public*/
int64
CommonBits::zeroLowerBits(int64 bits, int nBits)
{
        if (nBits >= sizeof(nBits) * 8) return 0;
        int64 invMask = (1<< nBits)-1;
        int64 mask = ~ invMask;
        int64 zeroed = bits & mask;
        return zeroed;
}

Found with autofuzz.

Change History (11)

comment:1 by robe, 6 years ago

Milestone: 3.6.33.6.4

comment:2 by Paul Ramsey <pramsey@…>, 5 years ago

In 6c5b169/git:

Handle nbits > 37
References #869

comment:3 by Paul Ramsey <pramsey@…>, 5 years ago

In 2c9bfe8/git:

Handle nbits > 63
References #869

comment:4 by Paul Ramsey <pramsey@…>, 5 years ago

Resolution: fixed
Status: newclosed

In b8a51cb/git:

Handle nbits > 63
3.6 branch
Closes #869

comment:5 by rouault, 5 years ago

Resolution: fixed
Status: closedreopened

Actually, the fix is incorrect for several reasons:

  • (1<< nBits)-1 has only int operands, so will be evaluated on 32 bit only. Consequently nBits >= 32 will result in incorrect behaviour, unless you cast the first 1 to int64 : ((int64)1 << nBits) - 1
  • but, if let to 32 bits ( (1<< nBits)-1 ), then nBits == 31 is also an invalid input (-fsanitize=undefined warns about "runtime error: left shift of 1 by 31 places cannot be represented in type 'int'") even if "sane" compilers / most CPUs will finally do the right thing. The right fix in that case to avoid undefined/implementation defined behaviour is to use a unsigned 1, so (1U << nBits) - 1
  • for the same reason, is the mask is intended to be a 64 bit one, so ((int64)1 << nBits) - 1), then nBits == 63 also triggers undefined behaviour. And thus the right fix would be ((unsigned int64)1 << nBits) - 1

comment:6 by Paul Ramsey <pramsey@…>, 5 years ago

In 311b64a/git:

Improve the bit-shifting logic with good types and so on
Even Roualt, Kurt Schwehr
References #869

comment:7 by Paul Ramsey <pramsey@…>, 5 years ago

In 3e8be5b/git:

Improve the bit-shifting logic with good types and so on
Even Roualt, Kurt Schwehr
References #869

comment:8 by Paul Ramsey <pramsey@…>, 5 years ago

In 9362bf2/git:

Improve the bit-shifting logic with good types and so on
Even Roualt, Kurt Schwehr
References #869

comment:9 by pramsey, 5 years ago

Resolution: fixed
Status: reopenedclosed

comment:10 by nila, 5 years ago

@pramsey I noticed the initial commits didn't fall out well on some builds.

I could not reproduce the failure, but perhaps using std::uint64_t would make any difference.

comment:11 by goatbar, 5 years ago

Thanks!

Last edited 5 years ago by goatbar (previous) (diff)
Note: See TracTickets for help on using tickets.