Skip to content

Memory leak in FlyingFox or FlyingSocks #193

Description

@forchid

The version info

Windows 10 x64, FlyingFox 0.26.2 or the main branch.

The test

Itr#0 -------------- memory size 300M+
Itr#1 -------------- memory size 500M+
Itr#2 -------------- memory size 700M+
Itr#3 -------------- memory size 1000M+
...

The test source

import FlyingFox
import FlyingSocks
import FlyingFoxMacros

import Foundation
import FoundationNetworking

let host = "127.0.0.1"
let port: UInt16 = 3000
let addr: SocketAddress = try .inet(ip4: host, port: port)
let logger = DisabledLogger.disabled
let bodySize = 2 << 20

// Start server
let server = HTTPServer(address: addr, logger: logger, handler: MemleakHandler())
let serverTask = Task { try await server.run() }
defer { serverTask.cancel() }
        
// Start tests
for i in 0 ..< 1000 {
    await startTest(itr: i)
}
print("Bye!")

func startTest(itr: Int) async {
    var i = 0
    while i < 10000 {
        let j = i
        async let c1 = startClient(itr, j)
        async let c2 = startClient(itr, j + 1)
        async let c3 = startClient(itr, j + 2)
        async let c4 = startClient(itr, j + 3)
        //async let c5 = startClient(j + 4) // Crash?!
        
        let res = await [
            c1, 
            c2, 
            c3, 
            c4, 
            //c5
        ]
        i += res.count
    }

    i = 0
    while i < 10 {
        print("Itr#\(itr)-\(i): wait for a while")
        try? await Task.sleep(for: .seconds(1))
        i += 1
    }
}

func startClient(_ itr: Int, _ i: Int) async -> Bool {
    let url = URL(string: "http://\(host):\(port)/flyingleak")!
    var req = URLRequest(url: url)
    req.httpMethod = "POST"
    req.httpBody = Data(Array<UInt8>(repeating: 65, count: bodySize))
    do {
        let (data, res) = try await URLSession.shared.data(for: req)
        guard let res = res as? HTTPURLResponse else {
            print("Client#\(i): response type error!")
            return false
        }
        if res.statusCode == 200 && data.count == bodySize {
            if i % 1000 == 0 {
                print("Itr#\(itr)-client-\(i): ok.")
            }
            return true
        } else {
            print("Itr#\(itr)-client-\(i): failed - status \(res.statusCode).")
            return false
        }
    } catch {
        print("Itr#\(itr)-client-\(i): failed - \(error)")
        return false
    }
}

@HTTPHandler
struct MemleakHandler {

  @HTTPRoute("/flyingleak")
  func hello(_ request: HTTPRequest) async throws -> HTTPResponse {
    let data = try await request.bodyData
    if data.count != bodySize {
        return HTTPResponse(statusCode: .badRequest)
    }
    var headers = HTTPHeaders()
    headers[.contentType] = "text/plain;charset=utf-8";
    let body = Data(Array<UInt8>(repeating: 66, count: bodySize))
    return HTTPResponse(statusCode: .ok, headers: headers, body: body)
  }
  
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions