Previous part is here.
Web service
Next step will be to run dotnet application in service that starts with your virtual PC and system will restart it if application crashes. We will create specific user (www.example.com) that will run dotnet application. Why do we need specific user? Answer is quite simple – security.
Let me elaborate on that. Nginx is running from specific user (
www-data). Service will run from another user that we will create (
www.example.com). Surely you can run everything from root account, but if nginx or dotnet has some vulnerability then hacker will get access to whole system. If each service has own quite limited account that not even able to login. Moreover,
[...Read More]
Previous part is here.
Configuring Web Server
I chose nginx as web server because after research it looks like it is gaining a lot of popularity while second contender Apache2 is losing popularity.
First step is to ensure that your web server is working correctly. Because http port is opened in Amazon router and in your virtual PC you should be able to access it from outside from your browser. Just type http://<you static IP address> in your browser and press Enter. You should see standard nginx web page.
Next step is to make sure that nginx will not serve anything that is not specifically added. Edit file /etc/nginx/sites-available/default and replace it content with following:
server {
listen 80 default_server;
listen [::]:80 default_server;
return 444;
}
[...Read More]
Some time ago I needed simple tutorial site. Initially I was thinking about static page hosting and I started research. But during research I found AWS Lightsail service. It cost $3.5 per month and offers 1 vCPU, 512 MB of RAM, 20 GB of SSD space and 1 TB of data transfer. It is about that the same as my current hosting offers but in case of Amazon it is your own virtual PC, and you can do whatever you like there. It looks attractive, but there is one catch. It is Linux. I had some experience with Linux, but it was far from extensive. On another side I really like challenges, so I decided to try it.
But before
[...Read More]
Recently I got relatively simple deadlock case, but I found quite interesting things during investigation. Our application hangs when user tries to quit it. I got dump file for this case and started investigation.
Call stack for main thread looks like this:
...
clr!JITutil_MonContention+0x115
System_ni!System.ComponentModel.Component.Dispose(Boolean)$##60031F8+0x40
System_ni!System.IO.FileSystemWatcher.Dispose(Boolean)$##600266D+0xd7
System_ni!System.IO.FileSystemWatcher.Dispose(Boolean)$##600266D+0xa6
System_ni!System.ComponentModel.Component.Dispose()$##60031F7+0x1a
...
As you clearly see, application waiting in
FileSystemWatcher’s
System.ComponentModel.Component.Dispose. If you go to
https://sourceof.net and paste name of the method there to see source code, you will see that there is
lock(this) and it looks like some other thread obtained lock before us. Obviously, I went over other 168 threads and found 2 similar call stacks. First thread was executing event from first
[...Read More]
Recently I got strange situation in our application. We have two different classes in .NET that exposed to managed code via COM interfaces. Both classes look very similar but one class by some reason supports IDispatch while another class does not. We have piece of code that work quite differently depending on IDispatch support. And was asked to investigate what is going on and why these two classes behave different.
Here is some data. First class looks like this:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Foo : BaseClass1, IDisposable
Second class looks like this:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Bar : BaseClass2, IMyInterface
IMyInterface declared like this:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("XXX")]
If
[...Read More]
Recently I was investigating memory leak in one of our web sites. The same story, site consuming more and more memory until IIS finally recycles it.
As usually, executed two standard commands:
.cordll -ve -u -l
!DumpHeap -stat
And then I found our class Xyz at about 10th place from bottom. Interesting. Then I executed following command:
!DumpHeap -short Namespace.Xyz
And immediately pressed Ctrl+Break to have only few hundred of them and not all of them. And then I executed this command to find how is holding that reference:
!GCRoot <address of Namespace.Xyz object>
From output I found some singleton class with
ConcurrentDictionary<Guid, List< Namespace.Xyz>>.
[...Read More]
I was investigating some dead lock that happens in our application. Here is call stack of main thread:
ntdll!NtWaitForSingleObject+0x14
KERNELBASE!WaitForSingleObjectEx+0x93
clr!CLREventWaitHelper2+0x3c
clr!CLREventWaitHelper+0x1f
clr!CLREventBase::WaitEx+0x71
clr!WKS::GCHeap::WaitUntilGCComplete+0x2e
clr!Thread::RareDisablePreemptiveGC+0x18f
clr!StubRareDisableHRWorker+0x38
clr!COMToCLRWorker+0x19d612
clr!GenericComCallStub+0x57
SomeDll!SomeFunction+0x62
ntdll!LdrpCallInitRoutine+0x6f
ntdll!LdrpInitializeNode+0x1c1
ntdll!LdrpInitializeGraphRecurse+0x80
ntdll!LdrpPrepareModuleForExecution+0xc5
ntdll!LdrpLoadDllInternal+0x199
ntdll!LdrpLoadDll+0xa8
ntdll!LdrLoadDll+0xe4
hmpalert!CVCCP+0x67eb
KERNELBASE!LoadLibraryExW+0x161
KERNELBASE!LoadLibraryExA+0x31
KERNELBASE!LoadLibraryA+0x3f
0x00007ffa`0fec9ece
...
clr!ExecuteEXE+0x3f
clr!_CorExeMainInternal+0xb2
clr!CorExeMain+0x14
mscoreei!CorExeMain+0x112
mscoree!CorExeMain_Exported+0x6c
kernel32!BaseThreadInitThunk+0x14
ntdll!RtlUserThreadStart+0x21
Ok, it looks like main thread is waiting for GC to finish. But what is GC doing? And it looks GC related code is here:
ntdll!NtWaitForSingleObject+0x14
KERNELBASE!WaitForSingleObjectEx+0x93
clr!CLREventWaitHelper2+0x3c
clr!CLREventWaitHelper+0x1f
clr!CLREventBase::WaitEx+0x71
clr!`anonymous namespace'::CreateSuspendableThread+0x10c
clr!GCToEEInterface::CreateThread+0x170
clr!WKS::gc_heap::prepare_bgc_thread+0x4c
clr!WKS::gc_heap::garbage_collect+0x1836b7
clr!WKS::GCHeap::GarbageCollectGeneration+0xef
clr!WKS::GCHeap::Alloc+0x29c
clr!JIT_New+0x339
...
mscorlib_ni!System.Threading.Tasks.Task.Execute()$##6003FAD+0x47
mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)$##6003AEF+0x172
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)$##6003AEE+0x15
mscorlib_ni!System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef)$##6003FBA+0x231
mscorlib_ni!System.Threading.Tasks.Task.ExecuteEntry(Boolean)$##6003FB9+0xa1
mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)$##6003AEF+0x172
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)$##6003AEE+0x15
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)$##6003AED+0x55
mscorlib_ni!System.Threading.ThreadHelper.ThreadStart(System.Object)$##6003BFF+0x60
clr!Thread::intermediateThreadProc+0x8b
kernel32!BaseThreadInitThunk+0x14
ntdll!RtlUserThreadStart+0x21
All other
[...Read More]
When I am working with WinDbg and .NET I usually using following command to load .NET support Dll into WinDbg:
.cordll -ve -u -l
But in case of .NET Core it does not work. It took me quite some time to figure out what to do. Firstly, install dotnet-sos tool into dotnet:
dotnet tool install -g dotnet-sos
Then activate dotnet-sos tool by execution this command:
dotnet-sos install
And this will copy support dll to C:\Users\<username>\.dotnet\sos\sos.dll, where <username> is your username on this computer. These two commands you need to execute only once per .NET Core version or after tool is updated.
And lastly to load this dll into WinDbg, execute this
[...Read More]
How to get to Exception object in .NET when native code calls it
Few day ago, I did investigate crash dump where .NET code raised some exception. Some .NET code called from native host using COM interface. .NET wraps such calls in try catch and return proper HRESULT to caller in native code in case of exception. In my case that .NET method failed and return failed HRESULT. Then due to unforeseen design issues, native code crashed and as result Windows created crash dump and terminated process.
Normally in most native languages when exception is raised, exception object of some kind is created and when exception handled somewhere, this object is destroyed and after that there is no way to
[...Read More]