Skip to content

Commit 50d3d0a

Browse files
mtopolnikclaude
andcommitted
Fix native memory leak in QwpUdpSender constructor
Move NativeSegmentList, NativeBufferWriter, and SegmentedNativeBufferWriter allocations from field initializers into the constructor body, wrapped in a try-catch. If any allocation or the UdpLineChannel/HashMap construction throws, the catch block frees all previously allocated native resources via Misc.free() before re-throwing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent decf797 commit 50d3d0a

1 file changed

Lines changed: 26 additions & 6 deletions

File tree

core/src/main/java/io/questdb/client/cutlass/qwp/client/QwpUdpSender.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import io.questdb.client.std.Decimal128;
3838
import io.questdb.client.std.Decimal256;
3939
import io.questdb.client.std.Decimal64;
40+
import io.questdb.client.std.Misc;
4041
import io.questdb.client.std.ObjList;
4142
import io.questdb.client.std.Unsafe;
4243
import io.questdb.client.std.bytes.DirectByteSlice;
@@ -69,10 +70,10 @@ public class QwpUdpSender implements Sender {
6970
private static final int VARINT_INT_UPPER_BOUND = 5;
7071
private final UdpLineChannel channel;
7172
private final QwpColumnWriter columnWriter = new QwpColumnWriter();
72-
private final NativeSegmentList datagramSegments = new NativeSegmentList();
73-
private final NativeBufferWriter headerBuffer = new NativeBufferWriter();
73+
private final NativeSegmentList datagramSegments;
74+
private final NativeBufferWriter headerBuffer;
7475
private final int maxDatagramSize;
75-
private final SegmentedNativeBufferWriter payloadWriter = new SegmentedNativeBufferWriter();
76+
private final SegmentedNativeBufferWriter payloadWriter;
7677
private final CharSequenceObjHashMap<QwpTableBuffer> tableBuffers;
7778
private final CharSequenceObjHashMap<TableHeadroomState> tableHeadroomStates;
7879
private final boolean trackDatagramEstimate;
@@ -105,9 +106,28 @@ public QwpUdpSender(NetworkFacade nf, int interfaceIPv4, int sendToAddress, int
105106
}
106107

107108
public QwpUdpSender(NetworkFacade nf, int interfaceIPv4, int sendToAddress, int port, int ttl, int maxDatagramSize) {
108-
this.channel = new UdpLineChannel(nf, interfaceIPv4, sendToAddress, port, ttl);
109-
this.tableHeadroomStates = new CharSequenceObjHashMap<>();
110-
this.tableBuffers = new CharSequenceObjHashMap<>();
109+
NativeSegmentList segments = null;
110+
NativeBufferWriter header = null;
111+
SegmentedNativeBufferWriter payload = null;
112+
UdpLineChannel ch = null;
113+
try {
114+
segments = new NativeSegmentList();
115+
header = new NativeBufferWriter();
116+
payload = new SegmentedNativeBufferWriter();
117+
ch = new UdpLineChannel(nf, interfaceIPv4, sendToAddress, port, ttl);
118+
this.tableHeadroomStates = new CharSequenceObjHashMap<>();
119+
this.tableBuffers = new CharSequenceObjHashMap<>();
120+
} catch (Throwable t) {
121+
Misc.free(ch);
122+
Misc.free(payload);
123+
Misc.free(header);
124+
Misc.free(segments);
125+
throw t;
126+
}
127+
this.channel = ch;
128+
this.datagramSegments = segments;
129+
this.headerBuffer = header;
130+
this.payloadWriter = payload;
111131
this.maxDatagramSize = maxDatagramSize;
112132
this.trackDatagramEstimate = maxDatagramSize > 0;
113133
}

0 commit comments

Comments
 (0)