SYNERGY1-1497 Memory leaks in copy/paste and drag and drop functionality (#7175)

* SYNERGY1-1497 Fix memory leak in copy/paste functionality

* SYNERGY1-1497 Memory leaks with function CFStringRefToUTF8String

* SYNERGY1-1497 Fix memory leak in Server::sendDragInfo

* SYNERGY1-1497 Fix memory leak in Server::sendFileToClient

* SYNERGY1-1497 Fix memory leak in Server::sendDragInfoThread

* SYNERGY1-1497 Fix code smells

* SYNERGY1-1497 Fix builds

* SYNERGY1-1497 Fix additional code smells
This commit is contained in:
Serhii Hadzhilov 2022-05-19 18:29:11 +03:00 committed by GitHub
parent d3ab180df6
commit 95ee948f26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 95 additions and 81 deletions

View file

@ -10,6 +10,7 @@ Bug fixes:
- #7149 Address issues with modifiers and dead keys - #7149 Address issues with modifiers and dead keys
- #7163 Fix compilation issues for FreeBSD - #7163 Fix compilation issues for FreeBSD
- #7172 Memory leaks in language sync and TLS functionality - #7172 Memory leaks in language sync and TLS functionality
- #7175 Memory leaks in copy/paste and drag and drop functionality
Github Actions: Github Actions:
- #7148 Fix unstable build for windows core - #7148 Fix unstable build for windows core

View file

@ -43,6 +43,16 @@ Event::Event(Type type, void* target, void* data, Flags flags) :
// do nothing // do nothing
} }
Event::Event(Type type, void* target, EventData* dataObject) :
m_type(type),
m_target(target),
m_data(nullptr),
m_flags(kNone),
m_dataObject(dataObject)
{
}
Event::Type Event::Type
Event::getType() const Event::getType() const
{ {

View file

@ -56,13 +56,21 @@ public:
The \p data must be POD (plain old data) allocated by malloc(), The \p data must be POD (plain old data) allocated by malloc(),
which means it cannot have a constructor, destructor or be which means it cannot have a constructor, destructor or be
composed of any types that do. For non-POD (normal C++ objects composed of any types that do. For non-POD (normal C++ objects
use \c setDataObject(). use \c setDataObject() or use appropriate constructor.
\p target is the intended recipient of the event. \p target is the intended recipient of the event.
\p flags is any combination of \c Flags. \p flags is any combination of \c Flags.
*/ */
Event(Type type, void* target = NULL, void* data = NULL, Event(Type type, void* target = NULL, void* data = NULL,
Flags flags = kNone); Flags flags = kNone);
//! Create \c Event with non-POD data
/*!
\p type of the event
\p target is the intended recipient of the event.
\p dataObject with event data
*/
Event(Type type, void* target, EventData* dataObject);
//! @name manipulators //! @name manipulators
//@{ //@{

View file

@ -72,8 +72,8 @@ Client::Client(
m_suspended(false), m_suspended(false),
m_connectOnResume(false), m_connectOnResume(false),
m_events(events), m_events(events),
m_sendFileThread(NULL), m_sendFileThread(nullptr),
m_writeToDropDirThread(NULL), m_writeToDropDirThread(nullptr),
m_socket(NULL), m_socket(NULL),
m_useSecureNetwork(args.m_enableCrypto), m_useSecureNetwork(args.m_enableCrypto),
m_args(args), m_args(args),
@ -258,9 +258,9 @@ Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
m_screen->mouseMove(xAbs, yAbs); m_screen->mouseMove(xAbs, yAbs);
m_screen->enter(mask); m_screen->enter(mask);
if (m_sendFileThread != NULL) { if (m_sendFileThread) {
StreamChunker::interruptFile(); StreamChunker::interruptFile();
m_sendFileThread = NULL; m_sendFileThread.reset(nullptr);
} }
} }
@ -827,9 +827,8 @@ void
Client::onFileRecieveCompleted() Client::onFileRecieveCompleted()
{ {
if (isReceivedFileSizeValid()) { if (isReceivedFileSizeValid()) {
m_writeToDropDirThread = new Thread( auto method = new TMethodJob<Client>(this, &Client::writeToDropDirThread);
new TMethodJob<Client>( m_writeToDropDirThread.reset(new Thread(method));
this, &Client::writeToDropDirThread));
} }
} }
@ -875,14 +874,13 @@ Client::isReceivedFileSizeValid()
void void
Client::sendFileToServer(const char* filename) Client::sendFileToServer(const char* filename)
{ {
if (m_sendFileThread != NULL) { if (m_sendFileThread) {
StreamChunker::interruptFile(); StreamChunker::interruptFile();
} }
m_sendFileThread = new Thread( auto data = static_cast<void*>(const_cast<char*>(filename));
new TMethodJob<Client>( auto method = new TMethodJob<Client>(this, &Client::sendFileThread, data);
this, &Client::sendFileThread, m_sendFileThread.reset(new Thread(method));
static_cast<void*>(const_cast<char*>(filename))));
} }
void void
@ -896,7 +894,7 @@ Client::sendFileThread(void* filename)
LOG((CLOG_ERR "failed sending file chunks: %s", error.what())); LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
} }
m_sendFileThread = NULL; m_sendFileThread.reset(nullptr);
} }
void void

