Golang代码中的这个bug在哪里?

Golang代码中的这个bug在哪里? 该方法检查第一个IP网络是否包含第二个IP网络(第一个的子网掩码长度应小于等于第二个的子网掩码长度,并且它们的IP地址在第一个掩码长度范围内应相同):

func ContainsIPNetwork(first, second net.IPNet) bool {
	if len(first.IP) != len(second.IP) {
		return false
	}

	i := len(first.IP) - 1

	for i > 0 && (first.Mask[i]|second.Mask[i] == 0) {
		i--
	}

	if first.Mask[i] > second.Mask[i] || ((first.IP[i]^second.IP[i])&first.Mask[i] != 0) {
		return false
	}

	i--

	for i >= 0 && first.IP[i] == second.IP[i] {
		i--
	}

	return i == -1
}

上面的代码存在一个错误,它在大多数情况下都能工作,但并非所有情况。你能找出来吗?

我个人无法找出,但确实存在一个错误。我应该怎么做才能找出它呢?


更多关于Golang代码中的这个bug在哪里?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

我没有检查代码,但是:

  • 你如何知道存在一个错误?(通过测试、流程……)
  • 你尝试过调试代码吗?

更多关于Golang代码中的这个bug在哪里?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如何知道存在错误?

以下是两个失败的测试用例:

第一个 {IP:0.0.0.0 Mask:00000000}, 第二个 {IP:2.0.0.0 Mask:ffffffff}, 包含关系为 false <–错误 第一个 {IP:0.0.0.0 Mask:00000000}, 第二个 {IP:255.255.255.255 Mask:ffffffff}, 包含关系为 false <–错误

第一个 {IP:0.0.0.0 Mask:00000000}, 第二个 {IP:2.0.0.0 Mask:ffffffff}, 包含 false <–错误

对于你的第一个例子,在这个循环中:

for i >= 0 && first.IP[i] == second.IP[i] {

i == 0 时,first.IP[0] == 0second.IP[0] == 2,所以循环中断并返回 i == -1 (0 == -1, false)。

第一个 {IP:0.0.0.0 Mask:00000000}, 第二个 {IP:255.255.255.255 Mask:ffffffff}, 包含 false <–错误

对于你的第二个例子,在同一个循环中,当 i3 递减到 2 时,first.IP[2] == 0second.IP[2] == 255,所以循环中断并返回 i == -1 (2 == -1, false)。

Go Playground - The Go Programming Language

Go Playground - The Go Programming Language

这个代码的bug在于掩码比较逻辑。问题出现在第10行的循环条件中:

for i > 0 && (first.Mask[i]|second.Mask[i] == 0) {
    i--
}

这个条件检查两个掩码字节的按位或结果是否为0,但正确的逻辑应该是检查第一个掩码是否小于等于第二个掩码。当前的逻辑会错误地跳过某些需要比较的字节。

以下是修复后的代码:

func ContainsIPNetwork(first, second net.IPNet) bool {
    if len(first.IP) != len(second.IP) {
        return false
    }

    // 找到需要比较的最高有效字节
    i := len(first.IP) - 1
    for i > 0 && first.Mask[i] == 0 && second.Mask[i] == 0 {
        i--
    }

    // 检查掩码长度条件:第一个掩码必须小于等于第二个掩码
    if first.Mask[i] > second.Mask[i] {
        return false
    }

    // 检查IP地址在第一个掩码范围内的匹配
    for j := 0; j <= i; j++ {
        if (first.IP[j]^second.IP[j])&first.Mask[j] != 0 {
            return false
        }
    }

    return true
}

或者更简洁的实现:

func ContainsIPNetwork(first, second net.IPNet) bool {
    if len(first.IP) != len(second.IP) {
        return false
    }

    // 检查掩码长度
    firstMaskLen, _ := first.Mask.Size()
    secondMaskLen, _ := second.Mask.Size()
    if firstMaskLen > secondMaskLen {
        return false
    }

    // 检查IP地址在掩码范围内的匹配
    for i := 0; i < len(first.IP); i++ {
        if (first.IP[i]^second.IP[i])&first.Mask[i] != 0 {
            return false
        }
    }

    return true
}

原代码的bug会导致在某些情况下,当掩码字节不全为0时,循环过早结束,从而跳过必要的比较。修复后的代码明确检查掩码长度条件,并正确比较所有相关字节。

回到顶部