LibVNC / libvncserver

LibVNCServer/LibVNCClient are cross-platform C libraries that allow you to easily implement VNC server or client functionality in your program.
GNU General Public License v2.0
1.08k stars 483 forks source link

Big memory leak, on client disconnect, in server that is started with the runInBackground argument set to TRUE #570

Open JorisHansMeijer opened 1 year ago

JorisHansMeijer commented 1 year ago

When starting the server with the runInBackground argument set to TRUE a big memory leak happens each time a client disconnects. This is because the client_thread is not joined after detach. I fixed this by adding pthread_detach(cl->client_thread); at the end of the clientInput function in main.c (just before the return).

Because no the thread doesn't need to be joined I have also removed the join that was there in rfbShutdownServer. This join will only join the clients that are active at the time of stopping the server (not the clients that have disconnected before rfbShutdownServer was called).

bk138 commented 1 year ago

Thanks for finding out! Could you be so kind and file a pull request? This way, we can also have proper author credits :-)

JorisHansMeijer commented 1 year ago

Done

bk138 commented 11 months ago

list of things to check for @bk138

bk138 commented 11 months ago

This needs some more love as 8560a5a72d76fc3ab3484ca41f604116807f34e8 alone caused https://github.com/bk138/droidVNC-NG/issues/163

JorisHansMeijer commented 11 months ago

Is it correct that the problem happens a shutting down the server? Looking at the code again I can see that pthread_join would wait for the client thread to finish execution. Removing pthread join (as detached trhead's can't be joined) would also remove the waiting for the client to finish code. So the solution seems to be to just wait for the client to finish instead of the previous pthread_join call.

bk138 commented 11 months ago

Exactly. How would we best wait for a detached thread to finish?

JorisHansMeijer commented 11 months ago

Maybe the best way would be using pthread_kill, it can be used in a simulation mode were it just test if the signal could be send. In this way it is possible to know if a thread is still running. Example (untested): while(pthread_kill(currentCl->client_thread, 0) != ESRCH){ sleep some ms.. }

bk138 commented 11 months ago

Hmm, busy sleep sounds like we can do better? Maybe a condition variable or the like? (disclaimer: I'm not soo familiar with pthreads...)

JorisHansMeijer commented 11 months ago

Some more digging reveals that using pthread_kill on a canceled thread is not a good way to go (in linux I believe it is fine, but not for all pthread implementations out there). Maybe a better way to go is keep track of the thread termination in the client object (add running variable, set it at thread start, clear it at thread detach) and wait for that to clear in the termination function.

The time between stopping the server and waiting for the threads to finish should not be long so a loop with a short sleep would not be that much of a issue I think (just a couple of ms using nanosleep on linux and something similar on windows).

As a alternative it is possible to NOT detach the threads that are still running at server termination (conditional detach). Than the original join can be put back. However this might cause problems with clients that are just in the process of detaching when the server is stopped.