18 January, 2017

The unexpected behavior of std::mutex

Hi there, this time I would like to tell about the issue in Microsoft implementation of std::mutex for VS2013. This night I spent in deep debugging trying to understand why my test is failing with std::mutex. but isn't failing with boost::mutex. The only difference was in calling DllMain() for my DLL. It was looked like somebody secretly called LoadLibrary() during std::mutex::lock(). I was very surprised when found that it's truth (Important: our product has static linking with Microsoft CRT):

26 October, 2016

Trampolines for hooking

Here I would like to show all variants of trampolines which I know.

32-bits Intel architecture (x86):

; 5 code bytes
; relative addressing
; no registers modification
; EIP+78563412h == 0019fa9ah+78563412h == 78702each
0019fa95 e912345678 jmp 78702each
0019fa9a
; 6 code bytes
; absolute addressing
; no registers modification
0019fa95 6812345678 push 78563412h
0019fa9a c3         ret
0019fa9b
; 8 code bytes
; absolute addressing
; EAX value lost
0019fa95 c7c012345678 mov eax,78563412h
0019fa9b ffe0         jmp eax
0019fa9d
; 6 code bytes + 4 data bytes
; absolute addressing
; no registers modification
; data in execution code
; absolute data addressing
0019fa95 ff259bfa1900 jmp dword ptr ds:[19FA9Bh]
0019fa9b 12345678     dd  78563412h
0019fa9f

64-bits AMD architecture (amd64 / x86_64 / x64):

; 14 code bytes
; absolute addressing
; no registers modification
00000000`0014f605 6812345678       push 78563412h
00000000`0014f60a c74424049abcdef0 mov  dword ptr [rsp+4],0F0DEBC9Ah 
00000000`0014f612 c3               ret
00000000`0014f613
; 6 code bytes
; absolute addressing in lower 4Gb
; no registers modification
00000000`0014f605 6812345678 push 78563412h
00000000`0014f60a c3         ret
00000000`0014f60b
; 12 code bytes
; absolute addressing
; change RAX (return value register)
00000000`0014f605 48b8123456789abcdef0 mov  rax,0F0DEBC9A78563412h
00000000`0014f60f ffe0                 jmp  rax
00000000`0014f611
; 13 code bytes
; absolute addressing
; change R11 (temporary register)
00000000`0014f605 49bb123456789abcdef0 mov r11,0F0DEBC9A78563412h
00000000`0014f60f 41ffe3               jmp r11
00000000`0014f612
; 6 code bytes + 8 data bytes in range RIP±2Gb
; absolute addressing
; no registers modification
; data in execution code
; relative data addressing
; RIP+00000000h == 00000000`0014f60bh+00000000h == 00000000`0014f60bh
00000000`0014f605 ff2500000000     jmp qword ptr [00000000`0014f60bh]
00000000`0014f60b 123456789abcdef0 dq  0F0DEBC9A78563412h
00000000`0014f613
; 5 code bytes
; relative addressing RIP±2Gb
; no registers modification
; EIP+78563412h == 00000000`0014f60ah+78563412h == 00000000`786b2a1ch
00000000`0014f605 e912345678 jmp 00000000`786b2a1ch
00000000`0014f60a

P.S. Please let me know if you have new variant.

09 July, 2016

Solve the "no GUID has been associated with this object" compiler error for __uuidof in templates instantinations

As you know WinRT has C++ interfaces ABI::Windows::Foundation::Collections::IIterable and ABI::Windows::Foundation::Collections::IIterable to make iteration in collections universal. This is the very good idea, but you got interfaces with templates: (see windows.foundation.collections.h):

namespace ABI {
namespace Windows {
namespace Foundation {
namespace Collections { 

    template <class T> 
    struct IIterator 
        : IIterator_impl<T>
        , detail::not_yet_specialized<IIterator<T>>
    {
    };

    template <class T> 
    struct IIterable
        : IIterable_impl<T>
        , detail::not_yet_specialized<IIterable<T>>
    {
    };

    template <class T, bool isStruct>
    struct IIterator_impl : IInspectable
    {
    private:
        typedef typename Windows::Foundation::Internal::GetAbiType<T>::type     T_abi;
        typedef typename Windows::Foundation::Internal::GetLogicalType<T>::type T_logical;
    public:
        typedef T                                                               T_complex;

        virtual /* propget */ HRESULT STDMETHODCALLTYPE get_Current(_Out_ T_abi *current) = 0;
        virtual /* propget */ HRESULT STDMETHODCALLTYPE get_HasCurrent(_Out_ boolean *hasCurrent) = 0;
        virtual HRESULT STDMETHODCALLTYPE MoveNext(_Out_ boolean *hasCurrent) = 0;
        virtual HRESULT STDMETHODCALLTYPE GetMany(_In_ unsigned capacity, _Out_writes_to_(capacity,*actual) T_abi *value, _Out_ unsigned *actual) = 0;
    };

    template <class T>
    struct IIterable_impl : IInspectable
    {
    private:
        typedef typename Windows::Foundation::Internal::GetAbiType<T>::type     T_abi;
        typedef typename Windows::Foundation::Internal::GetLogicalType<T>::type T_logical;
    public:
         typedef T                                                               T_complex;

        virtual HRESULT STDMETHODCALLTYPE First(_Outptr_result_maybenull_ IIterator<T_logical> **first) = 0;
    };

}}}}

18 September, 2015

How to load strong named assembly from the location out of application base directory to new application domain

I found the only one decision: dynamically generate the configuration file in temporary folder:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="YYY" culture="" publicKeyToken="0123456789012345" />
        <codeBase version="K.L.M.N" href="file:///X:/XXX/YYY.DLL" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="ZZZ" culture="" publicKeyToken="1234567890123456" />
        <codeBase version="A.B.C.D" href="file:///X:/XXX/ZZZ.DLL" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>
And set it to AppDomainSetup.ConfigurationFile:
var appDomain = AppDomain.CreateDomain("MyDomain", null, new AppDomainSetup
  {
    ConfigurationFile = configFile
  });

07 September, 2014

Powershell script to close mercurial branches older then 60 days

GitHub link
# Close old branches for Mercurial
# Copyright (C) 2014  Mikhail Pilin
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

if ($PSVersionTable.PSVersion.Major -lt 3) {
  throw "PS Version $($PSVersionTable.PSVersion) is below 3.0."
}

Set-StrictMode -Version Latest
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
$script:VerbosePreference = "Continue"

$encoding = "cp866"
[System.TimeSpan]$alive = [System.TimeSpan]::FromDays(60)
[System.DateTime]$now = [System.DateTime]::Now

[System.Object]$current = & hg parent --encoding $encoding -T "{node} {branch}" | ForEach-Object {
    $result = $_ | Select-Object -Property node, name
    $parts = $_.Split(' ', 2)
    
    $result.node = $parts[0]
    $result.name = $parts[1]
    $result
  } | Select-Object

Write-Host "Current branch: " -nonewline
Write-Host -foregroundcolor gray $current.name

[System.Object[]]$branches = @(& hg head --encoding $encoding -T "{date(date,'%Y%m%d%H%M%S')} {node} {branch}\n" | ForEach-Object {
    $result = $_ | Select-Object -Property date, node, name
    $parts = $_.Split(' ', 3)

    [System.DateTime]$result.date = [System.DateTime]::ParseExact($parts[0], "yyyyMMddHHmmss", [System.Globalization.CultureInfo]::InvariantCulture)
    $result.node = $parts[1]
    $result.name = $parts[2]
    $result
  } | Where-Object { $now - $_.date -gt $alive } | Sort-Object -property date)

function EscapeBranchName
{
  Param([System.String]$name)
  $name.Replace('"', '\"')
}

if ($branches.Length -eq 0) { Write-Host "No old branches were detected" } else {
  Write-Host "Closing $($branches.Length) old branches:"

  $branches | ForEach-Object {
      Write-Host "[$([System.String]::Format("{0:%d}", $now - $_.date)) days] " -nonewline
      Write-Host -foregroundcolor gray $_.name

      & hg debugsetparent $_.node | Out-Null
      if ($LastExitCode -ne 0) { Write-Warning "Failed to set node (exit code $LastExitCode)." } else {
        & hg branch $(EscapeBranchName $_.name) | Out-Null
        if ($LastExitCode -ne 0) { Write-Warning "Failed to set branch (exit code $LastExitCode)." } else {
          & hg commit --close-branch -X * -m $("The branch was not used for {0:%d} days and closed automatically." -f ($now - $_.date)) | Out-Null
          if ($LastExitCode -ne 0) { Write-Warning "Failed to commit (exit code $LastExitCode)." }
        }
      }
    }

  Write-Host "Restore current branch: " -nonewline
  Write-Host -foregroundcolor gray $current.name

  & hg debugsetparent $current.node | Out-Null
  if ($LastExitCode -ne 0) { Write-Warning "Failed to set node (exit code $LastExitCode)." } else {
    & hg branch $(EscapeBranchName $current.name) | Out-Null
    if ($LastExitCode -ne 0) { Write-Warning "Failed to set branch (exit code $LastExitCode)." }
  }
}

02 March, 2014

Decoding the parameters of a thrown C++ exception (0xE06D7363)

I have a lot questions after reading the post about decoding structural exception 0xE06D7363 from "The Old New Thing". I like computer magic like that: take address from here add the constant two and half time and you get it. However, this magic don't help to understand how it really works and what happened if I do that. So, following code from CRT kill all magic.

06 November, 2013

How to install .NET Framework 1.1 on Windows 8.1

After update from Windows 8.0 to Windows 8.1 I found that .NET Framework 1.1 was unexpectedly disappeared. Here I give you the tested way to return it back:

  • Download .NET Framework Cleanup Tool (product guide here) from following locations: here or here
  • Unzip and run following commands:
    cleanup_tool.exe /q:a /c:"cleanup.exe /p .NET Framework 1.0"
    cleanup_tool.exe /q:a /c:"cleanup.exe /p .NET Framework 1.1"
    
  • Following instructions were taken from here:
    • Create a new folder named DotNet in C:\ drive. (The path i used was C:\DotNet)
    • Download Microsoft .NET Framework 1.1 Redistributable Package (dotnetfx.exe). Make sure the setup file is saved as dotnetfx.exe.
    • Download Microsoft .NET Framework 1.1 Service Pack 1 (NDP1.1sp1-KB867460-X86.exe). Rename the file to dotnetfxsp1.exe.
    • Copy both installation files into the same directory (i.e. C:\DotNet),.
    • Open Command Prompt as Administrator.
    • Change to the directory where the two installation files are stored, ie C:\DotNet.
    • Run the following commands one by one:
      dotnetfx.exe /c:"msiexec.exe /a netfx.msi TARGETDIR=C:\DotNet"
      dotnetfxsp1.exe /Xp:C:\DotNet\netfxsp.msp
      msiexec.exe /a c:\DotNet\netfx.msi /p c:\DotNet\netfxsp.msp
      
    • Install Microsoft .Net Framework 1.1 with slipstreamed Service Pack 1 by running netfx.msi from the working folder.

Good luck!

07 June, 2013

Tricky macro to add file name and line number in C++ operator new

Header file:

#if defined(_DEBUG)
  #define _CRTDBG_MAP_ALLOC

  #include <crtdbg.h>

  extern __declspec(thread) char const * t_File;
  extern __declspec(thread) int t_Line;

  inline void * __CRTDECL operator new  (size_t const size) { return ::operator new  (size, _NORMAL_BLOCK, t_File, t_Line); }
  inline void * __CRTDECL operator new[](size_t const size) { return ::operator new[](size, _NORMAL_BLOCK, t_File, t_Line); }

  #define new (t_File = __FILE__, t_Line = __LINE__, false) ? nullptr : new
#endif
Source file:
#if defined(_DEBUG)
  __declspec(thread) char const * t_File = "???";
  __declspec(thread) int t_Line = 0;
#endif

This macro doesn't work with direct operator call like operator new(...) in code.

P.S. This macro tested only on Visual Studio 2012