View file

@ -27,6 +27,7 @@
#include "net/NetworkAddress.h" #include "net/NetworkAddress.h"
#include "base/EventTypes.h" #include "base/EventTypes.h"
#include "mt/CondVar.h" #include "mt/CondVar.h"
#include <memory>
class EventQueueTimer; class EventQueueTimer;
namespace synergy { class Screen; } namespace synergy { class Screen; }
@ -234,8 +235,9 @@ private:
String m_receivedFileData; String m_receivedFileData;
DragFileList m_dragFileList; DragFileList m_dragFileList;
String m_dragFileExt; String m_dragFileExt;
Thread* m_sendFileThread; using AutoThread = std::unique_ptr<Thread>;
Thread* m_writeToDropDirThread; AutoThread m_sendFileThread;
AutoThread m_writeToDropDirThread;
TCPSocket* m_socket; TCPSocket* m_socket;
bool m_useSecureNetwork; bool m_useSecureNetwork;
bool m_enableClipboard; bool m_enableClipboard;

View file

@ -920,7 +920,7 @@ ServerProxy::dragInfoReceived()
void void
ServerProxy::handleClipboardSendingEvent(const Event& event, void*) ServerProxy::handleClipboardSendingEvent(const Event& event, void*)
{ {
ClipboardChunk::send(m_stream, event.getData()); ClipboardChunk::send(m_stream, event.getDataObject());
} }
void void

View file

@ -152,7 +152,7 @@ TCPListenSocket::serviceListening(ISocketMultiplexerJob* job,
return NULL; return NULL;
} }
if (read) { if (read) {
m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this, NULL)); m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this));
// stop polling on this socket until the client accepts // stop polling on this socket until the client accepts
return NULL; return NULL;
} }

View file

@ -443,7 +443,7 @@ TCPSocket::sendConnectionFailedEvent(const char* msg)
void void
TCPSocket::sendEvent(Event::Type type) TCPSocket::sendEvent(Event::Type type)
{ {
m_events->addEvent(Event(type, getEventTarget(), nullptr)); m_events->addEvent(Event(type, getEventTarget()));
} }
void void

View file

