[Mono-bugs] [Bug 449300] New: [PATCH] Exceptions in Novell.Directory.Ldap
bugzilla_noreply at novell.com
bugzilla_noreply at novell.com
Wed Nov 26 10:00:52 EST 2008
https://bugzilla.novell.com/show_bug.cgi?id=449300
Summary: [PATCH] Exceptions in Novell.Directory.Ldap
Product: Mono: Class Libraries
Version: SVN
Platform: i386
OS/Version: Linux
Status: NEW
Keywords: patch
Severity: Normal
Priority: P5 - None
Component: System
AssignedTo: mono-bugs at lists.ximian.com
ReportedBy: jlarimer at gmail.com
QAContact: mono-bugs at lists.ximian.com
Found By: ---
Created an attachment (id=255825)
--> (https://bugzilla.novell.com/attachment.cgi?id=255825)
proposed patch
Description of Problem:
-----------------------
The Novell.DirectoryServices.Ldap.Connection class has multiple race conditions
that can cause unhandled exceptions.
There are three big issues I ran into:
1.
// Just before closing the sockets, abort the reader thread
if ((reader != null) && (reason != "reader: thread stopping"))
reader.Abort();
It's possible for reader to be null by the time reader.Abort() is
called,leading to a NullReferenceException.
2. The other issue is that when Abort() is called on the reader thread, there's
no guarantee the thread will be aborted immediately, so it's possible for
shutdown() to close the socket while the reader thread is still trying to read,
which causes an ObjectDisposedException.
If the code is compiled to run under a JVM (TARGET_JVM), the Abort() doesn't
happen and the reader thread catches the ObjectDisposedException. For now, I
think the non-JVM library should work the same way.
3. If there's a SocketException during connect(), freeWriteSemaphore() can get
called twice and will exception the 2nd time. This is because
freeWriteSemaphore() is called in the catch{} blocks and also in the finally{}
block.
Really, all of Connection.cs should be rewritten to use asynchronous I/O
instead of relying on a reader thread and the semaphore implementation, but the
attached patch fixes most of the issues that I ran into with this class.
Steps to reproduce the problem:
-------------------------------
Here's some test code. I ran it against a working Active Directory server,
fiddling with the various values (THREAD_COUNT, THREAD_WAIT) to get different
results. Some of the exceptions I've seen are below in Actual Results.
using System;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices;
using System.Threading;
namespace LdapTest {
class Program {
static readonly int THREAD_SLEEP = 1000;
static readonly int THREAD_COUNT = 50;
static readonly string SERVER = "LDAP://192.168.234.39";
static readonly string USERNAME = "Administrator";
static readonly string PASSWORD = "password123";
static void Main(string[] args) {
for(int i=0; i<THREAD_COUNT; i++) {
ThreadStart ts = new ThreadStart(TheThread);
Thread t = new Thread(ts);
t.Start();
}
}
static void TheThread() {
while(true) {
string path = SERVER;
DirectoryEntry de = null;
DirectorySearcher ds = null;
try {
de = new DirectoryEntry(path, USERNAME, PASSWORD,
AuthenticationTypes.Secure);
ds = new DirectorySearcher(de);
ds.SearchScope = SearchScope.Base;
ds.PropertiesToLoad.Add("defaultNamingContext");
using (SearchResultCollection src = ds.FindAll()) {
foreach (SearchResult sr in src) {
ResultPropertyValueCollection rpvc =
sr.Properties["defaultNamingContext"];
if (rpvc != null) rpvc[0].ToString();
}
}
} finally {
if (ds != null)
ds.Dispose();
if (de != null) {
de.Close();
de.Dispose();
}
}
Thread.Sleep(THREAD_SLEEP);
}
}
}
}
Actual Results:
---------------
Unhandled Exception: System.NullReferenceException: Object reference not set to
an instance of an object
at Novell.Directory.Ldap.Connection.shutdown (System.String reason, Int32
semaphoreId, Novell.Directory.Ldap.InterThreadException notifyUser) [0x0011d]
in /home/jlarimer/mono-dev/m
cs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Connection.cs:1148
at Novell.Directory.Ldap.Connection.destroyClone (Boolean apiCall) [0x0006d]
in
/home/jlarimer/mono-dev/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/Connection.cs:918
at Novell.Directory.Ldap.LdapConnection.Disconnect
(Novell.Directory.Ldap.LdapConstraints cons, Boolean how) [0x00000] in
/home/jlarimer/mono-dev/mcs/class/Novell.Directory.Ldap/No
vell.Directory.Ldap/LdapConnection.cs:2116
at Novell.Directory.Ldap.LdapConnection.Disconnect () [0x00000] in
/home/jlarimer/mono-dev/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/AssemblyInfo.cs:1
at System.DirectoryServices.DirectorySearcher.Dispose (Boolean disposing)
[0x00021] in
/home/jlarimer/mono-dev/mcs/class/System.DirectoryServices/System.DirectoryServices/Directory
Searcher.cs:712
at System.ComponentModel.Component.Dispose () [0x00000] in
/home/jlarimer/mono-dev/mcs/class/System/System.ComponentModel/Component.cs:115
at (wrapper remoting-invoke-with-check)
System.ComponentModel.Component:Dispose ()
at ldaptest.Program.TheThread () [0x00000]
Unhandled Exception: System.SystemException: Connection.freeWriteSemaphore(-2):
semaphore not owned by any thread
at Novell.Directory.Ldap.Connection.freeWriteSemaphore (Int32 msgId)
[0x00000]
at Novell.Directory.Ldap.Connection.connect (System.String host, Int32 port,
Int32 semaphoreId) [0x00000]
at Novell.Directory.Ldap.Connection.connect (System.String host, Int32 port)
[0x00000]
at Novell.Directory.Ldap.LdapConnection.Connect (System.String host, Int32
port) [0x00000]
at System.DirectoryServices.DirectorySearcher.InitBlock () [0x00000]
at System.DirectoryServices.DirectorySearcher.DoSearch () [0x00000]
at System.DirectoryServices.DirectorySearcher.get_SrchColl () [0x00000]
at System.DirectoryServices.DirectorySearcher.FindAll () [0x00000]
at (wrapper remoting-invoke-with-check)
System.DirectoryServices.DirectorySearcher:FindAll ()
at ldaptest.Program.TheThread () [0x00000]
Unhandled Exception: System.ObjectDisposedException: The object was used after
being
disposed.
at System.Net.Sockets.NetworkStream.CheckDisposed () [0x00000]
at System.Net.Sockets.NetworkStream.Read (System.Byte[] buffer, Int32 offset,
Int32
size) [0x00000]
at System.IO.Stream.ReadByte () [0x00000]
at Novell.Directory.Ldap.Asn1.Asn1Identifier..ctor (System.IO.Stream
in_Renamed)
[0x00000]
at Novell.Directory.Ldap.Connection+ReaderThread.Run () [0x00000]
Expected Results:
None of the above exceptions should happen.
How often does this happen?
The issues are mostly race conditions, so they happen randomly depending on the
hardware, platform, etc.
Additional Information:
-----------------------
See attached patch.
--
Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.
More information about the mono-bugs
mailing list