Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If statement evaluates to false but still branches as if it was true

Tags:

I am quite stumped. In an async method, I have a few initial guard statements, that throw exceptions if specific conditions are met.

One of them is the following:

var txPagesCount = _transactionPages.Count;
if (txPagesCount == 0)
    throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));

This is supposed to ensure there are pages in the _transactionPages dictionary and throw if there are none.

This is what happens when I run it (release and debug build, debugger attached):

Number of pages is 3

So the number of pages in the dictionary is 3.

if statement evaluates to false

And so, as expected, the if statement comparing 3 to 0 evaluates to false.

But then, when stepping further:

Steps into the branch

It steps into the branch as if the if statement evaluated to true, and throws the exception.

What am I missing here?

UPDATE

When I do this:

private static readonly object _globalLock = new object();

public async Task<Checkpoint> CommitAsync(PageNumber dataRoot, PageNumber firstUnusedPage)
{
    lock (_globalLock)
    {
        if (IsCompleted)
            throw new InvalidOperationException(string.Format("Cannot commit completed transaction {0}", _txId));
        var txPagesCount = _transactionPages.Count;
        if (txPagesCount == 0)
            throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
    }

the if statement does not branch to throw the exception. This is the case for both debug and release build. Is something messing up the call stack? Also, if instead of the lock I add System.Threading.Thread.MemoryBarrier(); after the if statement, it will not go into the branch.

UPDATE 2

The mystery becomes a bit larger. It is almost as if c++ scoping rules are used :D The code below (in debug build) will show the expected behavior: not go into the branch and not throw. In release build, it will go into the branch and throw just as before.

private static readonly object _globalLock = new object();

public async Task<Checkpoint> CommitAsync(PageNumber dataRoot, PageNumber firstUnusedPage)
{
    //lock (_globalLock)
    {
        if (IsCompleted)
            throw new InvalidOperationException(string.Format("Cannot commit completed transaction {0}", _txId));
        var txPagesCount = _transactionPages.Count;
        if (txPagesCount == 0)
            throw new InvalidOperationException(string.Format("Cannot commit transaction {0}. It is empty.", _txId));
    }

If I comment out the "scoping braces" it will go into the branch and throw the exception (as in my original images).

FINAL? UPDATE

Well that sucks. I made a few changes to unrelated areas of code and now I am no longer able to reproduce the problem.