@ -614,30 +614,28 @@ void
OSXScreen::getDropTargetThread(void*) OSXScreen::getDropTargetThread(void*)
{ {
#if defined(MAC_OS_X_VERSION_10_7) #if defined(MAC_OS_X_VERSION_10_7)
char* cstr = NULL;
// wait for 5 secs for the drop destinaiton string to be filled. // wait for 5 secs for the drop destinaiton string to be filled.
UInt32 timeout = ARCH->time() + 5; UInt32 timeout = ARCH->time() + 5;
m_dropTarget.clear();
while (ARCH->time() < timeout) { while (ARCH->time() < timeout) {
CFStringRef cfstr = getCocoaDropTarget(); CFStringRef cfstr = getCocoaDropTarget();
cstr = CFStringRefToUTF8String(cfstr); char* cstr = CFStringRefToUTF8String(cfstr);
CFRelease(cfstr); CFRelease(cfstr);
if (cstr != NULL) { if (cstr != NULL) {
LOG((CLOG_DEBUG "drop target: %s", cstr));
m_dropTarget = cstr;
free(cstr);
break; break;
} }
ARCH->sleep(.1f); ARCH->sleep(.1f);
} }
if (cstr != NULL) { if (m_dropTarget.empty()) {
LOG((CLOG_DEBUG "drop target: %s", cstr));
m_dropTarget = cstr;
}
else {
LOG((CLOG_ERR "failed to get drop target")); LOG((CLOG_ERR "failed to get drop target"));
m_dropTarget.clear();
} }
#else #else
LOG((CLOG_WARN "drag drop not supported")); LOG((CLOG_WARN "drag drop not supported"));
#endif #endif
@ -2069,14 +2067,15 @@ OSXScreen::CFStringRefToUTF8String(CFStringRef aString)
} }
CFIndex length = CFStringGetLength(aString); CFIndex length = CFStringGetLength(aString);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding( CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
length,
kCFStringEncodingUTF8);
char* buffer = (char*)malloc(maxSize); char* buffer = (char*)malloc(maxSize);
if (CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) {
return buffer; if (!CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) {
free(buffer);
buffer = NULL;
} }
return NULL;
return buffer;
} }
void void
@ -2100,21 +2099,20 @@ String&
OSXScreen::getDraggingFilename() OSXScreen::getDraggingFilename()
{ {
if (m_draggingStarted) { if (m_draggingStarted) {
m_draggingFilename.clear();
CFStringRef dragInfo = getDraggedFileURL(); CFStringRef dragInfo = getDraggedFileURL();
char* info = NULL; char* info = CFStringRefToUTF8String(dragInfo);
info = CFStringRefToUTF8String(dragInfo); CFRelease(dragInfo);
if (info == NULL) {
m_draggingFilename.clear(); if (info != NULL) {
}
else {
LOG((CLOG_DEBUG "drag info: %s", info)); LOG((CLOG_DEBUG "drag info: %s", info));
CFRelease(dragInfo); m_draggingFilename = info;
String fileList(info); free(info);
m_draggingFilename = fileList;
} }
// fake a escape key down and up then left mouse button up // fake a escape key down and up then left mouse button up
fakeKeyDown(kKeyEscape, 8192, 1, AppUtil::instance().getCurrentLanguageCode()); fakeKeyDown(kKeyEscape, 8192, 1, AppUtil::instance().getCurrentLanguageCode());
fakeKeyUp(1); fakeKeyUp(1);
fakeMouseButton(kButtonLeft, false); fakeMouseButton(kButtonLeft, false);
} }

View file

@ -64,7 +64,7 @@ ClientProxy1_6::setClipboard(ClipboardID id, const IClipboard* clipboard)
void void
ClientProxy1_6::handleClipboardSendingEvent(const Event& event, void*) ClientProxy1_6::handleClipboardSendingEvent(const Event& event, void*)
{ {
ClipboardChunk::send(getStream(), event.getData()); ClipboardChunk::send(getStream(), event.getDataObject());
} }
bool bool

View file

@ -91,13 +91,13 @@ Server::Server(
m_lockedToScreen(false), m_lockedToScreen(false),
m_screen(screen), m_screen(screen),
m_events(events), m_events(events),
m_sendFileThread(NULL), m_sendFileThread(nullptr),
m_writeToDropDirThread(NULL), m_writeToDropDirThread(nullptr),
m_ignoreFileTransfer(false), m_ignoreFileTransfer(false),
m_disableLockToScreen(false), m_disableLockToScreen(false),
m_enableClipboard(true), m_enableClipboard(true),
m_maximumClipboardSize(INT_MAX), m_maximumClipboardSize(INT_MAX),
m_sendDragInfoThread(NULL), m_sendDragInfoThread(nullptr),
m_waitDragInfoThread(true), m_waitDragInfoThread(true),
m_args(args) m_args(args)
{ {
@ -1558,7 +1558,7 @@ Server::handleFakeInputEndEvent(const Event&, void*)
void void
Server::handleFileChunkSendingEvent(const Event& event, void*) Server::handleFileChunkSendingEvent(const Event& event, void*)
{ {
onFileChunkSending(event.getData()); onFileChunkSending(event.getDataObject());
} }
void void
@ -1862,11 +1862,11 @@ Server::onMouseMovePrimary(SInt32 x, SInt32 y)
&& m_screen->isDraggingStarted() && m_screen->isDraggingStarted()
&& m_active != newScreen && m_active != newScreen
&& m_waitDragInfoThread) { && m_waitDragInfoThread) {
if (m_sendDragInfoThread == NULL) { if (!m_sendDragInfoThread) {
m_sendDragInfoThread = new Thread( m_sendDragInfoThread.reset(new Thread(
new TMethodJob<Server>( new TMethodJob<Server>(
this, this,
&Server::sendDragInfoThread, newScreen)); &Server::sendDragInfoThread, newScreen)));
} }
return false; return false;
@ -1909,7 +1909,8 @@ Server::sendDragInfoThread(void* arg)
m_dragFileList.clear(); m_dragFileList.clear();
} }
m_waitDragInfoThread = false; m_waitDragInfoThread = false;
m_sendDragInfoThread = NULL; m_sendDragInfoThread.reset(nullptr);
} }
void void
@ -1919,15 +1920,10 @@ Server::sendDragInfo(BaseClientProxy* newScreen)
UInt32 fileCount = DragInformation::setupDragInfo(m_dragFileList, infoString); UInt32 fileCount = DragInformation::setupDragInfo(m_dragFileList, infoString);
if (fileCount > 0) { if (fileCount > 0) {
char* info = NULL;
size_t size = infoString.size();
info = new char[size];
memcpy(info, infoString.c_str(), size);
LOG((CLOG_DEBUG2 "sending drag information to client")); LOG((CLOG_DEBUG2 "sending drag information to client"));
LOG((CLOG_DEBUG3 "dragging file list: %s", info)); LOG((CLOG_DEBUG3 "dragging file list: %s", infoString.c_str()));
LOG((CLOG_DEBUG3 "dragging file list string size: %i", size)); LOG((CLOG_DEBUG3 "dragging file list string size: %i", infoString.size()));
newScreen->sendDragInfo(fileCount, info, size); newScreen->sendDragInfo(fileCount, infoString.c_str(), infoString.size());
} }
} }
@ -2060,9 +2056,9 @@ Server::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
} while (false); } while (false);
if (jump) { if (jump) {
if (m_sendFileThread != NULL) { if (m_sendFileThread) {
StreamChunker::interruptFile(); StreamChunker::interruptFile();
m_sendFileThread = NULL; m_sendFileThread.reset(nullptr);
} }
SInt32 newX = m_x; SInt32 newX = m_x;
@ -2126,9 +2122,8 @@ void
Server::onFileRecieveCompleted() Server::onFileRecieveCompleted()
{ {
if (isReceivedFileSizeValid()) { if (isReceivedFileSizeValid()) {
m_writeToDropDirThread = new Thread( auto method = new TMethodJob<Server>(this, &Server::writeToDropDirThread);
new TMethodJob<Server>( m_writeToDropDirThread.reset(new Thread(method));
this, &Server::writeToDropDirThread));
} }
} }
@ -2429,10 +2424,9 @@ Server::sendFileToClient(const char* filename)
StreamChunker::interruptFile(); StreamChunker::interruptFile();
} }
m_sendFileThread = new Thread( auto data = static_cast<void*>(const_cast<char*>(filename));
new TMethodJob<Server>( auto method = new TMethodJob<Server>(this, &Server::sendFileThread, data);
this, &Server::sendFileThread, m_sendFileThread.reset(new Thread(method));
static_cast<void*>(const_cast<char*>(filename))));
} }
void void
@ -2447,7 +2441,7 @@ Server::sendFileThread(void* data)
LOG((CLOG_ERR "failed sending file chunks, error: %s", error.what())); LOG((CLOG_ERR "failed sending file chunks, error: %s", error.what()));
} }
m_sendFileThread = NULL; m_sendFileThread.reset(nullptr);
} }
void void

