Skip to content

Connection._force_close relies on garbage collector to close SocketIO instances #1183

@cfbolz

Description

@cfbolz

Describe the bug
We've had a bug report in PyPy that sockets aren't closed correctly when using PyMySQL: pypy/pypy#5020
I've have looked into it a bit, it seems that Connection._force_close does not close the self._rfile attributes before setting them to None. Since socket objects have a manual refcount how many times .makefile is called on them, this means that the socket file descriptor isn't closed immediately.

In CPython this isn't visible due to reference counting closing the SocketIO instance in a timely manner. But in PyPy, this could happen only at the end of the next major garbage collection cycle, which could be quite a bit later.

To Reproduce
Complete steps to reproduce the behavior:

import sys
import os
import pymysql

db_config = {
    'host': 'localhost',
    'user': 'rob',
    'password': '123456',
    'connect_timeout': 1,
    'read_timeout': 1,
    'write_timeout': 1,
}

def netstat():
    os.system(f"netstat -anp 2>/dev/null | grep 3306 | grep {os.getpid()}")

connection = pymysql.connect(**db_config)


connection = pymysql.connect(**db_config)
# keep the socket alive to simulate the slowness in calling __del__ of pypy
sock = connection._sock
rfile = connection._rfile

print(f"{connection=} {connection._sock=} {connection._rfile=}")
netstat()
connection._force_close()
print(f"after _force_close {connection=} {connection._sock=} {connection._rfile=}")
print(f"{sock=} {rfile=}")
netstat()

Expected behavior
I would expect the final netstat() call to not show an open socket.

Environment

  • OS: Linux
  • Server and version: 5.7.41
  • PyMySQL version: 1.4.6

Additional context
I'm happy to try to open a drive-by PR for this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions