diff --git a/src/iceberg/table_metadata.cc b/src/iceberg/table_metadata.cc index 94a154501..0763c4fe6 100644 --- a/src/iceberg/table_metadata.cc +++ b/src/iceberg/table_metadata.cc @@ -517,11 +517,18 @@ int32_t TableMetadataUtil::ParseVersionFromLocation(std::string_view metadata_lo size_t version_start = metadata_location.find_last_of('/') + 1; size_t version_end = metadata_location.find('-', version_start); + if (version_end == std::string::npos) { + return -1; + } + int32_t version = -1; - if (version_end != std::string::npos) { - std::from_chars(metadata_location.data() + version_start, - metadata_location.data() + version_end, version); + const auto* version_begin = metadata_location.data() + version_start; + const auto* version_limit = metadata_location.data() + version_end; + const auto [ptr, ec] = std::from_chars(version_begin, version_limit, version); + if (ec != std::errc{} || ptr != version_limit) { + return -1; } + return version; } diff --git a/src/iceberg/test/metadata_io_test.cc b/src/iceberg/test/metadata_io_test.cc index c780dc18c..03d9b0e1a 100644 --- a/src/iceberg/test/metadata_io_test.cc +++ b/src/iceberg/test/metadata_io_test.cc @@ -150,6 +150,21 @@ TEST_F(MetadataIOTest, WriteMetadataWithBase) { EXPECT_THAT(new_metadata_location, testing::HasSubstr("/metadata/00000-")); } + { + // Reject malformed and out-of-range version segments. + for (const auto& base_metadata_location : { + "/metadata/00010x-xxx.metadata.json", + "/metadata/2147483648-xxx.metadata.json", + "/metadata/-xxx.metadata.json", + }) { + TableMetadata new_metadata = PrepareMetadata(); + ICEBERG_UNWRAP_OR_FAIL( + auto new_metadata_location, + TableMetadataUtil::Write(*io_, &base, base_metadata_location, new_metadata)); + EXPECT_THAT(new_metadata_location, testing::HasSubstr("/metadata/00000-")); + } + } + // Reset base metadata_file_location // base.metadata_file_location = temp_filepath_;