diff --git a/cpp/src/parquet/encryption/external/test_utils.cc b/cpp/src/parquet/encryption/external/test_utils.cc index 9638a2607f3..e2b2c439155 100644 --- a/cpp/src/parquet/encryption/external/test_utils.cc +++ b/cpp/src/parquet/encryption/external/test_utils.cc @@ -61,18 +61,86 @@ std::string TestUtils::GetTestLibraryPath() { const char* cwd_override = std::getenv("PARQUET_TEST_LIBRARY_CWD"); std::string base_path; + const std::string exec_dir = GetExecutableDirectory(); if (cwd_override && cwd_override[0]) { base_path = std::string(cwd_override); } else { // Get the directory where the executable is located - base_path = GetExecutableDirectory(); + base_path = exec_dir; } std::vector possible_filenames = { - "libDBPATestAgent.so", "libDBPATestAgent.dylib", "DBPATestAgent.dll"}; +#if defined(__linux__) + "libDBPATestAgent.so" +#elif defined(__APPLE__) + "libDBPATestAgent.dylib" +#elif defined(_WIN32) + // Windows (MSVC): no "lib" prefix for DLLs + "DBPATestAgent.dll", + // Windows (MinGW): typically uses "lib" prefix even for DLLs + "libDBPATestAgent.dll", + + // Some toolchains use a debug postfix (commonly "d") + "DBPATestAgentd.dll", + "libDBPATestAgentd.dll" +#endif + }; + + std::vector possible_directories = {exec_dir + "/", base_path + "/", "./", + ""}; + + // Arrow's CMake places most runtime artifacts under: + // /cpp// + // and CI often runs `ctest` from /cpp. On Windows in particular, this + // means the shared library can sit under "./debug/" (or "./release/") even + // when the test executable isn't. + const std::string cwd = std::filesystem::current_path().string(); + const std::filesystem::path cwd_path = std::filesystem::current_path(); + const std::filesystem::path exec_dir_path = std::filesystem::path(exec_dir); + const std::string exec_parent = exec_dir_path.parent_path().string(); + + // Common CMake build-type directory spellings (Arrow CI frequently uses "debug"). + const std::vector build_type_dirs = { + "debug", "Debug", "release", "Release", + "relwithdebinfo", "RelWithDebInfo", "minsizerel", "MinSizeRel"}; + + auto add_build_type_dirs = [&](const std::filesystem::path& root) { + if (root.empty()) { + return; + } + const std::string root_s = root.string(); + for (const auto& cfg : build_type_dirs) { + possible_directories.push_back(root_s + "/" + cfg + "/"); + } + }; - std::vector possible_directories = {GetExecutableDirectory() + "/", - base_path + "/", "./", ""}; + // Search build-type dirs under CWD and a few parents (handles ctest running + // from build/cpp/src/* while outputs are in build/cpp//). + { + std::filesystem::path p = cwd_path; + for (int i = 0; i < 5 && !p.empty(); ++i) { + add_build_type_dirs(p); + p = p.parent_path(); + } + } + + // Also handle the common "build root" case where CWD is (not /cpp). + for (const auto& cfg : build_type_dirs) { + possible_directories.push_back(cwd + "/cpp/" + cfg + "/"); + } + + // Finally, search under the executable's parent and its parents. + { + std::filesystem::path p = exec_dir_path.parent_path(); + for (int i = 0; i < 5 && !p.empty(); ++i) { + add_build_type_dirs(p); + p = p.parent_path(); + } + } + + if (!exec_parent.empty()) { + possible_directories.push_back(exec_parent + "/"); + } for (const auto& filename : possible_filenames) { for (const auto& directory : possible_directories) { @@ -83,7 +151,7 @@ std::string TestUtils::GetTestLibraryPath() { } } - throw std::runtime_error("Could not find library"); + throw std::runtime_error("test_utils.cc: Could not find DBPATestAgent library "); } } // namespace parquet::encryption::external::test diff --git a/cpp/src/parquet/encryption/properties_test.cc b/cpp/src/parquet/encryption/properties_test.cc index 7bf8d065e54..54971abdcdb 100644 --- a/cpp/src/parquet/encryption/properties_test.cc +++ b/cpp/src/parquet/encryption/properties_test.cc @@ -250,6 +250,27 @@ TEST(TestEncryptionProperties, UseAES_GCM_CTR_V1Algorithm) { ASSERT_EQ(ParquetCipher::AES_GCM_CTR_V1, props->algorithm().algorithm); } +// Verify AadMetadata is safe to value-initialize (all fields deterministic). +// Regression guard: an uninitialized bool in supply_aad_prefix caused thrift +// serialization failures on Windows (MSVC debug fills with 0xCC). +TEST(TestEncryptionProperties, AadMetadataDefaultInitialization) { + AadMetadata aad{}; + ASSERT_EQ("", aad.aad_prefix); + ASSERT_EQ("", aad.aad_file_unique); + ASSERT_EQ(false, aad.supply_aad_prefix); +} + +// Verify EncryptionAlgorithm is safe to value-initialize — particularly the +// nested AadMetadata::supply_aad_prefix bool that previously lacked a default +// member initializer. +TEST(TestEncryptionProperties, EncryptionAlgorithmDefaultInitialization) { + EncryptionAlgorithm algo{}; + ASSERT_EQ(ParquetCipher::AES_GCM_V1, algo.algorithm); + ASSERT_EQ("", algo.aad.aad_prefix); + ASSERT_EQ("", algo.aad.aad_file_unique); + ASSERT_EQ(false, algo.aad.supply_aad_prefix); +} + TEST(TestExternalFileEncryptionProperties, SuperClassFieldsSetCorrectly) { std::string column_name_1 = "column_1"; ColumnEncryptionProperties::Builder column_builder_1(column_name_1); diff --git a/cpp/src/parquet/metadata.cc b/cpp/src/parquet/metadata.cc index 70c785b7359..cecfc515dd4 100644 --- a/cpp/src/parquet/metadata.cc +++ b/cpp/src/parquet/metadata.cc @@ -1753,7 +1753,7 @@ class ColumnChunkMetaDataBuilder::ColumnChunkMetaDataBuilderImpl { eck.__set_path_in_schema(column_->path()->ToDotVector()); // check if column has its own encryption algorithm if (encrypt_md->parquet_cipher().has_value()) { - EncryptionAlgorithm column_encryption_algorithm; + EncryptionAlgorithm column_encryption_algorithm{}; column_encryption_algorithm.algorithm = encrypt_md->parquet_cipher().value(); eck.__set_encryption_algorithm(ToThrift(column_encryption_algorithm)); } diff --git a/cpp/src/parquet/types.h b/cpp/src/parquet/types.h index f3b1b5d7f89..c71a06fc076 100644 --- a/cpp/src/parquet/types.h +++ b/cpp/src/parquet/types.h @@ -580,7 +580,7 @@ bool IsParquetCipherSupported(ParquetCipher::type cipher); struct AadMetadata { std::string aad_prefix; std::string aad_file_unique; - bool supply_aad_prefix; + bool supply_aad_prefix = false; }; struct EncryptionAlgorithm {