Skip to content

Fix broadcast() corrupting upper 64 bits for IPv4 addresses#30

Open
rustyconover wants to merge 3 commits into
duckdb:mainfrom
rustyconover:fix/ipv4-broadcast-upper-bits
Open

Fix broadcast() corrupting upper 64 bits for IPv4 addresses#30
rustyconover wants to merge 3 commits into
duckdb:mainfrom
rustyconover:fix/ipv4-broadcast-upper-bits

Conversation

@rustyconover
Copy link
Copy Markdown

Summary

  • The Broadcast() method uses ~Netmask().address (bitwise NOT on 128-bit uhugeint_t) to compute the host mask. For IPv4, the netmask has upper=0, so ~0 sets the upper 64 bits to 0xFFFFFFFFFFFFFFFF. This garbage propagates into the broadcast result.
  • Observable effects:
    • broadcast('192.168.1.0/24') = '192.168.1.255/24'false (should be true)
    • broadcast('192.168.1.0/24') > '0.0.0.1'false (should be true)
    • broadcast('10.0.0.0/24') + 1 → throws spurious overflow error
    • Raw stored address is negative instead of the correct positive value
  • The VARCHAR display happened to be correct since ToStringIPv4 only reads the lower 32 bits, masking the bug from casual observation.
  • Fix: compute the host mask as full_mask ^ netmask instead of ~netmask, where full_mask is the address-space mask (0xFFFFFFFF for IPv4, all-ones for IPv6). For IPv6 this is equivalent since all_ones ^ x == ~x.

Reproduction

LOAD inet;

-- Equality is broken
SELECT broadcast(INET '192.168.1.5/24') = INET '192.168.1.255/24';
-- Expected: true
-- Actual:   false

-- Ordering is broken
SELECT broadcast(INET '192.168.1.5/24') > INET '0.0.0.1';
-- Expected: true
-- Actual:   false

-- Raw address shows the corruption
SELECT broadcast('192.168.1.0/24'::INET)::STRUCT(ip_type UTINYINT, address HUGEINT, mask USMALLINT);
-- Shows address = -1062731265 (should be 3232236031)

Test plan

  • Added IPv4 broadcast equality test: broadcast(... /24) = '192.168.1.255/24'
  • Added IPv4 broadcast ordering test: broadcast(... /24) > '0.0.0.1'
  • Added IPv4 broadcast /0 test
  • Added IPv6 broadcast equality test (regression check)
  • Existing broadcast display tests still pass

🤖 Generated with Claude Code

samansmink and others added 3 commits October 28, 2025 11:16
…764349a126f53de0728c9f

Apply patches from duckdb/duckdb
The bitwise NOT `~netmask` in Broadcast() flips all 128 bits of the
uhugeint_t. For IPv4, the netmask has upper=0 and lower=netmask_value,
so `~` sets upper to 0xFFFFFFFFFFFFFFFF. This corrupts the broadcast
result, breaking equality comparisons, ordering, and arithmetic.

Fix: compute the host mask as `full_mask ^ netmask` where full_mask is
the address-space mask (0xFFFFFFFF for IPv4, all-ones for IPv6). This
keeps the inversion within the correct address space. For IPv6 the
behavior is unchanged since all_ones ^ x == ~x.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

2 participants