Below: callstack, data of LDAP* conn, relevant code, description of the
data and code, workaround.
my_app_1!closesocket
my_app_1!sb_stream_close+0x21
my_app_1!ber_int_sb_close+0x1e
my_app_1!ldap_free_connection+0x28d
my_app_1!ldap_ld_free+0x51
+0x000 conn : 0x0523fa80 ldap
+0x000 ld_sb : 0x0526b3b8 sockbuf
+0x000 sb_opts : lber_options
+0x000 lbo_valid : 0n3
+0x002 lbo_options : 0
+0x004 lbo_debug : 0n0
+0x008 sb_iod : 0x05259dd8 sockbuf_io_desc
+0x000 sbiod_level : 0n10
+0x004 sbiod_sb : 0x0526b3b8 sockbuf
+0x000 sb_opts : lber_options
+0x000 lbo_valid : 0n3
+0x002 lbo_options : 0
+0x004 lbo_debug : 0n0
+0x008 sb_iod : 0x05259dd8 sockbuf_io_desc
+0x000 sbiod_level : 0n10
+0x004 sbiod_sb : 0x0526b3b8 sockbuf
+0x008 sbiod_io : 0x0091ef88 sockbuf_io
+0x00c sbiod_pvt : (null)
+0x010 sbiod_next : 0x0520c380 sockbuf_io_desc
+0x00c sb_fd : 0x1534
+0x010 sb_max_incoming : 0
+0x014 sb_trans_needs_read : 0y0
+0x014 sb_trans_needs_write : 0y0
+0x008 sbiod_io : 0x0091ef88 sockbuf_io
+0x000 sbi_setup : 0x006ace40 int
my_app_1!sb_fd_setup+0
+0x004 sbi_remove : (null)
+0x008 sbi_ctrl : 0x0052cdd0 int
my_app_1!mbufFlush+0
+0x00c sbi_read : 0x006acdd0
long my_app_1!sb_stream_read+0
+0x010 sbi_write : 0x006acdf0
long my_app_1!sb_stream_write+0
+0x014 sbi_close : 0x006ace10 int
my_app_1!sb_stream_close+0
+0x00c sbiod_pvt : (null)
+0x010 sbiod_next : 0x0520c380 sockbuf_io_desc
+0x000 sbiod_level : 0n10
+0x004 sbiod_sb : 0x0526b3b8 sockbuf
+0x000 sb_opts : lber_options
+0x008 sb_iod : 0x05259dd8 sockbuf_io_desc
+0x00c sb_fd : 0x1534
+0x010 sb_max_incoming : 0
+0x014 sb_trans_needs_read : 0y0
+0x014 sb_trans_needs_write : 0y0
+0x008 sbiod_io : 0x0091ef88 sockbuf_io
+0x000 sbi_setup :
0x006ace40 int my_app_1!sb_fd_setup+0
+0x004 sbi_remove : (null)
+0x008 sbi_ctrl :
0x0052cdd0 int my_app_1!mbufFlush+0
+0x00c sbi_read :
0x006acdd0 long my_app_1!sb_stream_read+0
+0x010 sbi_write :
0x006acdf0 long my_app_1!sb_stream_write+0
+0x014 sbi_close :
0x006ace10 int my_app_1!sb_stream_close+0
+0x00c sbiod_pvt : (null)
+0x010 sbiod_next : (null)
+0x00c sb_fd : 0x1534
+0x010 sb_max_incoming : 0
+0x014 sb_trans_needs_read : 0y0
+0x014 sb_trans_needs_write : 0y0
(etc.)
ber_int_sb_close():
p = sb->sb_iod;
while ( p ) {
if ( p->sbiod_io->sbi_close&& p->sbiod_io->sbi_close( p )< 0 ) {
return -1;
}
p = p->sbiod_next;
}
sb_stream_close( Sockbuf_IO_Desc *sbiod ):
tcp_close( sbiod->sbiod_sb->sb_fd );
So the socket number 0x1534 was closed twice in rapid succession,
because there are 2 linked list nodes, both with the same sb_fd
(actually, both sbiod_sb point to 0x0526b3b8 sockbuf, which is their
"parent" a.k.a. conn->ld_sb, i.e.
conn->ld_sb->sb_iod->sbiod_sb == conn->ld_sb
and also == conn->ld_sb->sb_iod->sbiod_next->sbiod_sb).
The question is how/when the sbiod_next was added.
A dirty workaround would be to detect this special case in
ber_int_sb_close(), but I'd strongly prefer to fix the problem.
p = sb->sb_iod;
while ( p ) {
if ( p->sbiod_io->sbi_close&& p->sbiod_io->sbi_close(
p )< 0 ) {
return -1;
}
+ // workaround for double-closesocket:
+ while (p->sbiod_next
// there's another sbiod
+&& (p->sbiod_next->sbiod_sb == p->sbiod_sb) // points to the same
socket
+&& (p->sbiod_next->sbiod_io == p->sbiod_io) // same functions used
+&& (p->sbiod_io->sbi_close == sb_stream_close) // tcp
+ ) {
+ p = p->sbiod_next; // skip, don't close it
again
+ }
+ // end of workaround
p = p->sbiod_next;
}