Skip to content

Fix IPv4 byte order handling - #567

Closed
FranciscoMaxwell wants to merge 1 commit into
ClickHouse:masterfrom
FranciscoMaxwell:fix-ipv4-byte-order
Closed

FranciscoMaxwell wants to merge 1 commit into
ClickHouse:masterfrom
FranciscoMaxwell:fix-ipv4-byte-order

Conversation

@FranciscoMaxwell

Copy link
Copy Markdown

Fixes #521.

Summary

This fixes inconsistent byte-order handling in ColumnIPv4:

  • Append(std::string) now stores the network-order value returned by inet_pton without applying a second byte swap.
  • Append(in_addr) now stores in_addr::s_addr as-is, matching the platform/network-order representation used by socket APIs.
  • At() and operator[] now return the stored network-order representation directly.
  • Append(uint32_t) and the vector constructor continue to accept host-order integer values.
  • Adds coverage proving string, host-order integer, and in_addr appends serialize to the same bytes.

Testing

  • cmake -S . -B build -DBUILD_TESTS=ON
  • cmake --build build --target clickhouse-cpp-ut --config Debug --parallel 4
  • .\build\ut\Debug\clickhouse-cpp-ut.exe --gtest_filter="ColumnsCase.ColumnIPv4*"
  • git diff --check

@CLAassistant

CLAassistant commented Sep 24, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@slabko

slabko commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

@FranciscoMaxwell

ClickHouse toString function can be used to check if the value you have inserted is correct. The following code automates this process:

struct sockaddr_in sa{};
char str[INET_ADDRSTRLEN]{};
if (inet_pton(AF_INET, "142.251.142.206", &sa.sin_addr) != 1) {
    (void)fprintf(stderr, "failed to convert ip address\n");
    return 1;
}

uint32_t ip = 0x8EFB8ECE;

// check that this is correct ip in host byte order
uint32_t ip_check = 0;
memcpy(&ip_check, &sa.sin_addr, sizeof(ip_check));
assert(ip == ntohl(ip_check)); // `si_addr` is in network byte order

client.Execute("DROP TABLE IF EXISTS addresses");
client.Execute("CREATE TABLE addresses (desc String, addr IPv4) ENGINE = MergeTree ORDER BY desc");

ch::Block block = client.BeginInsert("INSERT INTO addresses VALUES");

auto col_desc = block[0]->AsStrict<ch::ColumnString>();
auto col_addr = block[1]->AsStrict<ch::ColumnIPv4>();

col_desc->Append("142.251.142.206 using Append(const std::string&)");
col_addr->Append("142.251.142.206");

col_desc->Append("142.251.142.206 using Append(in_addr)");
col_addr->Append(sa.sin_addr);

col_desc->Append("142.251.142.206 using Append(uint32_t)");
col_addr->Append(ip);

block.RefreshRowCount();

client.SendInsertBlock(block);
client.EndInsert();


client.BeginSelect("SELECT desc, toString(addr) FROM addresses");
while (auto block = client.NextBlock()) {
    for (size_t i = 0; i < block->GetRowCount(); ++i) {
        auto col_desc = block->At(0)->AsStrict<ch::ColumnString>();
        auto col_addr = block->At(1)->AsStrict<ch::ColumnString>();
        std::cout << col_desc->At(i) << ": " << col_addr->At(i) << "\n";
    }
}

The implementation in master prints the following when running this code:

142.251.142.206 using Append(const std::string&): 142.251.142.206
142.251.142.206 using Append(in_addr): 142.251.142.206
142.251.142.206 using Append(uint32_t): 206.142.251.142

It shows that Append(uint32_t) is clearly broken in master

After applying your fix it prints

142.251.142.206 using Append(const std::string&): 206.142.251.142
142.251.142.206 using Append(in_addr): 206.142.251.142
142.251.142.206 using Append(uint32_t): 206.142.251.142

Showing that all Append functions are now broken.

@slabko slabko closed this Sep 28, 2026
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.

Incorrect byte order conversion in ColumnIPv4::Append() overloads

3 participants