Skip to content

Conversation

@dantraMSFT
Copy link
Contributor

Issue #4029 exposed two problems when failing to load libpsrpclient.

  • WSManAPIDataCommon.ctor was not identifying the binary that failed DLLImport; hindering diagnosability
  • PrioritySendDataCollection.Clear() would throw a NullReferenceException when called from the finalizer after an error path.

This change addresses both of the above:

  • Guard against null arrays in PrioritySendDataCollection.Clear() - called from finalizer in error paths.

  • Diagnosability: Log the DllNotFoundException in WSManAPIDataCommon ctor and also include it as the internal exception when throwing PSRemotingTransportException.

@dantraMSFT
Copy link
Contributor Author

@mirichmo and @PaulHigin will either of you be able to look at this?

Copy link

@anmenaga anmenaga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave a comment

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field is different from array "_syncObjects" only by last letter - it is confusing.
It would be good to either add comment for "_syncObjects" array about what it is; or rename "_syncObject"; or both.

Copy link
Contributor Author

@dantraMSFT dantraMSFT Dec 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anmenaga: Actually, after reviewing this logic again, _syncObject is insufficient since it only guards Clear(). Additionally, _syncObjects also appears to be fragile; it guards against individual usage of a given element but assumes the elements are valid; which is the actual problem.

My thinking is _syncObjects should be removed and _syncObject used to serialize access to the set instead of individual members.

Thoughts?

@SteveL-MSFT, @daxian-dbw, @TravisEz13 Guys, would you take a look at this class. My inclincation is to remove the individual locks and lock the set.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dantraMSFT I'm all for simplification, but there should be a reason why they decided to go more complex 'individual-sync-object' route in the first place... Maybe something will deadlock with a single syncObject, and parallel "Add"s won't be able to execute for different DataPriorityTypes (not sure how critical this really is).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, after reviewing this logic again, _syncObject is insufficient since it only guards Clear().

_dataSyncObjects and _dataToBeSent are used in multiple methods, but it appears that there is an assumption that those methods won't be called until the Fragmentor property is set (where both _dataSyncObjects and _dataToBeSent would be initialized). With this assumption, I think it's fine to directly use _dataSyncObjects and _dataToBeSent in methods other than Clear(). But we probably should add a comment about that assumption.

For Clear(), it's possible to be called before Fragmentor being set (in error path), so it's necessary to check _dataSyncObjects for null beforehand.

@TravisEz13
Copy link
Member

also related to issue #5566

@TravisEz13
Copy link
Member

LGTM, but I would like @PaulHigin to have a look.

@TravisEz13
Copy link
Member

@anmenaga Do you want to sign off, or did you just comment?

@anmenaga
Copy link

anmenaga commented Dec 7, 2017

@TravisEz13
The conversation continues about refactoring that Dan proposed; but I think that refactoring (if needs to be done at all) can be done as separate PR.

Copy link

@anmenaga anmenaga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@TravisEz13 TravisEz13 changed the title Handle DLLImport failure of libpsrpclient remoting: Handle DLLImport failure of libpsrpclient Dec 8, 2017
@dantraMSFT
Copy link
Contributor Author

@TravisEz13 This should be ready to merge.

@TravisEz13
Copy link
Member

I've been asked to wait for a review by @PaulHigin or @daxian-dbw

Copy link
Member

@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left two comments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assert should be removed because apparently _dataToBeSent can be null in that error path.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind this comment. It's certainly right to assume _dataToBeSent != null when null != _dataSyncObjects 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can avoid the sync object _syncObject by the following code:

