Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String Length Evaluating Incorrectly

Tags:

string

c#

wcf

My coworker and I are debugging an issue in a WCF service he's working on where a string's length isn't being evaluated correctly. He is running this method to unit test a method in his WCF service:

// Unit test method
public void RemoveAppGroupTest()
{
    string addGroup = "TestGroup";
    string status = string.Empty;
    string message = string.Empty;

    appActiveDirectoryServicesClient.RemoveAppGroup("AOD", addGroup, ref status, ref message);
}


// Inside the WCF service
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void RemoveAppGroup(string AppName, string GroupName, ref string Status, ref string Message)
{
    string accessOnDemandDomain = "MyDomain";

    RemoveAppGroupFromDomain(AppName, accessOnDemandDomain, GroupName, ref Status, ref Message);
}

public AppActiveDirectoryDomain(string AppName, string DomainName)
{
    if (string.IsNullOrEmpty(AppName))
    {
        throw new ArgumentNullException("AppName", "You must specify an application name");
    }
}

We tried to step into the .NET source code to see what value string.IsNullOrEmpty was receiving, but the IDE printed this message when we attempted to evaluate the variable: 'Cannot obtain value of local or argument 'value' as it is not available at this instruction pointer, possibly because it has been optimized away.' (None of the projects involved have optimizations enabled). So, we decided to try explicitly setting the value of the variable inside the method itself, immediately before the length check -- but that didn't help.

// Lets try this again.
public AppActiveDirectoryDomain(string AppName, string DomainName)
{
    // Explicitly set the value for testing purposes.
    AppName = "AOD";

    if (AppName == null)
    {
        throw new ArgumentNullException("AppName", "You must specify an application name");
    }

    if (AppName.Length == 0)
    {
        // This exception gets thrown, even though it obviously isn't a zero length string.
        throw new ArgumentNullException("AppName", "You must specify an application name");
    }
}

We're really pulling our hair out on this one. Has anyone else experienced behavior like this? Any tips on debugging it?


Here's the MSIL for the AppActiveDirectoryDomain object, where the behavior is occuring:

.method public hidebysig specialname rtspecialname instance void .ctor(string AppName, string DomainName) cil managed
{
.maxstack 5
.locals init (
    [0] class [System]System.Net.NetworkCredential ldapCredentials,
    [1] string[] creds,
    [2] string userName,
    [3] class [mscorlib]System.ArgumentNullException exc,
    [4] class [System.DirectoryServices]System.DirectoryServices.ActiveDirectory.DirectoryContext directoryContext,
    [5] class [System.DirectoryServices]System.DirectoryServices.ActiveDirectory.Domain domain,
    [6] class [System.DirectoryServices.Protocols]System.DirectoryServices.Protocols.LdapException V_6,
    [7] class [mscorlib]System.Exception V_7,
    [8] bool CS$4$0000,
    [9] char[] CS$0$0001,
    [10] string[] CS$0$0002)
L_0000: ldarg.0 
L_0001: ldsfld string [mscorlib]System.String::Empty
L_0006: stfld string MyNamespace.MyClass.AppActiveDirectoryDomain::appOU
L_000b: ldarg.0 
L_000c: call instance void [mscorlib]System.Object::.ctor()
L_0011: nop 
L_0012: nop 
L_0013: ldstr "AOD"
L_0018: call bool [mscorlib]System.String::IsNullOrEmpty(string)
L_001d: ldc.i4.0 
L_001e: ceq 
L_0020: stloc.s CS$4$0000
L_0022: ldloc.s CS$4$0000
L_0024: brtrue.s L_0037
L_0026: nop 
L_0027: ldstr "AppName"
L_002c: ldstr "You must specify an application name"
L_0031: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string, string)
L_0036: throw

And the MSIL for the string.IsNullOrEmpty call:

.method public hidebysig static bool IsNullOrEmpty(string 'value') cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: brfalse.s L_000d
    L_0003: ldarg.0 
    L_0004: callvirt instance int32 System.String::get_Length()
    L_0009: ldc.i4.0 
    L_000a: ceq 
    L_000c: ret 
    L_000d: ldc.i4.1 
    L_000e: ret 
}

Edit:

Here is a screenshot of the variable in the 'Watch' window at the moment the ArgumentNullException is thrown: http://imgur.com/xQm4J.png

Also, a second screenshot showing the exception being thrown when checking the length of the string, after explicitly declaring it 5 lines above: http://imgur.com/lSrk9.png

Update #3: We tried changing the name of the local variable and it passes the null check and the length check, but fails when we call string.IsNullOrEmpty. See this screenshot: http://imgur.com/Z57AA.png.


Responses:

  • We don't use any tools that would modify the MSIL. We've performed a cleanup, and also manually deleted all files from the build directories, and forced a rebuild... same outcome.

  • The following statement evaluates as true and enters the if block: if (string.IsNullOrEmpty("AOD")) { /* */ }.

  • The constructor is called like so:

    try { using (AppActiveDirectoryDomain domain = new AppActiveDirectoryDomain(AppName, DomainName)) { } }

This is immediately within the WCF service method itself; AppName and DomainName are parameters to the call. Even bypassing these parameters and using new strings, we still get the errors.


like image 468
Justin Rusbatch Avatar asked Apr 30 '10 17:04

Justin Rusbatch


1 Answers

I have 2 suggestions

  1. Use ILDASM to take a look at the IL that is being generated, possibly post the IL here so the community can take a look

  2. Change the name of the argument 'AppName' to something very different 'xxxAppName' for example.

I know point 2 might seem pointless, but I have in the past come across seemingly unexplainable situations, only to find that something was not being compiled or there was a scope conflict, while the debugger shows what you expect. And, it won't hurt to try :)

like image 65
Chris Taylor Avatar answered Nov 09 '22 00:11

Chris Taylor