QFileSystemEngine::canonicalName (Unix): clean up control-flow
When passing a nullptr to realpath, it will allocate memory. That memory has to be freed (with free) later to avoid a leak, which we so far didn't. This patch ensures that we always clean up the memory by using a unique_ptr. As a drive-by, clean up the control-flow: - Always pass either the stack buffer or nullptr to realpath. - Rely on realpath returning nullptr in the error case. Lastly, fix a few coding-style issues. Change-Id: Ia906df77324020c267b087ec52a9a6c47aaa2a59 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
e1b76e68d0
commit
06e45cbd6a
@ -58,6 +58,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <memory> // for std::unique_ptr
|
||||||
|
|
||||||
#if __has_include(<paths.h>)
|
#if __has_include(<paths.h>)
|
||||||
# include <paths.h>
|
# include <paths.h>
|
||||||
#endif
|
#endif
|
||||||
@ -687,39 +689,40 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
|
|||||||
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
|
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
|
||||||
#else
|
#else
|
||||||
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || _POSIX_VERSION < 200801L
|
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || _POSIX_VERSION < 200801L
|
||||||
char stack_result[PATH_MAX+1];
|
// used to store the result of realpath in case where realpath cannot allocate itself
|
||||||
|
char stack_result[PATH_MAX + 1];
|
||||||
|
#else
|
||||||
|
// enables unconditionally passing stack_result below
|
||||||
|
std::nullptr_t stack_result = nullptr;
|
||||||
# endif
|
# endif
|
||||||
char *resolved_name = nullptr;
|
auto resolved_path_deleter = [&](char *ptr) {
|
||||||
|
// frees resolved_name if it was allocated by realpath
|
||||||
|
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || _POSIX_VERSION < 200801L
|
||||||
|
// ptr is either null, or points to stack_result
|
||||||
|
Q_ASSERT(!ptr || ptr == stack_result);
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
free(ptr);
|
||||||
|
# endif
|
||||||
|
};
|
||||||
|
std::unique_ptr<char, decltype (resolved_path_deleter)> resolved_name {nullptr, resolved_path_deleter};
|
||||||
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID)
|
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID)
|
||||||
// On some Android and macOS versions, realpath() will return a path even if
|
// On some Android and macOS versions, realpath() will return a path even if
|
||||||
// it does not exist. To work around this, we check existence in advance.
|
// it does not exist. To work around this, we check existence in advance.
|
||||||
if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute))
|
if (!data.hasFlags(QFileSystemMetaData::ExistsAttribute))
|
||||||
fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
|
fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
|
||||||
|
|
||||||
if (!data.exists()) {
|
if (!data.exists())
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
} else {
|
else
|
||||||
resolved_name = stack_result;
|
resolved_name.reset(realpath(entry.nativeFilePath().constData(), stack_result));
|
||||||
}
|
|
||||||
if (resolved_name && realpath(entry.nativeFilePath().constData(), resolved_name) == nullptr)
|
|
||||||
resolved_name = nullptr;
|
|
||||||
# else
|
# else
|
||||||
# if _POSIX_VERSION >= 200801L // ask realpath to allocate memory
|
resolved_name.reset(realpath(entry.nativeFilePath().constData(), stack_result));
|
||||||
resolved_name = realpath(entry.nativeFilePath().constData(), nullptr);
|
|
||||||
# else
|
|
||||||
resolved_name = stack_result;
|
|
||||||
if (realpath(entry.nativeFilePath().constData(), resolved_name) == nullptr)
|
|
||||||
resolved_name = nullptr;
|
|
||||||
# endif
|
|
||||||
# endif
|
# endif
|
||||||
if (resolved_name) {
|
if (resolved_name) {
|
||||||
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
||||||
data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
|
data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
|
||||||
QString canonicalPath = QDir::cleanPath(QFile::decodeName(resolved_name));
|
QString canonicalPath = QDir::cleanPath(QFile::decodeName(resolved_name.get()));
|
||||||
# if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || _POSIX_VERSION < 200801L
|
|
||||||
if (resolved_name != stack_result)
|
|
||||||
free(resolved_name);
|
|
||||||
# endif
|
|
||||||
return QFileSystemEntry(canonicalPath);
|
return QFileSystemEntry(canonicalPath);
|
||||||
} else if (errno == ENOENT || errno == ENOTDIR) { // file doesn't exist
|
} else if (errno == ENOENT || errno == ENOTDIR) { // file doesn't exist
|
||||||
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user