[z-applocal] Reduce nonexistent and non-PE files to warnings. (#1274)

This commit is contained in:
Billy O'Neal 2023-11-20 17:11:21 -08:00 коммит произвёл GitHub
Родитель 4c1df40a3c
Коммит a35ce804e1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 184 добавлений и 43 удалений

Просмотреть файл

@ -0,0 +1,3 @@
cd %~dp0
cl /c static-lib.cpp /Fostatic-lib.obj
lib static-lib.obj /out:static-lib.lib

Просмотреть файл

@ -0,0 +1 @@
int use_from_static_lib() { return 42; }

Просмотреть файл

@ -76,4 +76,40 @@ if ($IsWindows) {
Require-FileExists "$pluginsDir/k4a.dll"
Require-FileExists "$pluginsDir/depthengine_2_0.dll"
# Tests that nonexistent files are merely warnings
$nonexistentDll = Join-Path $basicDir 'nonexisting.dll'
Require-FileNotExists $nonexistentDll
$nonexistentOutput = Run-VcpkgAndCaptureOutput z-applocal `
--target-binary=$nonexistentDll `
--installed-bin-dir=$basicDir/installed/bin
Throw-IfNotFailed
if ($nonexistentOutput -match 'error:')
{
throw "Nonexistent emitted an error"
}
if ($nonexistentOutput -notmatch 'warning: no such file or directory')
{
throw "Nonexistent didn't emit expected warning"
}
# Tests that static libs emit a 'does not appear to be executable' warning
$staticLibDir = "$TestingRoot/applocal/static-lib"
Run-Vcpkg env "$staticLibDir/build.bat"
$staticLibFile = "$staticLibDir/static-lib.lib"
Require-FileExists $staticLibFile
$staticLibOutput = Run-VcpkgAndCaptureOutput z-applocal `
--target-binary=$staticLibFile `
--installed-bin-dir=$basicDir/installed/bin
Throw-IfNotFailed
if ($staticLibOutput -match 'error:')
{
throw "Static library emitted an error"
}
if ($staticLibOutput -notmatch 'warning: this file does not appear to be executable')
{
throw "Static library didn't emit expected warning"
}
}

Просмотреть файл

@ -1,9 +1,9 @@
#pragma once
#include <vcpkg/base/fwd/cofffilereader.h>
#include <vcpkg/base/fwd/expected.h>
#include <vcpkg/base/fwd/files.h>
#include <vcpkg/base/expected.h>
#include <vcpkg/base/fwd/optional.h>
#include <stdint.h>
@ -419,7 +419,8 @@ namespace vcpkg
};
std::vector<std::string> tokenize_command_line(StringView cmd_line);
ExpectedL<DllMetadata> try_read_dll_metadata(ReadFilePointer& f);
ExpectedL<Optional<DllMetadata>> try_read_dll_metadata(ReadFilePointer& f);
ExpectedL<DllMetadata> try_read_dll_metadata_required(ReadFilePointer& f);
ExpectedL<bool> try_read_if_dll_has_exports(const DllMetadata& dll, ReadFilePointer& f);
ExpectedL<std::vector<std::string>> try_read_dll_imported_dll_names(const DllMetadata& dll, ReadFilePointer& f);
ExpectedL<LibInformation> read_lib_information(ReadFilePointer& f);

Просмотреть файл

@ -81,6 +81,8 @@ namespace vcpkg
ExpectedL<Unit> try_seek_to(long long offset);
ExpectedL<Unit> try_seek_to(long long offset, int origin);
void close() noexcept;
~FilePointer();
};

Просмотреть файл

@ -158,7 +158,7 @@ DECLARE_MESSAGE(APackagePattern, (), "", "a package pattern")
DECLARE_MESSAGE(APackagePatternArray, (), "", "a package pattern array")
DECLARE_MESSAGE(APath, (), "", "a path")
DECLARE_MESSAGE(AppliedUserIntegration, (), "", "Applied user-wide integration for this vcpkg root.")
DECLARE_MESSAGE(ApplocalProcessing, (msg::path), "", "vcpkg applocal processing: {path}")
DECLARE_MESSAGE(ApplocalProcessing, (), "", "deploying dependencies")
DECLARE_MESSAGE(ARegistry, (), "", "a registry")
DECLARE_MESSAGE(ARegistryImplementationKind, (), "", "a registry implementation kind")
DECLARE_MESSAGE(ARegistryPath, (), "", "a registry path")
@ -1295,6 +1295,7 @@ DECLARE_MESSAGE(FailedVendorAuthentication,
"",
"One or more {vendor} credential providers failed to authenticate. See '{url}' for more details "
"on how to provide credentials.")
DECLARE_MESSAGE(FileIsNotExecutable, (), "", "this file does not appear to be executable")
DECLARE_MESSAGE(FilesContainAbsolutePath1,
(),
"This message is printed before a list of found absolute paths, followed by FilesContainAbsolutePath2, "
@ -2291,10 +2292,6 @@ DECLARE_MESSAGE(PERvaNotFound,
"{value:#X} is the Relative Virtual Address sought. Portable executable is a term-of-art, see "
"https://learn.microsoft.com/windows/win32/debug/pe-format",
"While parsing Portable Executable {path}, could not find RVA {value:#X}.")
DECLARE_MESSAGE(PESignatureMismatch,
(msg::path),
"Portable Executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format",
"While parsing Portable Executable {path}, signature mismatch.")
DECLARE_MESSAGE(PerformingPostBuildValidation, (), "", "-- Performing post-build validation")
DECLARE_MESSAGE(PortBugAllowRestrictedHeaders,
(msg::env_var),

Просмотреть файл

@ -140,8 +140,7 @@
"_AndroidHomeDirMissingProps.comment": "Note: 'source.properties' is code and should not be translated. An example of {env_var} is VCPKG_DEFAULT_TRIPLET. An example of {path} is /foo/bar.",
"AnotherInstallationInProgress": "Another installation is in progress on the machine, sleeping 6s before retrying.",
"AppliedUserIntegration": "Applied user-wide integration for this vcpkg root.",
"ApplocalProcessing": "vcpkg applocal processing: {path}",
"_ApplocalProcessing.comment": "An example of {path} is /foo/bar.",
"ApplocalProcessing": "deploying dependencies",
"ArtifactsBootstrapFailed": "vcpkg-artifacts is not installed and could not be bootstrapped.",
"ArtifactsNotInstalledReadonlyRoot": "vcpkg-artifacts is not installed, and it can't be installed because VCPKG_ROOT is assumed to be readonly. Reinstalling vcpkg using the 'one liner' may fix this problem.",
"ArtifactsNotOfficialWarning": "Using vcpkg-artifacts with an unofficial ",
@ -806,6 +805,7 @@
"_FetchingRegistryInfo.comment": "{value} is a reference An example of {url} is https://github.com/microsoft/vcpkg.",
"FieldKindDidNotHaveExpectedValue": "\"kind\" did not have an expected value: (expected one of: {expected}; found {actual})",
"_FieldKindDidNotHaveExpectedValue.comment": "{expected} is a list of literal kinds the user must type, separated by commas, {actual} is what the user supplied",
"FileIsNotExecutable": "this file does not appear to be executable",
"FileNotFound": "{path}: file not found",
"_FileNotFound.comment": "An example of {path} is /foo/bar.",
"FileReadFailed": "Failed to read {count} bytes from {path} at offset {byte_offset}.",
@ -1266,8 +1266,6 @@
"_PEPlusTagInvalid.comment": "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format An example of {path} is /foo/bar.",
"PERvaNotFound": "While parsing Portable Executable {path}, could not find RVA {value:#X}.",
"_PERvaNotFound.comment": "{value:#X} is the Relative Virtual Address sought. Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format An example of {path} is /foo/bar.",
"PESignatureMismatch": "While parsing Portable Executable {path}, signature mismatch.",
"_PESignatureMismatch.comment": "Portable Executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format An example of {path} is /foo/bar.",
"PackageAlreadyRemoved": "unable to remove {spec}: already removed",
"_PackageAlreadyRemoved.comment": "An example of {spec} is zlib:x64-windows.",
"PackageDiscoveryHeader": "Package Discovery",

Просмотреть файл

@ -22,11 +22,28 @@ namespace
static_assert(sizeof(SectionTableHeader) == 40,
"The SectionTableHeader struct must match its on-disk representation.");
ExpectedL<Unit> read_pe_signature_and_get_coff_header_offset(ReadFilePointer& f)
// reads f as a portable executable and checks for magic number signatures.
// if an I/O error occurs, returns the error; otherwise,
// returns iff signatures match
ExpectedL<bool> read_pe_signature_and_get_coff_header_offset(ReadFilePointer& f)
{
static constexpr StringLiteral EXPECTED_MZ_HEADER = "MZ";
{
char mz_signature[EXPECTED_MZ_HEADER.size()];
auto maybe_read_mz = f.try_read_all_from(0, mz_signature, sizeof(mz_signature));
if (!maybe_read_mz)
{
return std::move(maybe_read_mz).error();
}
if (EXPECTED_MZ_HEADER != StringView{mz_signature, sizeof(mz_signature)})
{
return false;
}
}
static constexpr long OFFSET_TO_PE_SIGNATURE_OFFSET = 0x3c;
static constexpr StringLiteral PE_SIGNATURE = "PE\0\0";
static constexpr auto PE_SIGNATURE_SIZE = static_cast<uint32_t>(PE_SIGNATURE.size());
static constexpr StringLiteral EXPECTED_PE_SIGNATURE = "PE\0\0";
uint32_t offset;
{
auto read_offset = f.try_read_all_from(OFFSET_TO_PE_SIGNATURE_OFFSET, &offset, sizeof(offset));
@ -36,21 +53,16 @@ namespace
}
}
char signature[PE_SIGNATURE_SIZE];
char pe_signature[EXPECTED_PE_SIGNATURE.size()];
{
auto read_signature = f.try_read_all_from(offset, signature, PE_SIGNATURE_SIZE);
auto read_signature = f.try_read_all_from(offset, pe_signature, sizeof(pe_signature));
if (!read_signature.has_value())
{
return std::move(read_signature).error();
}
}
if (PE_SIGNATURE != StringView{signature, PE_SIGNATURE_SIZE})
{
return msg::format(msgPESignatureMismatch, msg::path = f.path());
}
return Unit{};
return EXPECTED_PE_SIGNATURE == StringView{pe_signature, sizeof(pe_signature)};
}
ExpectedL<Unit> try_read_optional_header(DllMetadata& metadata, ReadFilePointer& f)
@ -639,20 +651,28 @@ namespace vcpkg
return result;
}
ExpectedL<DllMetadata> try_read_dll_metadata(ReadFilePointer& f)
ExpectedL<Optional<DllMetadata>> try_read_dll_metadata(ReadFilePointer& f)
{
Optional<DllMetadata> result;
{
auto signature = read_pe_signature_and_get_coff_header_offset(f);
if (!signature.has_value())
auto maybe_signature_ok = read_pe_signature_and_get_coff_header_offset(f);
if (auto signature_ok = maybe_signature_ok.get())
{
return std::move(signature).error();
if (!*signature_ok)
{
return nullopt;
}
}
else
{
return std::move(maybe_signature_ok).error();
}
}
DllMetadata result{};
DllMetadata& target = result.emplace();
{
auto read_coff = f.try_read_all(&result.coff_header, sizeof(result.coff_header));
auto read_coff = f.try_read_all(&target.coff_header, sizeof(target.coff_header));
if (!read_coff.has_value())
{
return std::move(read_coff).error();
@ -660,7 +680,7 @@ namespace vcpkg
}
{
auto read_optional_header = try_read_optional_header(result, f);
auto read_optional_header = try_read_optional_header(target, f);
if (!read_optional_header.has_value())
{
return std::move(read_optional_header).error();
@ -668,7 +688,7 @@ namespace vcpkg
}
{
auto read_section_headers = try_read_section_headers(result, f);
auto read_section_headers = try_read_section_headers(target, f);
if (!read_section_headers)
{
return std::move(read_section_headers).error();
@ -676,7 +696,7 @@ namespace vcpkg
}
{
auto read_load_config_directory = try_read_image_config_directory(result, f);
auto read_load_config_directory = try_read_image_config_directory(target, f);
if (!read_load_config_directory)
{
return std::move(read_load_config_directory).error();
@ -686,6 +706,21 @@ namespace vcpkg
return result;
}
ExpectedL<DllMetadata> try_read_dll_metadata_required(ReadFilePointer& f)
{
return try_read_dll_metadata(f).then([&](Optional<DllMetadata>&& maybe_metadata) -> ExpectedL<DllMetadata> {
if (auto metadata = maybe_metadata.get())
{
return std::move(*metadata);
}
return LocalizedString::from_raw(f.path())
.append_raw(": ")
.append_raw(ErrorPrefix)
.append(msgFileIsNotExecutable);
});
}
ExpectedL<bool> try_read_if_dll_has_exports(const DllMetadata& dll, ReadFilePointer& f)
{
const auto export_data_directory = dll.try_get_image_data_directory(0);

Просмотреть файл

@ -1381,14 +1381,17 @@ namespace vcpkg
return Unit{};
}
FilePointer::~FilePointer()
void FilePointer::close() noexcept
{
if (m_fs)
{
Checks::check_exit(VCPKG_LINE_INFO, ::fclose(m_fs) == 0);
m_fs = 0;
}
}
FilePointer::~FilePointer() { close(); }
ReadFilePointer::ReadFilePointer() noexcept = default;
ReadFilePointer::ReadFilePointer(ReadFilePointer&&) noexcept = default;

Просмотреть файл

@ -12,6 +12,7 @@
#include <map>
#include <set>
#include <string>
#include <system_error>
using namespace vcpkg;
@ -104,11 +105,22 @@ namespace
void resolve(const Path& binary)
{
msg::println(msgApplocalProcessing, msg::path = binary);
msg::print(LocalizedString::from_raw(binary)
.append_raw(": ")
.append_raw(MessagePrefix)
.append(msgApplocalProcessing)
.append_raw('\n'));
auto dll_file = m_fs.open_for_read(binary, VCPKG_LINE_INFO);
const auto dll_metadata = vcpkg::try_read_dll_metadata(dll_file).value_or_exit(VCPKG_LINE_INFO);
const auto dll_metadata = vcpkg::try_read_dll_metadata_required(dll_file).value_or_exit(VCPKG_LINE_INFO);
const auto imported_names =
vcpkg::try_read_dll_imported_dll_names(dll_metadata, dll_file).value_or_exit(VCPKG_LINE_INFO);
dll_file.close();
resolve_explicit(binary, imported_names);
}
void resolve_explicit(const Path& binary, const std::vector<std::string>& imported_names)
{
Debug::print("Imported DLLs of ", binary, " were ", Strings::join("\n", imported_names), "\n");
for (auto&& imported_name : imported_names)
@ -569,7 +581,7 @@ namespace vcpkg
nullptr,
};
void command_z_applocal_and_exit(const VcpkgCmdArguments& args, const Filesystem&)
void command_z_applocal_and_exit(const VcpkgCmdArguments& args, const Filesystem& fs)
{
auto parsed = args.parse_arguments(CommandZApplocalMetadata);
const auto target_binary = parsed.settings.find(OPTION_TARGET_BINARY);
@ -585,17 +597,70 @@ namespace vcpkg
}
const auto target_installed_bin_dir =
real_filesystem.almost_canonical(target_installed_bin_setting->second, VCPKG_LINE_INFO);
const auto target_binary_path = real_filesystem.almost_canonical(target_binary->second, VCPKG_LINE_INFO);
fs.almost_canonical(target_installed_bin_setting->second, VCPKG_LINE_INFO);
const auto decoded = decode_from_canonical_bin_dir(target_installed_bin_dir);
AppLocalInvocation invocation(real_filesystem,
// the first binary is special in that it might not be a DLL or might not exist
const Path target_binary_path = target_binary->second;
msg::print(LocalizedString::from_raw(target_binary_path)
.append_raw(": ")
.append_raw(MessagePrefix)
.append(msgApplocalProcessing)
.append_raw('\n'));
std::error_code ec;
auto dll_file = fs.open_for_read(target_binary_path, ec);
if (ec)
{
auto io_error = ec.message();
if (ec == std::errc::no_such_file_or_directory)
{
msg::print(Color::warning,
LocalizedString::from_raw(target_binary_path)
.append_raw(": ")
.append_raw(WarningPrefix)
.append_raw(io_error)
.append_raw('\n'));
}
else
{
msg::print(Color::error,
LocalizedString::from_raw(target_binary_path)
.append_raw(": ")
.append_raw(ErrorPrefix)
.append_raw(io_error)
.append_raw('\n'));
}
Checks::exit_fail(VCPKG_LINE_INFO);
}
auto maybe_dll_metadata = vcpkg::try_read_dll_metadata(dll_file).value_or_exit(VCPKG_LINE_INFO);
auto dll_metadata = maybe_dll_metadata.get();
if (!dll_metadata)
{
msg::print(Color::warning,
LocalizedString::from_raw(target_binary_path)
.append_raw(": ")
.append_raw(WarningPrefix)
.append(msgFileIsNotExecutable)
.append_raw('\n'));
Checks::exit_fail(VCPKG_LINE_INFO);
}
const auto imported_names =
vcpkg::try_read_dll_imported_dll_names(*dll_metadata, dll_file).value_or_exit(VCPKG_LINE_INFO);
dll_file.close();
AppLocalInvocation invocation(fs,
target_binary_path.parent_path(),
target_installed_bin_dir,
decoded.installed_root,
decoded.is_debug,
maybe_create_log(parsed.settings, OPTION_TLOG_FILE, real_filesystem),
maybe_create_log(parsed.settings, OPTION_COPIED_FILES_LOG, real_filesystem));
invocation.resolve(target_binary_path);
maybe_create_log(parsed.settings, OPTION_TLOG_FILE, fs),
maybe_create_log(parsed.settings, OPTION_COPIED_FILES_LOG, fs));
invocation.resolve_explicit(target_binary_path, imported_names);
Checks::exit_success(VCPKG_LINE_INFO);
}
} // namespace vcpkg

Просмотреть файл

@ -445,7 +445,7 @@ namespace vcpkg
return std::move(maybe_file).error();
}
auto maybe_metadata = try_read_dll_metadata(*file);
auto maybe_metadata = try_read_dll_metadata_required(*file);
auto metadata = maybe_metadata.get();
if (!metadata)
{