aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-10-01 22:05:51 +0200
committerMax Kellermann <max@duempel.org>2014-10-01 23:03:31 +0200
commitedd003b62af802fae7828336628adb0ea3f6bd21 (patch)
treea8abc4b09e2dd84722f9ce682441c4a4a738f8da
parent10cc87e422e09f437f86f56074dc2e018ed75bf1 (diff)
downloadmpd-edd003b62af802fae7828336628adb0ea3f6bd21.tar.gz
mpd-edd003b62af802fae7828336628adb0ea3f6bd21.tar.xz
mpd-edd003b62af802fae7828336628adb0ea3f6bd21.zip
lib/nfs/Connection: fix memory leak when cancelling Open()
Close the newly allocated file handle passed to the callback.
-rw-r--r--src/lib/nfs/Connection.cxx14
-rw-r--r--src/lib/nfs/Connection.hxx14
2 files changed, 23 insertions, 5 deletions
diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx
index 89ef24312..853cacc9a 100644
--- a/src/lib/nfs/Connection.cxx
+++ b/src/lib/nfs/Connection.cxx
@@ -94,6 +94,14 @@ NfsConnection::CancellableCallback::Callback(int err, void *data)
cb.OnNfsError(Error(nfs_domain, err,
(const char *)data));
} else {
+ if (open) {
+ /* a nfs_open_async() call was cancelled - to
+ avoid a memory leak, close the newly
+ allocated file handle immediately */
+ struct nfsfh *fh = (struct nfsfh *)data;
+ connection.Close(fh);
+ }
+
connection.callbacks.Remove(*this);
}
}
@@ -157,7 +165,7 @@ NfsConnection::Open(const char *path, int flags, NfsCallback &callback,
{
assert(!callbacks.Contains(callback));
- auto &c = callbacks.Add(callback, *this);
+ auto &c = callbacks.Add(callback, *this, true);
if (!c.Open(context, path, flags, error)) {
callbacks.Remove(c);
return false;
@@ -172,7 +180,7 @@ NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback, Error &error)
{
assert(!callbacks.Contains(callback));
- auto &c = callbacks.Add(callback, *this);
+ auto &c = callbacks.Add(callback, *this, false);
if (!c.Stat(context, fh, error)) {
callbacks.Remove(c);
return false;
@@ -188,7 +196,7 @@ NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size,
{
assert(!callbacks.Contains(callback));
- auto &c = callbacks.Add(callback, *this);
+ auto &c = callbacks.Add(callback, *this, false);
if (!c.Read(context, fh, offset, size, error)) {
callbacks.Remove(c);
return false;
diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx
index f6e5d2949..880b7d467 100644
--- a/src/lib/nfs/Connection.hxx
+++ b/src/lib/nfs/Connection.hxx
@@ -39,11 +39,21 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
class CancellableCallback : public CancellablePointer<NfsCallback> {
NfsConnection &connection;
+ /**
+ * Is this a nfs_open_async() operation? If yes, then
+ * we need to call nfs_close_async() on the new file
+ * handle as soon as the callback is invoked
+ * successfully.
+ */
+ const bool open;
+
public:
explicit CancellableCallback(NfsCallback &_callback,
- NfsConnection &_connection)
+ NfsConnection &_connection,
+ bool _open)
:CancellablePointer<NfsCallback>(_callback),
- connection(_connection) {}
+ connection(_connection),
+ open(_open) {}
bool Open(nfs_context *context, const char *path, int flags,
Error &error);