if (null != _dataSyncObjects)
{
    int promptResponseIndex = (int)DataPriorityType.PromptResponse;
    int defaultIndex = (int)DataPriorityType.Default;

    if (_dataToBeSent[promptResponseIndex] != null)
    {
        lock (_dataSyncObjects[promptResponseIndex])
        {
            if (_dataToBeSent[promptResponseIndex] != null)
            {
                _dataToBeSent[promptResponseIndex].Dispose();
                _dataToBeSent[promptResponseIndex] = null;
            }
        }
    }

    if (_dataToBeSent[defaultIndex] != null)
    {
        lock (_dataSyncObjects[defaultIndex])
        {
            if (_dataToBeSent[defaultIndex] != null)
            {
                _dataToBeSent[defaultIndex].Dispose();
                _dataToBeSent[defaultIndex] = null;
            }
        }
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right; I'll make the change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

…WSManAPIDataCommon.ctor was not identifying the binary that failed DLLImport and PrioritySendDataCollection.Clear() would throw a NullReferenceException when called from the finalizer after an error path.

This change addresses both of the above but does not address the DllImport failure.

* Guard against null arrays in PrioritySendDataCollection.Clear() - called from finalizer in error paths.
* Diagnosability: Log DllNotFoundException in WSManAPIDataCommon ctor and also include as the internal exception when throwing PSRemotingTransportException.
@dantraMSFT
Copy link
Contributor Author

@daxian-dbw do you have any additional feedback?

@dantraMSFT
Copy link
Contributor Author

@PaulHigin, @daxian-dbw, please take a look at this; it's marked as GA. Thanks.

@SteveL-MSFT SteveL-MSFT added this to the 6.0.0-GA milestone Jan 4, 2018
@daxian-dbw daxian-dbw dismissed their stale review January 4, 2018 05:02

My comments have been addressed

@TravisEz13 TravisEz13 merged commit 5488131 into PowerShell:master Jan 4, 2018
@dantraMSFT dantraMSFT deleted the dantra/issue4029 branch January 4, 2018 21:36
lock (_syncObjects[(int)DataPriorityType.Default])
{
_dataToBeSent[(int)DataPriorityType.Default].Dispose();
lock (_dataSyncObjects[promptResponseIndex])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review. I am not familiar with the error path but if _dataToBeSent array can contain null entries then it seems like so can _dataSyncObjects (_dataSyncObjects[promptResponseIndex] == null ?).

It seems like these arrays should be created in the PrioritySendDataCollection constructor...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PaulHigin: _dataSyncObjects is populated when it is created. The entries are not null if the array is not null.
As far as when it is created, it appears the intent was to create both arrays at the same point. I saw no strong reason to change it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the _dataSyncObjects array is filled within a loop:

for (int i = 0; i < names.Length; i++)
    {
        _dataToBeSent[i] = new SerializedDataStream(_fragmentor.FragmentSize);
        _dataSyncObjects[i] = new object();
    }

If an exception is thrown within the loop then it is possible an array element is null. Is this not the error path we are worried about?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SerializedDataStream's ctor does not currently throw.

Note that it should (it relies on Dbg.Assert) and I opened an issue for this: #5800

TravisEz13 pushed a commit to TravisEz13/PowerShell that referenced this pull request Jan 5, 2018
Issue PowerShell#4029 exposed two problems when failing to load libpsrpclient.

WSManAPIDataCommon.ctor was not identifying the binary that failed DLLImport; hindering diagnosability
PrioritySendDataCollection.Clear() would throw a NullReferenceException when called from the finalizer after an error path.
This change addresses both of the above:

Guard against null arrays in PrioritySendDataCollection.Clear() - called from finalizer in error paths.

Diagnosability: Log the DllNotFoundException in WSManAPIDataCommon ctor and also include it as the internal exception when throwing PSRemotingTransportException.
TravisEz13 pushed a commit that referenced this pull request Jan 5, 2018
Issue #4029 exposed two problems when failing to load libpsrpclient.

WSManAPIDataCommon.ctor was not identifying the binary that failed DLLImport; hindering diagnosability
PrioritySendDataCollection.Clear() would throw a NullReferenceException when called from the finalizer after an error path.
This change addresses both of the above:

Guard against null arrays in PrioritySendDataCollection.Clear() - called from finalizer in error paths.

Diagnosability: Log the DllNotFoundException in WSManAPIDataCommon ctor and also include it as the internal exception when throwing PSRemotingTransportException.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants