locked
StreamSocket with SSL causes crash when using PPL Task in C++

    Question

  • I make a sample that is composed of a SocketStress app in CSharp and a Windows Runtime Component WRC in C++ to show this problem. WRC contains class SocketWrapper that implements a wrapper for StreamSocket with SSL. The SocketStress sample repeatedly calls into WRC to connect to a SSL server in a blocking way and dispose the SocketWrapper object to release the memory and TCP connection.

            Windows::Networking::HostName ^ hostname = ref new Windows::Networking::HostName(remoteAddr);
            Windows::Foundation::IAsyncAction ^ op = _tcpSocket->ConnectAsync(hostname, remotePort.ToString(), SocketProtectionLevel::Ssl);
            concurrency::task<void> connectTask(op);
            connectTask.wait();

    More source code are posted at the end.

    Observations:

      • The sample will crash after certain amount of iterations and throws exception:

    First-chance exception at 0x0000000000000000 in SocketStress.exe: 0xC0000005: Access violation executing location 0x0000000000000000.

    Unhandled exception at 0x0000000000000000 in SocketStress.exe: 0xC0000005: Access violation executing location 0x0000000000000000.

    2. The crash stack trace is as follows:
    0000000000000000() Unknown
    ntdll.dll!TppWorkerThread() Unknown
    kernel32.dll!BaseThreadInitThunk‑() Unknown
    ntdll.dll!RtlUserThreadStart‑() Unknown

    3. The crash happens sooner when more concurrent clients are running. In my sample, when 2 clients are started to concurrently connect to the server, and it takes just a few iteration for the sample to crash. When the number of client is 1, it may take up to a few hundred iterations to produce the crash.

    4. I did not see the crash when without SSL.

    ======= CSharp code : MainPage.xmal.cs ============

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    using System.Threading;
    using WRC;

    namespace SocketStress
    {
        public sealed partial class MainPage : Page
        {
            const int Clients = 2;
            const string DomainAddress = "rdvs.alljoyn.org";
            const string RawAddress = "192.190.109.114";
            bool ssl = true;
            Task[] _clientTasks = new Task[Clients];
            int _successCount = 0;
            int _failCount = 0;
            volatile int clientsRunning = 0;

            public MainPage()
            {
                this.InitializeComponent();
            }

            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }

            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
             
            }

            private  void Button_Click_2(object sender, RoutedEventArgs e)
            {
                if (clientsRunning != 0)
                {
                    return;
                }

                // Client start
                for (int c = 0; c < Clients; c++)
                {

                    _clientTasks[c] = new Task(async  () =>
                    {
                        while (true)
                        {

                            SocketWrapper clientSocket = new SocketWrapper();
                                string addr;
                                int port = 0;
                                if (!ssl)
                                {
                                    addr = RawAddress;
                                    port = 80;
                                }
                                else
                                {
                                    addr = DomainAddress;
                                    port = 443;
                                }
                                clientSocket.Connect(addr, port);
                                bool success = true;
                                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                                    {
                                        if (success)
                                        {
                                            successCount.Text = (++_successCount).ToString();
                                        }
                                        else
                                        {
                                            failCount.Text = (++_failCount).ToString();
                                        }
                                    });
                              clientSocket.Dispose();
                        }
                    });
                    _clientTasks[c].Start();
                }
            }
        }
    }

    ======= C++ code : SocketWrapper.h ============

    #pragma once

    namespace WRC
    {
        public ref class SocketWrapper sealed
        {
        public:
            SocketWrapper();
         void SocketWrapper::Connect(Platform::String ^ remoteAddr, int remotePort);
            virtual ~SocketWrapper();
      void SocketWrapper::Close();
     private:
          Windows::Networking::Sockets::StreamSocket ^ _tcpSocket;
        };
    }

    ======= C++ code : SocketWrapper.cpp ============

    #include "pch.h"
    #include "SocketWrapper.h"
    #include "ppltasks.h"

    using namespace WRC;
    using namespace Platform;
    using namespace Windows::Foundation;
    using namespace Windows::Networking::Sockets;
    using namespace Windows::Storage::Streams;

    SocketWrapper::SocketWrapper()
    {
        if (nullptr == _tcpSocket) {
            _tcpSocket = ref new StreamSocket();
        }
    }

    void SocketWrapper::Connect(Platform::String ^ remoteAddr, int remotePort)
    {
        try {
            Windows::Networking::HostName ^ hostname = ref new Windows::Networking::HostName(remoteAddr);
            Windows::Foundation::IAsyncAction ^ op = _tcpSocket->ConnectAsync(hostname, remotePort.ToString(), SocketProtectionLevel::Ssl);
            try {
                concurrency::task<void> connectTask(op);
                connectTask.wait();
            } catch (Platform::COMException ^ ex) {
                auto m = ex->Message;
            } catch (...) {
            }
        }catch (...) {
        }
    }

    void SocketWrapper::Close()
    {
     if(_tcpSocket != nullptr) {
      delete _tcpSocket;
      _tcpSocket = nullptr;
     }
    }

    SocketWrapper::~SocketWrapper() {
     Close();
    }

    Thursday, October 4, 2012 6:06 PM

Answers

  • The problem seems gone after installing the cumulative udate released on 10/09/2012
    • Marked as answer by Jesse Jiang Thursday, October 11, 2012 2:25 AM
    Wednesday, October 10, 2012 9:00 PM

All replies