Skip to content

Commit 90e848b

Browse files
miroslavpokornyRob-Hague
authored andcommitted
🐛 AsyncResult contains invalid value
- AsyncResult should contain invalid value immediately after async operation is marked as completed - there was race condition problems with callback method which is invoked on different thread so updating of value is done without any synchronization. So in some cases async operation is marked as completed but async result value is not yet updated and contains invalid value
1 parent f28c2c2 commit 90e848b

File tree

1 file changed

+13
-20
lines changed

1 file changed

+13
-20
lines changed

src/Renci.SshNet/SftpClient.cs

+13-20
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ public IEnumerable<ISftpFile> ListDirectory(string path, Action<int> listCallbac
584584
{
585585
CheckDisposed();
586586

587-
return InternalListDirectory(path, listCallback);
587+
return InternalListDirectory(path, asyncResult: null, listCallback);
588588
}
589589

590590
#if FEATURE_ASYNC_ENUMERABLE
@@ -669,12 +669,7 @@ public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback,
669669
{
670670
try
671671
{
672-
var result = InternalListDirectory(path, count =>
673-
{
674-
asyncResult.Update(count);
675-
676-
listCallback?.Invoke(count);
677-
});
672+
var result = InternalListDirectory(path, asyncResult, listCallback);
678673

679674
asyncResult.SetAsCompleted(result, completedSynchronously: false);
680675
}
@@ -899,12 +894,7 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback
899894
{
900895
try
901896
{
902-
InternalDownloadFile(path, output, asyncResult, offset =>
903-
{
904-
asyncResult.Update(offset);
905-
906-
downloadCallback?.Invoke(offset);
907-
});
897+
InternalDownloadFile(path, output, asyncResult, downloadCallback);
908898

909899
asyncResult.SetAsCompleted(exception: null, completedSynchronously: false);
910900
}
@@ -1132,11 +1122,7 @@ public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride,
11321122
{
11331123
try
11341124
{
1135-
InternalUploadFile(input, path, flags, asyncResult, offset =>
1136-
{
1137-
asyncResult.Update(offset);
1138-
uploadCallback?.Invoke(offset);
1139-
});
1125+
InternalUploadFile(input, path, flags, asyncResult, uploadCallback);
11401126

11411127
asyncResult.SetAsCompleted(exception: null, completedSynchronously: false);
11421128
}
@@ -2200,7 +2186,7 @@ private IEnumerable<FileInfo> InternalSynchronizeDirectories(string sourcePath,
22002186

22012187
#region Existing Files at The Destination
22022188

2203-
var destFiles = InternalListDirectory(destinationPath, listCallback: null);
2189+
var destFiles = InternalListDirectory(destinationPath, asyncResult: null, listCallback: null);
22042190
var destDict = new Dictionary<string, ISftpFile>();
22052191
foreach (var destFile in destFiles)
22062192
{
@@ -2267,13 +2253,14 @@ private IEnumerable<FileInfo> InternalSynchronizeDirectories(string sourcePath,
22672253
/// Internals the list directory.
22682254
/// </summary>
22692255
/// <param name="path">The path.</param>
2256+
/// <param name="asyncResult">An <see cref="IAsyncResult"/> that references the asynchronous request.</param>
22702257
/// <param name="listCallback">The list callback.</param>
22712258
/// <returns>
22722259
/// A list of files in the specfied directory.
22732260
/// </returns>
22742261
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <b>null</b>.</exception>
22752262
/// <exception cref="SshConnectionException">Client not connected.</exception>
2276-
private IEnumerable<ISftpFile> InternalListDirectory(string path, Action<int> listCallback)
2263+
private IEnumerable<ISftpFile> InternalListDirectory(string path, SftpListDirectoryAsyncResult asyncResult, Action<int> listCallback)
22772264
{
22782265
if (path is null)
22792266
{
@@ -2309,6 +2296,8 @@ private IEnumerable<ISftpFile> InternalListDirectory(string path, Action<int> li
23092296
f.Value));
23102297
}
23112298

2299+
asyncResult?.Update(result.Count);
2300+
23122301
// Call callback to report number of files read
23132302
if (listCallback is not null)
23142303
{
@@ -2375,6 +2364,8 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR
23752364

23762365
totalBytesRead += (ulong) data.Length;
23772366

2367+
asyncResult?.Update(totalBytesRead);
2368+
23782369
if (downloadCallback is not null)
23792370
{
23802371
// copy offset to ensure it's not modified between now and execution of callback
@@ -2447,6 +2438,8 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo
24472438
_ = Interlocked.Decrement(ref expectedResponses);
24482439
_ = responseReceivedWaitHandle.Set();
24492440

2441+
asyncResult?.Update(writtenBytes);
2442+
24502443
// Call callback to report number of bytes written
24512444
if (uploadCallback is not null)
24522445
{

0 commit comments

Comments
 (0)