inetaf / netaddr

Network address types

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

possible bug in uint128.lastWithBitZero

josharian opened this issue · comments

// lastWithBitZero returns a copy of u with the given bit
// cleared and the following all set.
func (u uint128) lastWithBitZero(bit uint8) uint128 {
	u.clear(bit)
	for ; bit < 128; bit++ {
		u.set(bit)
	}
	return u
}

The docs say it clears the given bit and sets the following.

The code clears the given bit, and then sets it again, along with the following.

Seems like it needs a bit++ before the for loop.

Something similar is true for uint128.firstWithBitOne.

Also, it's unclear from the docs which direction bit counting commences from--is the 0th bit the highest or the lowest order bit?

I also suspect that this can be implemented without a loop, using a branch on whether bit is above/below 64 and a helper like:

func u64LastWithBitZero(x uint64, bit uint8) uint64 {
	x &^= 1 << bit
	x |= (1 << bit) - 1
	return x
}

but before doing that I want to correct, document, and stabilize the existing code.

cc @bradfitz @danderson

Debugging. It looks like it works because the caller adds +1,

        dst = appendRangePrefixes(dst, makePrefix, a, a.lastWithBitZero(common+1))
        dst = appendRangePrefixes(dst, makePrefix, b.firstWithBitOne(common+1), b)

And that previous bit was already correct, always a zero first in a, and set in b, because ais less thanb`, due to it being a valid range.

I wonder if I changed my mind on how to implement midway through and forgot to rename the funcs or I was just saved by what is kinda two off by one errors.

I'll rename & clarify. You can optimize later.

Picture of debug output, FWIW:

Screen Shot 2020-12-31 at 8 25 25 PM