Skip to content

Instantly share code, notes, and snippets.

@Frityet
Created February 18, 2026 19:55
Show Gist options
  • Select an option

  • Save Frityet/a330fffc5d8d06dff5b3e55e9e25e6ef to your computer and use it in GitHub Desktop.

Select an option

Save Frityet/a330fffc5d8d06dff5b3e55e9e25e6ef to your computer and use it in GitHub Desktop.
objfw-issues
#include <stdio.h>
#include <stdint.h>
#import <ObjFW/ObjFW.h>
int
main(void)
{
void *pool = objc_autoreleasePoolPush();
OFMemoryStream *stream;
@try {
stream = [OFMemoryStream streamWithMemoryAddress: (char *)"A" size: 1 writable: false];
(void)[stream readStringWithLength: SIZE_MAX];
puts("NO_CRASH");
} @catch (id e) {
printf("EXCEPTION:%s\n", object_getClassName(e));
}
objc_autoreleasePoolPop(pool);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdatomic.h>
#import <ObjFW/ObjFW.h>
#import <ObjFWRT/ObjFWRT.h>
static _Atomic bool gStop = false;
static id gWeak;
@interface LoaderThread: OFThread
@end
@implementation LoaderThread
- (id)main
{
while (!atomic_load(&gStop)) {
id value = objc_loadWeakRetained(&gWeak);
if (value != nil)
objc_release(value);
}
return nil;
}
@end
int
main(int argc, char **argv)
{
void *pool = objc_autoreleasePoolPush();
unsigned long iterations = 500000;
LoaderThread *t1 = [[LoaderThread alloc] init];
LoaderThread *t2 = [[LoaderThread alloc] init];
if (argc > 1)
iterations = strtoul(argv[1], NULL, 10);
[t1 start];
[t2 start];
for (unsigned long i = 0; i < iterations; i++) {
id obj = [[OFObject alloc] init];
objc_storeWeak(&gWeak, obj);
objc_release(obj);
}
atomic_store(&gStop, true);
[t1 join];
[t2 join];
objc_release(t1);
objc_release(t2);
printf("completed iterations=%lu\n", iterations);
objc_autoreleasePoolPop(pool);
return 0;
}
#include <stdio.h>
#include <stdatomic.h>
#import <ObjFW/ObjFW.h>
static _Atomic int gLive = 0;
static _Atomic int gCreated = 0;
@interface Token: OFObject
+ (instancetype)token;
@end
@implementation Token
+ (instancetype)token
{
return objc_autorelease([[self alloc] init]);
}
- (instancetype)init
{
self = [super init];
if (self != nil) {
atomic_fetch_add(&gLive, 1);
atomic_fetch_add(&gCreated, 1);
}
return self;
}
- (void)dealloc
{
atomic_fetch_sub(&gLive, 1);
[super dealloc];
}
@end
@interface ProbeDelegate: OFObject <OFApplicationDelegate>
@end
@implementation ProbeDelegate
- (void)makeGarbage
{
for (int i = 0; i < 20000; i++)
(void)[Token token];
printf("after_first_timer created=%d live=%d\n",
atomic_load(&gCreated), atomic_load(&gLive));
}
- (void)checkAndExit
{
printf("before_terminate created=%d live=%d\n",
atomic_load(&gCreated), atomic_load(&gLive));
[OFApplication terminate];
}
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
(void)notification;
[OFTimer scheduledTimerWithTimeInterval: 0.01
target: self
selector: @selector(makeGarbage)
repeats: false];
[OFTimer scheduledTimerWithTimeInterval: 0.02
target: self
selector: @selector(checkAndExit)
repeats: false];
}
@end
OF_APPLICATION_DELEGATE(ProbeDelegate)
#include <stdio.h>
#import <ObjFW/ObjFW.h>
int
main(void)
{
void *pool = objc_autoreleasePoolPush();
OFMutableZIPArchiveEntry *entry = [OFMutableZIPArchiveEntry entryWithFileName: @"file.txt"];
OFMutableZIPArchiveEntry *copy;
entry.extraField = [OFData dataWithItems: "EXTRA" count: 5];
entry.fileComment = @"COMMENT";
copy = [entry mutableCopy];
printf("orig_comment_class=%s\n", object_getClassName(entry.fileComment));
printf("copy_comment_class=%s\n", object_getClassName(copy.fileComment));
printf("copy_extra_class=%s\n", object_getClassName(copy.extraField));
if ([copy.fileComment isKindOfClass: [OFString class]])
printf("copy_comment=%s\n", copy.fileComment.UTF8String);
else
puts("copy_comment_not_string");
objc_release(copy);
objc_autoreleasePoolPop(pool);
return 0;
}
#include <stdio.h>
#import <ObjFW/ObjFW.h>
@interface ProbeDelegate: OFObject <OFApplicationDelegate, OFHTTPServerDelegate>
{
OFHTTPServer *_server;
size_t _requests;
}
@end
@implementation ProbeDelegate
- (void)stopLater
{
printf("STOP requests=%zu\n", _requests);
[OFApplication terminate];
}
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
OFArray OF_GENERIC(OFString *) *args = [OFApplication arguments];
uint16_t port = 18183;
(void)notification;
if (args.count >= 1)
port = (uint16_t)((OFString *)args[0]).unsignedLongLongValue;
_server = [[OFHTTPServer alloc] init];
_server.host = @"127.0.0.1";
_server.port = port;
_server.delegate = self;
[_server start];
printf("LISTENING %u\n", port);
fflush(stdout);
[OFTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector: @selector(stopLater)
repeats: false];
}
- (void)server: (OFHTTPServer *)server
didReceiveRequest: (OFHTTPRequest *)request
requestBody: (OFStream *)requestBody
response: (OFHTTPResponse *)response
{
(void)server;
(void)requestBody;
_requests++;
printf("REQUEST_RECEIVED method=%u\n", (unsigned int)request.method);
fflush(stdout);
@try {
[response writeString: @"OK"];
} @catch (id e) {
(void)e;
}
}
- (void)server: (OFHTTPServer *)server
didEncounterException: (id)exception
request: (OFHTTPRequest *)request
response: (OFHTTPResponse *)response
{
(void)server;
(void)request;
(void)response;
printf("SERVER_EXCEPTION %s\n", object_getClassName(exception));
fflush(stdout);
}
@end
OF_APPLICATION_DELEGATE(ProbeDelegate)
#include <stdio.h>
#import <ObjFW/ObjFW.h>
@interface ProbeDelegate: OFObject <OFApplicationDelegate>
@end
@implementation ProbeDelegate
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
OFArray OF_GENERIC(OFString *) *args = [OFApplication arguments];
OFString *portArg, *lenArg;
OFTCPSocket *socket;
OFMutableString *host;
uint16_t port;
size_t len;
(void)notification;
if (args.count != 2) {
fprintf(stderr, "usage: 03_socks5_hostlen_trunc <proxy-port> <len>\n");
[OFApplication terminateWithStatus: 2];
return;
}
portArg = args[0];
lenArg = args[1];
port = (uint16_t)portArg.unsignedLongLongValue;
len = (size_t)lenArg.unsignedLongLongValue;
host = [OFMutableString string];
for (size_t i = 0; i < len; i++)
[host appendString: @"a"];
socket = [OFTCPSocket socket];
socket.SOCKS5Host = @"127.0.0.1";
socket.SOCKS5Port = port;
@try {
[socket connectToHost: host port: 80];
puts("CONNECT_OK");
} @catch (id e) {
printf("EXCEPTION:%s\n", object_getClassName(e));
}
@try {
[socket close];
} @catch (id e) {
(void)e;
}
[OFApplication terminate];
}
@end
OF_APPLICATION_DELEGATE(ProbeDelegate)
#include <stdio.h>
#import <ObjFW/ObjFW.h>
@interface ProbeServerDelegate: OFObject <OFApplicationDelegate, OFHTTPServerDelegate>
{
OFHTTPServer *_server;
}
@end
@implementation ProbeServerDelegate
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
OFArray OF_GENERIC(OFString *) *args = [OFApplication arguments];
uint16_t port = 18181;
(void)notification;
if (args.count >= 1)
port = (uint16_t)((OFString *)args[0]).unsignedLongLongValue;
_server = [[OFHTTPServer alloc] init];
_server.host = @"127.0.0.1";
_server.port = port;
_server.delegate = self;
[_server start];
printf("LISTENING %u\n", port);
fflush(stdout);
}
- (void)server: (OFHTTPServer *)server
didReceiveRequest: (OFHTTPRequest *)request
requestBody: (OFStream *)requestBody
response: (OFHTTPResponse *)response
{
(void)server;
(void)request;
(void)requestBody;
@try {
[response writeString: @"OK"];
} @catch (id e) {
(void)e;
}
}
- (void)server: (OFHTTPServer *)server
didEncounterException: (id)exception
request: (OFHTTPRequest *)request
response: (OFHTTPResponse *)response
{
(void)server;
(void)request;
(void)response;
printf("SERVER_EXCEPTION %s\n", object_getClassName(exception));
fflush(stdout);
}
@end
OF_APPLICATION_DELEGATE(ProbeServerDelegate)
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#import <ObjFW/ObjFW.h>
#import <ObjFWRT/ObjFWRT.h>
@interface EvilStream: OFStream
@end
@implementation EvilStream
- (bool)lowlevelIsAtEndOfStream
{
return false;
}
- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length
{
(void)length;
((char *)buffer)[0] = 'A';
return 1;
}
@end
static Ivar
findIvar(Class cls, const char *name)
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(cls, &count);
Ivar found = NULL;
for (unsigned int i = 0; i < count; i++) {
if (strcmp(ivar_getName(ivars[i]), name) == 0) {
found = ivars[i];
break;
}
}
OFFreeMemory(ivars);
return found;
}
static void
setIvarBytes(id obj, Class cls, const char *name, const void *value, size_t size)
{
Ivar iv = findIvar(cls, name);
if (iv == NULL) {
fprintf(stderr, "missing ivar %s\n", name);
return;
}
memcpy((char *)obj + ivar_getOffset(iv), value, size);
}
int
main(void)
{
void *pool = objc_autoreleasePoolPush();
EvilStream *stream = [[EvilStream alloc] init];
char *mem = OFAllocMemory(1, 1);
size_t huge = SIZE_MAX;
bool waiting = true;
setIvarBytes(stream, [OFStream class], "_readBufferMemory", &mem,
sizeof(mem));
setIvarBytes(stream, [OFStream class], "_readBuffer", &mem,
sizeof(mem));
setIvarBytes(stream, [OFStream class], "_readBufferLength", &huge,
sizeof(huge));
setIvarBytes(stream, [OFStream class], "_waitingForDelimiter", &waiting,
sizeof(waiting));
@try {
(void)[stream tryReadLine];
puts("NO_CRASH");
} @catch (id e) {
printf("EXCEPTION:%s\n", object_getClassName(e));
}
objc_release(stream);
objc_autoreleasePoolPop(pool);
return 0;
}
#include <stdio.h>
#include <unistd.h>
#import <ObjFW/ObjFW.h>
#import <ObjFWRT/ObjFWRT.h>
static void
noop(id self, SEL _cmd)
{
(void)self;
(void)_cmd;
}
int
main(void)
{
char className[128], selName[64];
Class cls;
snprintf(className, sizeof(className), "ReproClass_%ld", (long)getpid());
cls = objc_allocateClassPair([OFObject class], className, 0);
if (cls == Nil)
return 1;
objc_registerClassPair(cls);
for (size_t i = 0; i < 10000; i++) {
snprintf(selName, sizeof(selName), "x%zu", i);
(void)class_addMethod(cls, sel_registerName(selName), (IMP)noop,
"v@:");
}
objc_deinit();
return 0;
}
#include <stdio.h>
#import <ObjFW/ObjFW.h>
int
main(void)
{
void *pool = objc_autoreleasePoolPush();
OFMutableArray *arr = [OFMutableArray arrayWithObject: @"x"];
OFIndexSet *indexes =
[OFIndexSet indexSetWithIndexesInRange: OFMakeRange(5, 1)];
for (size_t i = 0; i < 1000; i++) {
@try {
[arr removeObjectsAtIndexes: indexes];
} @catch (OFOutOfRangeException *e) {
(void)e;
}
}
objc_autoreleasePoolPop(pool);
puts("DONE");
return 0;
}

