diff options
Diffstat (limited to 'tests/stdlib')
-rw-r--r-- | tests/stdlib/tfdleak.nim | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim new file mode 100644 index 000000000..08ef06da3 --- /dev/null +++ b/tests/stdlib/tfdleak.nim @@ -0,0 +1,85 @@ +discard """ + exitcode: 0 + output: "" + matrix: "; -d:nimInheritHandles" +""" + +import os, osproc, strutils, nativesockets, net, selectors, memfiles +when defined(windows): + import winlean +else: + import posix + +proc leakCheck(f: int | FileHandle | SocketHandle, msg: string, expectLeak = defined(nimInheritHandles)) = + discard startProcess( + getAppFilename(), + args = @[$f.int, msg, $expectLeak], + options = {poParentStreams} + ).waitForExit -1 + +proc isValidHandle(f: int): bool = + ## Check if a handle is valid. Requires OS-native handles. + when defined(windows): + var flags: DWORD + result = getHandleInformation(f.Handle, addr flags) != 0 + else: + result = fcntl(f.cint, F_GETFD) != -1 + +proc main() = + if paramCount() == 0: + # Parent process + let f = system.open("__test_fdleak", fmReadWrite) + defer: close f + + leakCheck(f.getOsFileHandle, "system.open()") + + doAssert f.reopen("__test_fdleak2", fmReadWrite), "reopen failed" + + leakCheck(f.getOsFileHandle, "reopen") + + let sock = createNativeSocket() + defer: close sock + leakCheck(sock, "createNativeSocket()") + if sock.setInheritable(true): + leakCheck(sock, "createNativeSocket()", true) + else: + raiseOSError osLastError() + + let server = newSocket() + defer: close server + server.bindAddr() + server.listen() + let (_, port) = server.getLocalAddr + + leakCheck(server.getFd, "newSocket()") + + let client = newSocket() + defer: close client + client.connect("127.0.0.1", port) + + var input: Socket + server.accept(input) + + leakCheck(input.getFd, "accept()") + + # ioselectors_select doesn't support returning a handle. + when not defined(windows): + let selector = newSelector[int]() + leakCheck(selector.getFd, "selector()", false) + + var mf = memfiles.open("__test_fdleak3", fmReadWrite, newFileSize = 1) + defer: close mf + when defined(windows): + leakCheck(mf.fHandle, "memfiles.open().fHandle", false) + leakCheck(mf.mapHandle, "memfiles.open().mapHandle", false) + else: + leakCheck(mf.handle, "memfiles.open().handle", false) + else: + let + fd = parseInt(paramStr 1) + expectLeak = parseBool(paramStr 3) + msg = (if expectLeak: "not " else: "") & "leaked " & paramStr 2 + if expectLeak xor fd.isValidHandle: + echo msg + +when isMainModule: main() |