Pipe based communication between debugee and managed debugger on Linux
[platform/upstream/coreclr.git] / src / debug / di / publish.cpp
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 //*****************************************************************************
6 // File: publish.cpp
7 // 
8
9 //
10 //*****************************************************************************
11
12
13 #include "stdafx.h"
14 #ifdef FEATURE_DBG_PUBLISH
15
16 #include "check.h"
17
18 #include <tlhelp32.h>
19 #include "wtsapi32.h"
20
21 #ifndef SM_REMOTESESSION
22 #define SM_REMOTESESSION 0x1000
23 #endif
24
25 #include "corpriv.h"
26 #include "../../dlls/mscorrc/resource.h"
27 #include <limits.h>
28
29 // Publish shares header files with the rest of ICorDebug.
30 // ICorDebug should not call ReadProcessMemory & other APIs directly, it should instead go through
31 // the Data-target. ICD headers #define these APIs to help enforce this. 
32 // Since Publish is separate and doesn't use data-targets, it can access the APIs directly. 
33 // see code:RSDebuggingInfo#UseDataTarget
34 #undef ReadProcessMemory
35
36 //****************************************************************************
37 //************ App Domain Publishing Service API Implementation **************
38 //****************************************************************************
39
40 // This function enumerates all the process in the system and returns
41 // their PIDs
42 BOOL GetAllProcessesInSystem(DWORD *ProcessId,
43                              DWORD dwArraySize,
44                              DWORD *pdwNumEntries)
45 {    
46     HandleHolder hSnapshotHolder;
47
48 #if !defined(FEATURE_CORESYSTEM)
49     // Load the dll "kernel32.dll".
50     HModuleHolder hDll = WszLoadLibrary(W("kernel32"));
51     _ASSERTE(hDll != NULL);
52
53     if (hDll == NULL)
54     {
55         LOG((LF_CORDB, LL_INFO1000,
56                 "Unable to load the dll for enumerating processes. "
57                 "LoadLibrary (kernel32.dll) failed.\n"));
58         return FALSE;
59     }
60 #else
61         // Load the dll "api-ms-win-obsolete-kernel32-l1-1-0.dll".
62     HModuleHolder hDll = WszLoadLibrary(W("api-ms-win-obsolete-kernel32-l1-1-0.dll"));
63     _ASSERTE(hDll != NULL);
64
65     if (hDll == NULL)
66     {
67         LOG((LF_CORDB, LL_INFO1000,
68                 "Unable to load the dll for enumerating processes. "
69                 "LoadLibrary (api-ms-win-obsolete-kernel32-l1-1-0.dll) failed.\n"));
70         return FALSE;
71     }
72 #endif
73   
74     
75     // Create the Process' Snapshot
76     // Get the pointer to the requested function
77     FARPROC pProcAddr = GetProcAddress(hDll, "CreateToolhelp32Snapshot");
78
79     // If the proc address was not found, return error
80     if (pProcAddr == NULL)
81     {
82         LOG((LF_CORDB, LL_INFO1000,
83                 "Unable to enumerate processes in the system. "
84                 "GetProcAddr (CreateToolhelp32Snapshot) failed.\n"));
85         return FALSE;
86     }
87
88     
89
90     // Handle from CreateToolHelp32Snapshot must be freed via CloseHandle().    
91     typedef HANDLE CREATETOOLHELP32SNAPSHOT(DWORD, DWORD);
92
93     HANDLE hSnapshot =
94             ((CREATETOOLHELP32SNAPSHOT *)pProcAddr)(TH32CS_SNAPPROCESS, NULL);
95
96     if (hSnapshot == INVALID_HANDLE_VALUE)
97     {
98         LOG((LF_CORDB, LL_INFO1000,
99                 "Unable to create snapshot of processes in the system. "
100                 "CreateToolhelp32Snapshot() failed.\n"));
101         return FALSE;
102     }
103     // HandleHolder doesn't deal with INVALID_HANDLE_VALUE, so we only assign if we have a legal value.
104     hSnapshotHolder.Assign(hSnapshot);
105
106     // Get the first process in the process list
107     // Get the pointer to the requested function
108     pProcAddr = GetProcAddress(hDll, "Process32First");
109
110     // If the proc address was not found, return error
111     if (pProcAddr == NULL)
112     {
113         LOG((LF_CORDB, LL_INFO1000,
114                 "Unable to enumerate processes in the system. "
115                 "GetProcAddr (Process32First) failed.\n"));
116         return FALSE;
117     }
118
119     PROCESSENTRY32  PE32;
120
121     // need to initialize the dwSize field before calling Process32First
122     PE32.dwSize = sizeof (PROCESSENTRY32);
123
124     typedef BOOL PROCESS32FIRST(HANDLE, LPPROCESSENTRY32);
125
126     BOOL succ =
127             ((PROCESS32FIRST *)pProcAddr)(hSnapshot, &PE32);
128
129     if (succ != TRUE)
130     {
131         LOG((LF_CORDB, LL_INFO1000,
132                 "Unable to create snapshot of processes in the system. "
133                 "Process32First() returned FALSE.\n"));
134         return FALSE;
135     }
136
137
138     // Loop over and get all the remaining processes
139     // Get the pointer to the requested function
140     pProcAddr = GetProcAddress(hDll, "Process32Next");
141
142     // If the proc address was not found, return error
143     if (pProcAddr == NULL)
144     {
145         LOG((LF_CORDB, LL_INFO1000,
146                 "Unable to enumerate processes in the system. "
147                 "GetProcAddr (Process32Next) failed.\n"));
148         return FALSE;
149     }
150
151     typedef BOOL PROCESS32NEXT(HANDLE, LPPROCESSENTRY32);
152
153     int iIndex = 0;
154
155     do
156     {
157         ProcessId [iIndex++] = PE32.th32ProcessID;
158
159         succ = ((PROCESS32NEXT *)pProcAddr)(hSnapshot, &PE32);
160
161     } while ((succ == TRUE) && (iIndex < (int)dwArraySize));
162
163     // I would like to know if we're running more than 512 processes on Win95!!
164     _ASSERTE (iIndex < (int)dwArraySize);
165
166     *pdwNumEntries = iIndex;
167
168     // If we made it this far, we succeeded
169     return TRUE;
170 }
171
172
173 // We never want to wait infinite on an object that we can't verify.
174 // Wait with a timeout.
175 const DWORD SAFETY_TIMEOUT = 2000;
176
177 // ******************************************
178 // CorpubPublish
179 // ******************************************
180
181 CorpubPublish::CorpubPublish()
182     : CordbCommonBase(0),
183     m_fpGetModuleFileNameEx(NULL)
184 {
185     // Try to get psapi!GetModuleFileNameExW once, and then every process object can use it.
186     // If we can't get it, then we'll fallback to getting information from the IPC block.
187 #if !defined(FEATURE_CORESYSTEM)
188     m_hPSAPIdll = WszLoadLibrary(W("psapi.dll"));
189 #else
190         m_hPSAPIdll = WszLoadLibrary(W("api-ms-win-obsolete-psapi-l1-1-0.dll"));
191 #endif
192
193     if (m_hPSAPIdll != NULL)
194     {
195         m_fpGetModuleFileNameEx = (FPGetModuleFileNameEx*) GetProcAddress(m_hPSAPIdll, "GetModuleFileNameExW");
196     }
197
198     CordbCommonBase::InitializeCommon();
199 }
200
201 CorpubPublish::~CorpubPublish()
202 {
203     // m_hPSAPIdll is a module holder, so the dtor will free it automatically for us.
204 }
205
206
207 COM_METHOD CorpubPublish::QueryInterface(REFIID id, void **ppInterface)
208 {
209     if (id == IID_ICorPublish)
210         *ppInterface = (ICorPublish*)this;
211     else if (id == IID_IUnknown)
212         *ppInterface = (IUnknown*)(ICorPublish*)this;
213     else
214     {
215         *ppInterface = NULL;
216         return E_NOINTERFACE;
217     }
218
219     ExternalAddRef();
220     return S_OK;
221 }
222
223
224 COM_METHOD CorpubPublish::EnumProcesses(COR_PUB_ENUMPROCESS Type,
225                                         ICorPublishProcessEnum **ppIEnum)
226 {
227     HRESULT hr = E_FAIL;
228     CorpubProcess* pProcessList = NULL  ;
229     CorpubProcessEnum* pProcEnum = NULL;
230     *ppIEnum = NULL;
231
232     if( Type != COR_PUB_MANAGEDONLY )
233     {
234         hr = E_INVALIDARG;
235         goto exit;
236     }
237
238     // call function to get PIDs for all processes in the system
239 #define MAX_PROCESSES  512
240
241     DWORD ProcessId[MAX_PROCESSES];
242     DWORD dwNumProcesses = 0;
243     if( !GetAllProcessesInSystem(ProcessId, MAX_PROCESSES, &dwNumProcesses) )
244     {
245         hr = E_FAIL;
246         goto exit;
247     }
248
249     // iterate over all the processes to fetch all the managed processes
250     for (int i = 0; i < (int)dwNumProcesses; i++)
251     {
252         CorpubProcess *pProcess = NULL;
253         hr = GetProcessInternal( ProcessId[i], &pProcess );
254         if( FAILED(hr) )
255         {
256             _ASSERTE( pProcess == NULL );
257             goto exit;      // a serious error has occurred, abort
258         }
259
260         if( hr == S_OK )
261         {
262             // Success, Add the process to the list.
263             _ASSERTE( pProcess != NULL );
264             pProcess->SetNext( pProcessList );
265             pProcessList = pProcess;
266         }
267         else
268         {
269             // Ignore this process (isn't managed, or shut down, etc.)
270             _ASSERTE( pProcess == NULL );
271         }
272     }
273
274     // create and return the ICorPublishProcessEnum
275     pProcEnum = new (nothrow) CorpubProcessEnum(pProcessList);
276     if (pProcEnum == NULL)
277     {
278         hr = E_OUTOFMEMORY;
279         goto exit;
280     }
281     pProcEnum->AddRef();
282
283     hr = pProcEnum->QueryInterface(IID_ICorPublishProcessEnum, (void**)ppIEnum);
284     if( FAILED(hr) )
285     {
286         goto exit;
287     }
288
289     hr = S_OK;
290
291 exit:
292     // release our handle on the process objects
293     while (pProcessList != NULL)
294     {
295         CorpubProcess *pTmp = pProcessList;
296         pProcessList = pProcessList->GetNextProcess();
297         pTmp->Release();
298     }
299     if( pProcEnum != NULL )
300     {
301         pProcEnum->Release();
302         pProcEnum = NULL;
303     }
304
305     return hr;
306 }
307
308
309 HRESULT CorpubPublish::GetProcess(unsigned pid,
310                                   ICorPublishProcess **ppProcess)
311 {
312     *ppProcess = NULL;
313
314     // Query for this specific process (even if we've already handed out a
315     // now-stale process object for this pid)
316     CorpubProcess * pProcess = NULL;
317     HRESULT hr = GetProcessInternal( pid, &pProcess );
318     if( hr != S_OK )
319     {
320         // Couldn't get this process (doesn't exist, or isn't managed)
321         _ASSERTE( pProcess == NULL );
322         if( FAILED(hr) )
323         {
324             return hr;      // there was a serious error trying to get this process info
325         }
326         return E_INVALIDARG;  // this process doesn't exist, isn't managed or is shutting down
327     }
328
329     // QI to ICorPublishProcess and return it
330     _ASSERTE( pProcess != NULL );
331     hr = pProcess->QueryInterface(IID_ICorPublishProcess, (void**)ppProcess);
332     pProcess->Release();
333     return hr;
334 }
335
336
337 // Attempts to create a CorpubProcess object for a specific managed process
338 // On success returns S_OK and sets ppProcess to a new AddRef'd CorpubProcess
339 // object.  Otherwise, returns S_FALSE if the process isn't managed or if it has
340 // terminated (i.e. it should be ignored), or and error code on a serious failure.
341 HRESULT CorpubPublish::GetProcessInternal(
342                                     unsigned pid,
343                                     CorpubProcess **ppProcess )
344 {
345 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
346     return E_NOTIMPL;
347
348 #else // !FEATURE_DBGIPC_TRANSPORT_DI
349     HRESULT hr = S_OK;
350     *ppProcess = NULL;
351
352     NewHolder<IPCReaderInterface> pIPCReader( new (nothrow) IPCReaderInterface() );
353     if (pIPCReader == NULL)
354     {
355         LOG((LF_CORDB, LL_INFO100, "CP::EP: Failed to allocate memory for IPCReaderInterface.\n"));
356         return E_OUTOFMEMORY;
357     }
358
359     // See if it is a managed process by trying to open the shared
360     // memory block.
361     hr = pIPCReader->OpenLegacyPrivateBlockTempV4OnPid(pid);
362     if (FAILED(hr))
363     {
364         return S_FALSE;     // Not a managed process
365     }
366
367     // Get the AppDomainIPCBlock
368     AppDomainEnumerationIPCBlock *pAppDomainCB = pIPCReader->GetAppDomainBlock();
369     if (pAppDomainCB == NULL)
370     {
371         LOG((LF_CORDB, LL_INFO1000, "CP::EP: Failed to obtain AppDomainIPCBlock.\n"));
372         return S_FALSE;
373     }
374
375     // Get the process handle.
376     HANDLE hProcess = OpenProcess((PROCESS_VM_READ | 
377                                    PROCESS_QUERY_INFORMATION | 
378                                    PROCESS_DUP_HANDLE | 
379                                    SYNCHRONIZE),
380                                   FALSE, pid);
381     if (hProcess == NULL)
382     {
383         LOG((LF_CORDB, LL_INFO1000, "CP::EP: OpenProcess() returned NULL handle.\n"));
384         return S_FALSE;
385     }
386
387     // If the mutex isn't filled in, the CLR is either starting up or shutting down
388     if (pAppDomainCB->m_hMutex == NULL)
389     {
390         LOG((LF_CORDB, LL_INFO1000, "CP::EP: IPC block isn't properly filled in.\n"));
391         return S_FALSE;
392     }
393
394     // Dup the valid mutex handle into this process.
395     HANDLE hMutex;
396     if( !pAppDomainCB->m_hMutex.DuplicateToLocalProcess(hProcess, &hMutex) )
397     {
398         return S_FALSE;
399     }
400
401     // Acquire the mutex, only waiting two seconds.
402     // We can't actually gaurantee that the target put a mutex object in here.
403     DWORD dwRetVal = WaitForSingleObject(hMutex, SAFETY_TIMEOUT);
404
405     if (dwRetVal == WAIT_OBJECT_0)
406     {
407         // Make sure the mutex handle is still valid. If
408         // its not, then we lost a shutdown race.
409         if (pAppDomainCB->m_hMutex == NULL)
410         {
411             LOG((LF_CORDB, LL_INFO1000, "CP::EP: lost shutdown race, skipping...\n"));
412
413             ReleaseMutex(hMutex);
414             CloseHandle(hMutex);
415             return S_FALSE;
416         }
417     }
418     else
419     {
420         // Again, landing here is most probably a shutdown race. Its okay, though...
421         LOG((LF_CORDB, LL_INFO1000, "CP::EP: failed to get IPC mutex.\n"));
422
423         if (dwRetVal == WAIT_ABANDONED)
424         {
425             ReleaseMutex(hMutex);
426         }
427         CloseHandle(hMutex);
428         return S_FALSE;
429     }
430     // Beware: if the target pid is not properly honoring the mutex, the data in the
431     // IPC block may still shift underneath us.
432
433     // If we get here, then hMutex is held by this process.
434
435     // Now create the CorpubProcess object for the ProcessID
436     CorpubProcess *pProc = new (nothrow) CorpubProcess(pid,
437                                            true,
438                                            hProcess,
439                                            hMutex,
440                                            pAppDomainCB,
441                                            pIPCReader,
442                                            m_fpGetModuleFileNameEx);
443
444     // Release our lock on the IPC block.
445     ReleaseMutex(hMutex);
446
447     if (pProc == NULL)
448     {
449         return E_OUTOFMEMORY;
450     }
451     pIPCReader.SuppressRelease();
452
453     // Success, return the Process object
454     pProc->AddRef();
455     *ppProcess = pProc;
456     return S_OK;
457
458 #endif // FEATURE_DBGIPC_TRANSPORT_DI
459 }
460
461
462
463 // ******************************************
464 // CorpubProcess
465 // ******************************************
466
467 // Constructor
468 CorpubProcess::CorpubProcess(DWORD dwProcessId,
469                              bool fManaged,
470                              HANDLE hProcess,
471                              HANDLE hMutex,
472                              AppDomainEnumerationIPCBlock *pAD,
473 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
474                              IPCReaderInterface *pIPCReader,
475 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
476                              FPGetModuleFileNameEx * fpGetModuleFileNameEx)
477     : CordbCommonBase(0, enumCorpubProcess),
478       m_dwProcessId(dwProcessId),
479       m_fIsManaged(fManaged),
480       m_hProcess(hProcess),
481       m_hMutex(hMutex),
482       m_AppDomainCB(pAD),
483 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
484       m_pIPCReader(pIPCReader),
485 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
486       m_pNext(NULL)
487 {
488     {
489         // First try to get the process name from the OS. That can't be spoofed by badly formed IPC block.
490         // psapi!GetModuleFileNameExW can get that, but it's not available on all platforms so we
491         // need to load it dynamically.
492         if (fpGetModuleFileNameEx != NULL)
493         {
494             // MSDN is very confused about whether the lenght is in bytes (MSDN 2002) or chars (MSDN 2004).
495             // We err on the safe side by having buffer that's twice as large, and ignoring
496             // the units on the return value.
497             WCHAR szName[MAX_PATH * sizeof(WCHAR)];
498
499             DWORD lenInCharsOrBytes = MAX_PATH*sizeof(WCHAR);
500
501             // Pass NULL module handle to get "Main Module", which will give us the process name.
502             DWORD ret = (*fpGetModuleFileNameEx) (hProcess, NULL, szName, lenInCharsOrBytes);
503             if (ret > 0)
504             {
505                 // Recompute string length because we don't know if 'ret' is in bytes or char.
506                 SIZE_T len = wcslen(szName) + 1;
507                 m_szProcessName = new (nothrow) WCHAR[len];
508                 if (m_szProcessName != NULL)
509                 {
510                     wcscpy_s(m_szProcessName, len, szName);
511                     goto exit;
512                 }
513             }
514         }
515
516         // This is a security feature on WinXp + above, so make sure it worked there.
517         CONSISTENCY_CHECK_MSGF(FALSE, ("On XP/2k03 OSes + above, we should have been able to get\n"
518             "the module name from psapi!GetModuleFileNameEx. fp=0x%p\n.", fpGetModuleFileNameEx));
519     }
520     // We couldn't get it from the OS, so fallthrough to getting it from the IPC block.
521
522     // Fetch the process name from the AppDomainIPCBlock
523     _ASSERTE (pAD->m_szProcessName != NULL);
524
525     if (pAD->m_szProcessName == NULL)
526         m_szProcessName = NULL;
527     else
528     {
529         SIZE_T nBytesRead;
530
531         _ASSERTE(pAD->m_iProcessNameLengthInBytes > 0);
532
533         // Note: this assumes we're reading the null terminator from
534         // the IPC block.
535         m_szProcessName = (WCHAR*) new (nothrow) char[pAD->m_iProcessNameLengthInBytes];
536
537         if (m_szProcessName == NULL)
538         {
539             LOG((LF_CORDB, LL_INFO1000,
540              "CP::CP: Failed to allocate memory for ProcessName.\n"));
541
542             goto exit;
543         }
544
545         BOOL bSucc = ReadProcessMemory(hProcess,
546                                         pAD->m_szProcessName,
547                                         m_szProcessName,
548                                         pAD->m_iProcessNameLengthInBytes,
549                                         &nBytesRead);
550
551         if ((bSucc == 0) ||
552             (nBytesRead != (SIZE_T)pAD->m_iProcessNameLengthInBytes))
553         {
554             // The EE may have done a rude exit
555             LOG((LF_CORDB, LL_INFO1000,
556              "CP::EAD: ReadProcessMemory (ProcessName) failed.\n"));
557         }
558     }
559
560 exit:
561     ;
562 }
563
564 CorpubProcess::~CorpubProcess()
565 {
566     delete [] m_szProcessName;
567 #if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
568     delete m_pIPCReader;
569 #endif // !FEATURE_DBGIPC_TRANSPORT_DI
570     CloseHandle(m_hProcess);
571     CloseHandle(m_hMutex);
572 }
573
574
575 HRESULT CorpubProcess::QueryInterface(REFIID id, void **ppInterface)
576 {
577     if (id == IID_ICorPublishProcess)
578         *ppInterface = (ICorPublishProcess*)this;
579     else if (id == IID_IUnknown)
580         *ppInterface = (IUnknown*)(ICorPublishProcess*)this;
581     else
582     {
583         *ppInterface = NULL;
584         return E_NOINTERFACE;
585     }
586
587     AddRef();
588     return S_OK;
589 }
590
591
592 // Helper to tell if this process has exited.
593 bool CorpubProcess::IsExited()
594 {
595     DWORD res = WaitForSingleObject(this->m_hProcess, 0);
596     return (res == WAIT_OBJECT_0);
597 }
598
599
600 HRESULT CorpubProcess::IsManaged(BOOL *pbManaged)
601 {
602     *pbManaged = (m_fIsManaged == true) ? TRUE : FALSE;
603
604     return S_OK;
605 }
606
607 // Helper.
608 // Allocates a local buffer (using 'new') and fills it by copying it from remote memory.
609 // Returns:
610 // - on success, S_OK, *ppNewLocalBuffer points to a newly allocated buffer containing
611 //               the full copy from remote memoy. Caller must use 'delete []' to free this.
612 // - on failure, a failing HR. No memory is allocated.
613 HRESULT AllocateAndReadRemoteBuffer(
614     HANDLE hProcess,
615     void * pRemotePtr,
616     SIZE_T cbSize, // size of buffer to allocate + copy.
617     BYTE * * ppNewLocalBuffer
618 )
619 {
620     _ASSERTE(ppNewLocalBuffer != NULL);
621     *ppNewLocalBuffer = NULL;
622
623
624     if (pRemotePtr == NULL)
625     {
626         return E_INVALIDARG;
627     }
628
629     BYTE *pLocalBuffer = new (nothrow) BYTE[cbSize];
630
631     if (pLocalBuffer == NULL)
632     {
633         _ASSERTE(!"Failed to alloc memory. Likely size is bogusly large, perhaps from an attacker.");
634         return E_OUTOFMEMORY;
635     }
636
637     SIZE_T nBytesRead;
638
639     // Need to read in the remote process' memory
640     BOOL bSucc = ReadProcessMemory(hProcess,
641                                     pRemotePtr,
642                                     pLocalBuffer, cbSize,
643                                     &nBytesRead);
644
645     if ((bSucc == 0) || (nBytesRead != cbSize))
646     {
647         // The EE may have done a rude exit
648         delete [] pLocalBuffer;
649         return E_FAIL;
650     }
651
652     *ppNewLocalBuffer = pLocalBuffer;
653     return S_OK;
654 }
655
656 // Wrapper around AllocateAndReadRemoteBuffer,
657 // to ensure that we're reading an remote-null terminated string.
658 // Ensures that string is null-terminated.
659 HRESULT AllocateAndReadRemoteString(
660     HANDLE hProcess,
661     void * pRemotePtr,
662     SIZE_T cbSize, // size of buffer to allocate + copy.
663     __deref_out_bcount(cbSize) WCHAR * * ppNewLocalBuffer
664     )
665 {
666     // Make sure buffer has right geometry.
667     if (cbSize < 0)
668     {
669         return E_INVALIDARG;
670     }
671
672     // If it's not on a WCHAR boundary, then we may have a 1-byte buffer-overflow.
673     SIZE_T ceSize = cbSize / sizeof(WCHAR);
674     if ((ceSize * sizeof(WCHAR)) != cbSize)
675     {
676         return E_INVALIDARG;
677     }
678
679     // It should at least have 1 char for the null terminator.
680     if (ceSize < 1)
681     {
682         return E_INVALIDARG;
683     }
684
685
686     HRESULT hr = AllocateAndReadRemoteBuffer(hProcess, pRemotePtr, cbSize, (BYTE**) ppNewLocalBuffer);
687     if (SUCCEEDED(hr))
688     {
689         // Ensure that the string we just read is actually null terminated.
690         // We can't call wcslen() on it yet, since that may AV on a non-null terminated string.
691         WCHAR * pString = *ppNewLocalBuffer;
692
693         if (pString[ceSize - 1] == W('\0'))
694         {
695             // String is null terminated.
696             return S_OK;
697         }
698         pString[ceSize - 1] = W('\0');
699
700         SIZE_T ceTestLen = wcslen(pString);
701         if (ceTestLen == ceSize - 1)
702         {
703             // String was not previously null-terminated.
704             delete [] ppNewLocalBuffer;
705             return E_INVALIDARG;
706         }
707     }
708     return S_OK;
709 }
710
711 //
712 // Enumerate the list of known application domains in the target process.
713 //
714 HRESULT CorpubProcess::EnumAppDomains(ICorPublishAppDomainEnum **ppIEnum)
715 {
716     VALIDATE_POINTER_TO_OBJECT(ppIEnum, ICorPublishAppDomainEnum **);
717     *ppIEnum = NULL;
718
719     int i;
720
721     HRESULT hr = S_OK;
722     WCHAR *pAppDomainName = NULL;
723     CorpubAppDomain *pAppDomainHead = NULL;
724
725     // Lock the IPC block:
726     // We can't trust any of the data in the IPC block (including our own mutex handle),
727     // because we don't want bugs in the debuggee escalating into bugs in the debugger.
728     DWORD res = WaitForSingleObject(m_hMutex, SAFETY_TIMEOUT);
729
730     if (res == WAIT_TIMEOUT)
731     {
732         // This should only happen if the target process is illbehaved.
733         return CORDBG_E_TIMEOUT;
734     }
735
736     // If the process has gone away, or if it has cleared out its control block, then
737     // we've lost the race to access this process before it is terminated.
738     // Note that if the EE does a rude process exit, it won't have cleared the control block so there
739     // will be a small race window.
740     if (this->IsExited() || this->m_AppDomainCB->m_hMutex == NULL )
741     {
742         // This is the common case. A process holding the mutex shouldn't normally exit,
743         // but once it releases the mutex, it may exit asynchronously.
744         return CORDBG_E_PROCESS_TERMINATED;
745     }
746
747     if (res == WAIT_FAILED)
748     {
749         // This should be the next most common failure case
750         return HRESULT_FROM_GetLastError();
751     }
752
753     if (res != WAIT_OBJECT_0)
754     {
755         // Catch all other possible failures
756         return E_FAIL;
757     }
758
759     int iAppDomainCount = 0;
760     AppDomainInfo *pADI = NULL;
761
762     // Make a copy of the IPC block so that we can gaurantee that it's not changing on us.
763     AppDomainEnumerationIPCBlock tempBlock;
764     memcpy(&tempBlock, m_AppDomainCB, sizeof(tempBlock));
765
766     // Allocate memory to read the remote process' memory into
767     const SIZE_T cbADI = tempBlock.m_iSizeInBytes;
768
769     // It's possible the process will not have any appdomains.
770     if ((tempBlock.m_rgListOfAppDomains == NULL) != (tempBlock.m_iSizeInBytes == 0))
771     {
772         _ASSERTE(!"Inconsistent IPC block in publish.");
773         hr = E_FAIL;
774         goto exit;
775     }
776
777     // All the data in the IPC block is signed integers. They should never be negative,
778     // so check that now.
779     if ((tempBlock.m_iTotalSlots < 0) ||
780         (tempBlock.m_iNumOfUsedSlots < 0) ||
781         (tempBlock.m_iLastFreedSlot < 0) ||
782         (tempBlock.m_iSizeInBytes < 0) ||
783         (tempBlock.m_iProcessNameLengthInBytes < 0))
784     {
785         hr = E_FAIL;
786         goto exit;
787     }
788
789     // Check other invariants.
790     if (cbADI != tempBlock.m_iTotalSlots * sizeof(AppDomainInfo))
791     {
792         _ASSERTE(!"Size mismatch");
793         hr = E_FAIL;
794         goto exit;
795     }
796
797     hr = AllocateAndReadRemoteBuffer(m_hProcess, tempBlock.m_rgListOfAppDomains, cbADI, (BYTE**) &pADI);
798     if (FAILED(hr))
799     {
800         goto exit;
801     }
802     _ASSERTE(pADI != NULL);
803
804     // Collect all the AppDomain info info a list of CorpubAppDomains
805     for (i = 0; i < tempBlock.m_iTotalSlots; i++)
806     {
807         if (!pADI[i].IsEmpty())
808         {
809             // Should be positive, and at least have a null-terminator character.
810             if (pADI[i].m_iNameLengthInBytes <= 1)
811             {
812                 hr = E_INVALIDARG;
813                 goto exit;
814             }
815             hr = AllocateAndReadRemoteString(m_hProcess,
816                 (void*) pADI[i].m_szAppDomainName, pADI[i].m_iNameLengthInBytes, // remote string + size in bytes
817                 &pAppDomainName);
818             if (FAILED(hr))
819             {
820                 goto exit;
821             }
822
823             // create a new AppDomainObject. This will take ownership of pAppDomainName.
824             // We know the string is a well-formed null-terminated string,
825             // but beyond that, we can't verify that the data is actually truthful.
826             CorpubAppDomain *pCurrentAppDomain = new (nothrow) CorpubAppDomain(pAppDomainName,
827                                                             pADI[i].m_id);
828
829             if (pCurrentAppDomain == NULL)
830             {
831                 LOG((LF_CORDB, LL_INFO1000,
832                  "CP::EAD: Failed to allocate memory for CorpubAppDomain.\n"));
833
834                 hr = E_OUTOFMEMORY;
835                 goto exit;
836             }
837
838             // Since CorpubAppDomain now owns pAppDomain's memory, we don't worry about freeing it.
839             pAppDomainName = NULL;
840
841             // Add the appdomain to the list.
842             pCurrentAppDomain->SetNext(pAppDomainHead);
843             pAppDomainHead = pCurrentAppDomain;
844
845             // Shortcut to opt out of reading the rest of the array if it's empty.
846             if (++iAppDomainCount >= tempBlock.m_iNumOfUsedSlots)
847                 break;
848         }
849     }
850
851     {
852         _ASSERTE ((iAppDomainCount >= tempBlock.m_iNumOfUsedSlots)
853                   && (i <= tempBlock.m_iTotalSlots));
854
855         // create and return the ICorPublishAppDomainEnum object, handing off the AppDomain list to it
856         CorpubAppDomainEnum *pTemp = new (nothrow) CorpubAppDomainEnum(pAppDomainHead);
857
858         if (pTemp == NULL)
859         {
860             hr = E_OUTOFMEMORY;
861             goto exit;
862         }
863
864         pAppDomainHead = NULL;      // handed off AppDomain list to enum, don't delete below
865
866         hr = pTemp->QueryInterface(IID_ICorPublishAppDomainEnum,
867                                    (void **)ppIEnum);
868     }
869
870 exit:
871     ReleaseMutex(m_hMutex);
872
873     // If we didn't hand off the AppDomain objects, delete them
874     while( pAppDomainHead != NULL )
875     {
876         CorpubAppDomain *pTemp = pAppDomainHead;
877         pAppDomainHead = pAppDomainHead->GetNextAppDomain();
878         delete pTemp;
879     }
880
881     if (pADI != NULL)
882         delete[] pADI;
883
884     if (pAppDomainName != NULL)
885         delete [] pAppDomainName;
886
887     // Either we succeeded && provided an enumerator; or we failed and didn't provide an enum.
888     _ASSERTE(SUCCEEDED(hr) == (*ppIEnum != NULL));
889     return hr;
890 }
891
892 /*
893  * Returns the OS ID for the process in question.
894  */
895 HRESULT CorpubProcess::GetProcessID(unsigned *pid)
896 {
897     *pid = m_dwProcessId;
898
899     return S_OK;
900 }
901
902 /*
903  * Get the display name for a process.
904  */
905 HRESULT CorpubProcess::GetDisplayName(ULONG32 cchName,
906                                       ULONG32 *pcchName,
907                                       __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
908 {
909     VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(szName, WCHAR, cchName, true, true);
910     VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcchName, ULONG32 *);
911
912     // Reasonable defaults
913     if (szName)
914         *szName = 0;
915
916     if (pcchName)
917         *pcchName = 0;
918
919     const WCHAR *szTempName = m_szProcessName;
920
921     // In case we didn't get the name (most likely out of memory on ctor).
922     if (!szTempName)
923         szTempName = W("<unknown>");
924
925     return CopyOutString(szTempName, cchName, pcchName, szName);
926 }
927
928
929 // ******************************************
930 // CorpubAppDomain
931 // ******************************************
932
933 CorpubAppDomain::CorpubAppDomain (__in LPWSTR szAppDomainName, ULONG Id)
934     : CordbCommonBase (0, enumCorpubAppDomain),
935     m_pNext (NULL),
936     m_szAppDomainName (szAppDomainName),
937     m_id (Id)
938 {
939     _ASSERTE(m_szAppDomainName != NULL);
940 }
941
942 CorpubAppDomain::~CorpubAppDomain()
943 {
944     delete [] m_szAppDomainName;
945 }
946
947 HRESULT CorpubAppDomain::QueryInterface (REFIID id, void **ppInterface)
948 {
949     if (id == IID_ICorPublishAppDomain)
950         *ppInterface = (ICorPublishAppDomain*)this;
951     else if (id == IID_IUnknown)
952         *ppInterface = (IUnknown*)(ICorPublishAppDomain*)this;
953     else
954     {
955         *ppInterface = NULL;
956         return E_NOINTERFACE;
957     }
958
959     AddRef();
960     return S_OK;
961 }
962
963
964 /*
965  * Get the name and ID for an application domain.
966  */
967 HRESULT CorpubAppDomain::GetID (ULONG32 *pId)
968 {
969     VALIDATE_POINTER_TO_OBJECT(pId, ULONG32 *);
970
971     *pId = m_id;
972
973     return S_OK;
974 }
975
976 /*
977  * Get the name for an application domain.
978  */
979 HRESULT CorpubAppDomain::GetName(ULONG32 cchName,
980                                 ULONG32 *pcchName,
981                                 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
982 {
983     VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(szName, WCHAR, cchName, true, true);
984     VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcchName, ULONG32 *);
985
986     const WCHAR *szTempName = m_szAppDomainName;
987
988     // In case we didn't get the name (most likely out of memory on ctor).
989     if (!szTempName)
990         szTempName = W("<unknown>");
991
992     return CopyOutString(szTempName, cchName, pcchName, szName);
993 }
994
995
996
997 // ******************************************
998 // CorpubProcessEnum
999 // ******************************************
1000
1001 CorpubProcessEnum::CorpubProcessEnum (CorpubProcess *pFirst)
1002     : CordbCommonBase (0, enumCorpubProcessEnum),
1003     m_pFirst (pFirst),
1004     m_pCurrent (pFirst)
1005 {
1006     // Increment the ref count on each process, we own the list
1007     CorpubProcess * cur = pFirst;
1008     while( cur != NULL )
1009     {
1010         cur->AddRef();
1011         cur = cur->GetNextProcess();
1012     }
1013 }
1014
1015 CorpubProcessEnum::~CorpubProcessEnum()
1016 {
1017     // Release each process in the list (our client may still have a reference
1018     // to some of them)
1019     while (m_pFirst != NULL)
1020     {
1021         CorpubProcess *pTmp = m_pFirst;
1022         m_pFirst = m_pFirst->GetNextProcess();
1023         pTmp->Release();
1024     }
1025 }
1026
1027 HRESULT CorpubProcessEnum::QueryInterface (REFIID id, void **ppInterface)
1028 {
1029     if (id == IID_ICorPublishProcessEnum)
1030         *ppInterface = (ICorPublishProcessEnum*)this;
1031     else if (id == IID_IUnknown)
1032         *ppInterface = (IUnknown*)(ICorPublishProcessEnum*)this;
1033     else
1034     {
1035         *ppInterface = NULL;
1036         return E_NOINTERFACE;
1037     }
1038
1039     AddRef();
1040     return S_OK;
1041 }
1042
1043
1044 HRESULT CorpubProcessEnum::Skip(ULONG celt)
1045 {
1046     while ((m_pCurrent != NULL) && (celt-- > 0))
1047     {
1048         m_pCurrent = m_pCurrent->GetNextProcess();
1049     }
1050
1051     return S_OK;
1052 }
1053
1054 HRESULT CorpubProcessEnum::Reset()
1055 {
1056     m_pCurrent = m_pFirst;
1057
1058     return S_OK;
1059 }
1060
1061 HRESULT CorpubProcessEnum::Clone(ICorPublishEnum **ppEnum)
1062 {
1063     VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorPublishEnum **);
1064     return E_NOTIMPL;
1065 }
1066
1067 HRESULT CorpubProcessEnum::GetCount(ULONG *pcelt)
1068 {
1069     VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
1070
1071     CorpubProcess *pTemp = m_pFirst;
1072
1073     *pcelt = 0;
1074
1075     while (pTemp != NULL)
1076     {
1077         (*pcelt)++;
1078         pTemp = pTemp->GetNextProcess();
1079     }
1080
1081     return S_OK;
1082 }
1083
1084 HRESULT CorpubProcessEnum::Next(ULONG celt,
1085                 ICorPublishProcess *objects[],
1086                 ULONG *pceltFetched)
1087 {
1088     VALIDATE_POINTER_TO_OBJECT_ARRAY(objects, ICorPublishProcess *,
1089         celt, true, true);
1090     VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
1091
1092     if ((pceltFetched == NULL) && (celt != 1))
1093     {
1094         return E_INVALIDARG;
1095     }
1096
1097     if (celt == 0)
1098     {
1099         if (pceltFetched != NULL)
1100         {
1101             *pceltFetched = 0;
1102         }
1103         return S_OK;
1104     }
1105
1106     HRESULT hr = S_OK;
1107
1108     ULONG count = 0;
1109
1110     while ((m_pCurrent != NULL) && (count < celt))
1111     {
1112         hr = m_pCurrent->QueryInterface (IID_ICorPublishProcess,
1113                                         (void**)&objects[count]);
1114
1115         if (hr != S_OK)
1116         {
1117             break;
1118         }
1119
1120         count++;
1121         m_pCurrent = m_pCurrent->GetNextProcess();
1122     }
1123
1124     if (pceltFetched != NULL)
1125     {
1126         *pceltFetched = count;
1127     }
1128
1129     //
1130     // If we reached the end of the enumeration, but not the end
1131     // of the number of requested items, we return S_FALSE.
1132     //
1133     if (count < celt)
1134     {
1135         return S_FALSE;
1136     }
1137
1138     return hr;
1139 }
1140
1141 // ******************************************
1142 // CorpubAppDomainEnum
1143 // ******************************************
1144 CorpubAppDomainEnum::CorpubAppDomainEnum (CorpubAppDomain *pFirst)
1145     : CordbCommonBase (0, enumCorpubAppDomainEnum),
1146     m_pFirst (pFirst),
1147     m_pCurrent (pFirst)
1148 {
1149     CorpubAppDomain *pCur = pFirst;
1150     while( pCur != NULL )
1151     {
1152         pCur->AddRef();
1153         pCur = pCur->GetNextAppDomain();
1154     }
1155 }
1156
1157 CorpubAppDomainEnum::~CorpubAppDomainEnum()
1158 {
1159     // Delete all the app domains
1160     while (m_pFirst != NULL )
1161     {
1162         CorpubAppDomain *pTemp = m_pFirst;
1163         m_pFirst = m_pFirst->GetNextAppDomain();
1164         pTemp->Release();
1165     }
1166 }
1167
1168 HRESULT CorpubAppDomainEnum::QueryInterface (REFIID id, void **ppInterface)
1169 {
1170     if (id == IID_ICorPublishAppDomainEnum)
1171         *ppInterface = (ICorPublishAppDomainEnum*)this;
1172     else if (id == IID_IUnknown)
1173         *ppInterface = (IUnknown*)(ICorPublishAppDomainEnum*)this;
1174     else
1175     {
1176         *ppInterface = NULL;
1177         return E_NOINTERFACE;
1178     }
1179
1180     AddRef();
1181     return S_OK;
1182 }
1183
1184
1185 HRESULT CorpubAppDomainEnum::Skip(ULONG celt)
1186 {
1187     while ((m_pCurrent != NULL) && (celt-- > 0))
1188     {
1189         m_pCurrent = m_pCurrent->GetNextAppDomain();
1190     }
1191
1192     return S_OK;
1193 }
1194
1195 HRESULT CorpubAppDomainEnum::Reset()
1196 {
1197     m_pCurrent = m_pFirst;
1198
1199     return S_OK;
1200 }
1201
1202 HRESULT CorpubAppDomainEnum::Clone(ICorPublishEnum **ppEnum)
1203 {
1204     VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorPublishEnum **);
1205     return E_NOTIMPL;
1206 }
1207
1208 HRESULT CorpubAppDomainEnum::GetCount(ULONG *pcelt)
1209 {
1210     VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
1211
1212     CorpubAppDomain *pTemp = m_pFirst;
1213
1214     *pcelt = 0;
1215
1216     while (pTemp != NULL)
1217     {
1218         (*pcelt)++;
1219         pTemp = pTemp->GetNextAppDomain();
1220     }
1221
1222     return S_OK;
1223 }
1224
1225 HRESULT CorpubAppDomainEnum::Next(ULONG celt,
1226                 ICorPublishAppDomain *objects[],
1227                 ULONG *pceltFetched)
1228 {
1229     VALIDATE_POINTER_TO_OBJECT_ARRAY(objects, ICorPublishProcess *,
1230         celt, true, true);
1231     VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
1232
1233     if ((pceltFetched == NULL) && (celt != 1))
1234     {
1235         return E_INVALIDARG;
1236     }
1237
1238     if (celt == 0)
1239     {
1240         if (pceltFetched != NULL)
1241         {
1242     *pceltFetched = 0;
1243         }
1244         return S_OK;
1245     }
1246
1247     HRESULT hr = S_OK;
1248
1249     ULONG count = 0;
1250
1251     while ((m_pCurrent != NULL) && (count < celt))
1252     {
1253         hr = m_pCurrent->QueryInterface (IID_ICorPublishAppDomain,
1254                                         (void **)&objects[count]);
1255
1256         if (hr != S_OK)
1257         {
1258             break;
1259         }
1260
1261         count++;
1262         m_pCurrent = m_pCurrent->GetNextAppDomain();
1263     }
1264
1265
1266     if (pceltFetched != NULL)
1267     {
1268         *pceltFetched = count;
1269     }
1270
1271     //
1272     // If we reached the end of the enumeration, but not the end
1273     // of the number of requested items, we return S_FALSE.
1274     //
1275     if (count < celt)
1276     {
1277         return S_FALSE;
1278     }
1279
1280     return hr;
1281 }
1282
1283 #endif // defined(FEATURE_DBG_PUBLISH)