ObjFW Audit Repros

Minimal repro harnesses for the confirmed and likely findings from the deep audit.

Requirements

  • ObjFW installed at /workspaces/ObjFW/install (override with OBJFW_PREFIX)
  • valgrind
  • python3

Usage

Run from repo root:

./repros/run.sh c1   # one repro
./repros/run.sh l3   # one likely repro
./repros/run.sh all  # everything

Repro Index

  • c1 confirmed: readStringWithLength:SIZE_MAX overflow crash (src/OFStream.m)
  • c2 confirmed: ZIP mutableCopy copies wrong field (src/OFZIPArchiveEntry.m)
  • c3 confirmed: SOCKS5 hostname length wraps/truncates at 256 (src/OFTCPSocketSOCKS5Connector.m)
  • c4 confirmed: HTTP long-line buffering drives memory growth (src/OFHTTPServer.m + src/OFStream.m)
  • c5 confirmed: runtime dynamic method-list leak on objc_deinit (src/runtime/class.m)
  • c6 confirmed: leak on out-of-range removeObjectsAtIndexes: path (src/OFConcreteMutableArray.m)
  • c7 confirmed (test infra): CustomData/CustomMutableData leak via OFDataTests
  • l1 likely: weak-reference race stress (src/runtime/arc.m)
  • l2 likely: run-loop pool lifecycle probe (src/OFRunLoop.m)
  • l3 likely: huge chunk size accepted (no practical cap) (src/OFHTTPServer.m)
  • l4 likely: unchecked _readBufferLength + bufferLength wrap path (src/OFStream.m)