View file

@ -33,6 +33,7 @@
#include "common/stdmap.h" #include "common/stdmap.h"
#include "common/stdset.h" #include "common/stdset.h"
#include "common/stdvector.h" #include "common/stdvector.h"
#include <memory>
class BaseClientProxy; class BaseClientProxy;
class EventQueueTimer; class EventQueueTimer;
@ -471,19 +472,20 @@ private:
IEventQueue* m_events; IEventQueue* m_events;
// file transfer // file transfer
using AutoThread = std::unique_ptr<Thread>;
size_t m_expectedFileSize; size_t m_expectedFileSize;
String m_receivedFileData; String m_receivedFileData;
DragFileList m_dragFileList; DragFileList m_dragFileList;
DragFileList m_fakeDragFileList; DragFileList m_fakeDragFileList;
Thread* m_sendFileThread; AutoThread m_sendFileThread;
Thread* m_writeToDropDirThread; AutoThread m_writeToDropDirThread;
String m_dragFileExt; String m_dragFileExt;
bool m_ignoreFileTransfer; bool m_ignoreFileTransfer;
bool m_disableLockToScreen; bool m_disableLockToScreen;
bool m_enableClipboard; bool m_enableClipboard;
size_t m_maximumClipboardSize; size_t m_maximumClipboardSize;
Thread* m_sendDragInfoThread; AutoThread m_sendDragInfoThread;
bool m_waitDragInfoThread; bool m_waitDragInfoThread;
ClientListener* m_clientListener; ClientListener* m_clientListener;

View file

@ -18,13 +18,14 @@
#pragma once #pragma once
#include "common/basic_types.h" #include "common/basic_types.h"
#include <base/EventTypes.h>
class Chunk { class Chunk : public EventData {
public: public:
Chunk(size_t size); Chunk(size_t size);
Chunk(Chunk const &) =delete; Chunk(Chunk const &) =delete;
Chunk(Chunk &&) =delete; Chunk(Chunk &&) =delete;
~Chunk(); ~Chunk() override;
Chunk& operator=(Chunk const &) =delete; Chunk& operator=(Chunk const &) =delete;
Chunk& operator=(Chunk &&) =delete; Chunk& operator=(Chunk &&) =delete;

View file

@ -83,7 +83,7 @@ PacketStreamFilter::read(void* buffer, UInt32 n)
if (m_inputShutdown && m_size == 0) { if (m_inputShutdown && m_size == 0) {
m_events->addEvent(Event(m_events->forIStream().inputShutdown(), m_events->addEvent(Event(m_events->forIStream().inputShutdown(),
getEventTarget(), NULL)); getEventTarget()));
} }
return n; return n;