Notes:

  • l1 is nondeterministic by nature; script runs multiple attempts.
  • l2 is a probe to validate behavior around callback-to-callback autorelease draining.
  • l4 uses injected internal stream state to hit the wrap path without allocating near-SIZE_MAX memory.
#!/usr/bin/env bash
set -euo pipefail
OBJFW_PREFIX="${OBJFW_PREFIX:-/workspaces/ObjFW/install}"
export PATH="$OBJFW_PREFIX/bin:$PATH"
export LD_LIBRARY_PATH="$OBJFW_PREFIX/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
REPRO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_DIR="$REPRO_ROOT/.build"
OBJ_DIR="$BUILD_DIR/obj"
LOG_DIR="$REPRO_ROOT/.logs"
mkdir -p "$BUILD_DIR" "$OBJ_DIR" "$LOG_DIR"
compile_objfw() {
local src="$1"
local out="$2"
objfw-compile -g -O0 --builddir "$OBJ_DIR" -o "$out" "$src"
}
print_header() {
local msg="$1"
printf '\n===== %s =====\n' "$msg"
}
#!/usr/bin/env bash
set -euo pipefail
source "$(cd "$(dirname "$0")" && pwd)/common.sh"
REPO_ROOT="$(cd "$REPRO_ROOT/.." && pwd)"
build_repro() {
local rel="$1"
local src="$REPRO_ROOT/$rel"
local out="$BUILD_DIR/$(basename "${rel%.m}")"
compile_objfw "$src" "$out" >/dev/null
echo "$out"
}
run_c1() {
print_header "c1 stream SIZE_MAX overflow"
local bin
bin="$(build_repro confirmed/01_stream_size_max_overflow.m)"
set +e
"$bin"
local code=$?
set -e
echo "exit_code=$code (expect non-zero / SIGSEGV)"
}
run_c2() {
print_header "c2 ZIP mutableCopy fileComment mismatch"
local bin
bin="$(build_repro confirmed/02_zip_mutablecopy_comment.m)"
"$bin"
}
run_c3() {
print_header "c3 SOCKS5 host length truncation"
local bin
bin="$(build_repro confirmed/03_socks5_hostlen_trunc.m)"
for len in 255 256; do
local cap="$LOG_DIR/c3.proxy.$len.log"
local client="$LOG_DIR/c3.client.$len.log"
python3 "$REPRO_ROOT/helpers/socks5_capture.py" >"$cap" 2>&1 &
local spid=$!
for _ in $(seq 1 200); do
[[ -s "$cap" ]] && break
sleep 0.02
done
local port
port="$(head -n1 "$cap" | tr -d '\r\n')"
set +e
"$bin" "$port" "$len" >"$client" 2>&1
set -e
wait "$spid" || true
echo "-- len=$len client --"
cat "$client"
echo "-- len=$len proxy --"
cat "$cap"
done
}
run_c4() {
print_header "c4 HTTP long-line memory growth"
local bin
bin="$(build_repro confirmed/04_http_line_server.m)"
local server_log="$LOG_DIR/c4.server.log"
: > "$server_log"
"$bin" 18181 >"$server_log" 2>&1 &
local spid=$!
for _ in $(seq 1 200); do
grep -q "LISTENING" "$server_log" && break
sleep 0.05
done
local rss_before
rss_before="$(awk '/VmRSS:/ {print $2}' "/proc/$spid/status")"
python3 - <<'PY'
import socket, time
N = 16 * 1024 * 1024
s = socket.create_connection(("127.0.0.1", 18181), timeout=5)
s.sendall(b"GET /")
chunk = b"A" * 65536
remaining = N - 5
while remaining > 0:
n = min(len(chunk), remaining)
s.sendall(chunk[:n])
remaining -= n
time.sleep(2)
s.close()
PY
local rss_after
rss_after="$(awk '/VmRSS:/ {print $2}' "/proc/$spid/status")"
kill "$spid" >/dev/null 2>&1 || true
wait "$spid" 2>/dev/null || true
echo "rss_before_kb=$rss_before"
echo "rss_after_kb=$rss_after"
echo "rss_delta_kb=$((rss_after-rss_before))"
echo "-- server log --"
cat "$server_log"
}
run_c5() {
print_header "c5 runtime class_addMethod/class_replaceMethod deinit leak"
local bin
bin="$(build_repro confirmed/05_runtime_methodlist_deinit_leak.m)"
local log="$LOG_DIR/c5.valgrind.log"
set +e
valgrind --leak-check=full --show-leak-kinds=all \
--errors-for-leak-kinds=definite --error-exitcode=99 \
"$bin" >"$log" 2>&1
local code=$?
set -e
echo "valgrind_exit_code=$code (99 expected when definite leaks found)"
grep -nE "definitely lost|indirectly lost|ERROR SUMMARY" "$log" || true
}
run_c6() {
print_header "c6 mutable array OOB exception leak"
local bin
bin="$(build_repro confirmed/06_mutable_array_oob_leak.m)"
local log="$LOG_DIR/c6.valgrind.log"
set +e
valgrind --leak-check=full --show-leak-kinds=all \
--errors-for-leak-kinds=definite --error-exitcode=99 \
"$bin" >"$log" 2>&1
local code=$?
set -e
echo "valgrind_exit_code=$code (99 expected when definite leaks found)"
grep -nE "definitely lost|ERROR SUMMARY|removeObjectsAtIndexes" "$log" || true
}
run_c7() {
print_header "c7 test-scaffold leak in CustomData/CustomMutableData"
local log="$LOG_DIR/c7.valgrind.ofdata.log"
pushd "$REPO_ROOT/tests" >/dev/null
set +e
LD_LIBRARY_PATH="/workspaces/ObjFW/install/lib" \
valgrind --leak-check=full --show-leak-kinds=all \
--errors-for-leak-kinds=definite --error-exitcode=99 \
./tests OFDataTests >"$log" 2>&1
local code=$?
set -e
popd >/dev/null
echo "valgrind_exit_code=$code (99 expected when definite leaks found)"
grep -nE "CustomData|definitely lost|ERROR SUMMARY" "$log" || true
}
run_l1() {
print_header "l1 weak-reference race stress"
local bin
bin="$(build_repro likely/01_weak_race_arc.m)"
local attempts=5
local iter=300000
local crashed=0
for i in $(seq 1 "$attempts"); do
set +e
"$bin" "$iter" >"$LOG_DIR/l1.run.$i.log" 2>&1
local code=$?
set -e
echo "attempt=$i exit_code=$code"
if [[ $code -ne 0 ]]; then
crashed=1
echo "-- failing attempt log (tail) --"
tail -n 40 "$LOG_DIR/l1.run.$i.log" || true
break
fi
done
if [[ $crashed -eq 0 ]]; then
echo "No crash observed in $attempts attempts (nondeterministic race)."
fi
}
run_l2() {
print_header "l2 run-loop autorelease-pool lifecycle probe"
local bin
bin="$(build_repro likely/02_runloop_pool_probe.m)"
"$bin"
echo "Interpretation: if live remains large before second timer, pool draining is suspect."
}
run_l3() {
print_header "l3 HTTP huge chunk size acceptance probe"
local bin
bin="$(build_repro likely/03_http_chunked_huge_server.m)"
local server_log="$LOG_DIR/l3.server.log"
: > "$server_log"
"$bin" 18183 >"$server_log" 2>&1 &
local spid=$!
for _ in $(seq 1 200); do
grep -q "LISTENING" "$server_log" && break
sleep 0.05
done
python3 - <<'PY'
import socket, time
s = socket.create_connection(("127.0.0.1", 18183), timeout=5)
req = (
b"POST / HTTP/1.1\r\n"
b"Host: x\r\n"
b"Transfer-Encoding: chunked\r\n"
b"\r\n"
b"7fffffffffffffff\r\n"
)
s.sendall(req)
time.sleep(1.5)
s.close()
PY
wait "$spid" || true
cat "$server_log"
echo "Interpretation: receiving request without immediate 4xx/reject demonstrates no practical chunk-size cap here."
}
run_l4() {
print_header "l4 OFStream unchecked _readBufferLength+bufferLength wrap (injected state)"
local bin
bin="$(build_repro likely/04_stream_readbuffer_wrap_injected.m)"
set +e
"$bin"
local code=$?
set -e
echo "exit_code=$code (expect non-zero / SIGSEGV)"
}
run_all() {
run_c1
run_c2
run_c3
run_c4
run_c5
run_c6
run_c7
run_l1
run_l2
run_l3
run_l4
}
main() {
local target="${1:-all}"
case "$target" in
c1) run_c1 ;;
c2) run_c2 ;;
c3) run_c3 ;;
c4) run_c4 ;;
c5) run_c5 ;;
c6) run_c6 ;;
c7) run_c7 ;;
l1) run_l1 ;;
l2) run_l2 ;;
l3) run_l3 ;;
l4) run_l4 ;;
all) run_all ;;
*)
echo "Usage: $0 {c1|c2|c3|c4|c5|c6|c7|l1|l2|l3|l4|all}" >&2
exit 2
;;
esac
}
main "$@"
#!/usr/bin/env python3
import socket
import sys
ls = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ls.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ls.bind(("127.0.0.1", 0))
ls.listen(1)
print(ls.getsockname()[1], flush=True)
conn, _ = ls.accept()
conn.settimeout(5)
hdr = conn.recv(2)
if len(hdr) != 2:
print("ERR greeting header", file=sys.stderr)
sys.exit(2)
ver, nmethods = hdr
methods = conn.recv(nmethods)
conn.sendall(b"\x05\x00")
req = conn.recv(4)
if len(req) != 4:
print("ERR request header", file=sys.stderr)
sys.exit(3)
ver2, cmd, _, atyp = req
host_len = None
host = b""
if atyp == 0x03:
b = conn.recv(1)
if len(b) != 1:
print("ERR domain len", file=sys.stderr)
sys.exit(4)
host_len = b[0]
host = conn.recv(host_len)
_ = conn.recv(2)
else:
print(f"ERR atyp={atyp}", file=sys.stderr)
sys.exit(5)
conn.sendall(b"\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00")
print(f"GREETING ver={ver} nmethods={nmethods} methods={methods.hex()}")
print(
f"REQUEST ver={ver2} cmd={cmd} atyp={atyp} "
f"host_len={host_len} host_recv_bytes={len(host)}"
)
conn.close()
ls.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment