Exemplo n.º 1
0
//*****************************************************************************
// Called to read the data into allocated memory and release the backing store.
//  Only available on read-only data.
//*****************************************************************************
HRESULT 
StgIO::LoadFileToMemory()
{
    HRESULT hr;
    void   *pData;          // Allocated buffer for file.
    ULONG   cbData;         // Size of the data.
    ULONG   cbRead = 0;     // Data actually read.
    
    // Make sure it is a read-only file.
    if (m_fFlags & DBPROP_TMODEF_WRITE)
        return E_INVALIDARG;
    
    // Try to allocate the buffer.
    cbData = m_cbData;
    pData = AllocateMemory(cbData);
    IfNullGo(pData);
    
    // Try to read the file into the buffer.
    IfFailGo(Read(pData, cbData, &cbRead));
    if (cbData != cbRead)
    {
        _ASSERTE_MSG(FALSE, "Read didn't succeed.");
        IfFailGo(CLDB_E_FILE_CORRUPT);
    }
    
    // Done with the old data.
    Close();
    
    // Open with new data.
    hr = Open(NULL /* szName */, STGIO_READ, pData, cbData, NULL /* IStream* */, NULL /* lpSecurityAttributes */);
    _ASSERTE(SUCCEEDED(hr)); // should not be a failure code path with open on buffer.
    
    // Mark the new memory so that it will be freed later.
    m_pBaseData = m_pData;
    m_bFreeMem = true;
    
ErrExit:
    if (FAILED(hr) && pData)
       FreeMemory(pData);
    
    return hr;
} // StgIO::LoadFileToMemory
Exemplo n.º 2
0
// impl of interface method ICorDebugMutableDataTarget::WriteVirtual
HRESULT STDMETHODCALLTYPE
DataTargetAdapter::WriteVirtual( 
    CORDB_ADDRESS address,
    const BYTE * pBuffer,
    ULONG32 cbRequestSize)
{
    SUPPORTS_DAC_HOST_ONLY;
    CLRDATA_ADDRESS cdAddr = TO_CDADDR(address);
    ULONG32 cbWritten = 0;
    HRESULT hr = S_OK;

    hr = m_pLegacyTarget->WriteVirtual(cdAddr, const_cast<BYTE *>(pBuffer), cbRequestSize, &cbWritten);

    if (SUCCEEDED(hr) && cbWritten != cbRequestSize)
    {
        // This shouldn't happen - existing data target implementations make writes atomic (eg. 
        // WriteProcessMemory), even though that isn't strictly required by the old interface.  
        // If this does happen, we technically leave the process in an inconsistent state, and we make no
        // attempt to recover from that here.
        _ASSERTE_MSG(false, "Legacy data target WriteVirtual partial write - target left in inconsistent state");
        return HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
    }
    return hr;
}
Exemplo n.º 3
0
// Similar to DacGetTargetAddrForHostAddr above except that ptr can represent any pointer within a host data
// structure marshalled from the target (rather than just a pointer to the first field).
TADDR
DacGetTargetAddrForHostInteriorAddr(LPCVOID ptr, bool throwEx)
{
    // Our algorithm for locating the containing DAC instance will search backwards through memory in
    // DAC_INSTANCE_ALIGN increments looking for a valid header. The following constant determines how many of
    // these iterations we'll perform before deciding the caller made a mistake and didn't marshal the
    // containing instance from the target to the host properly. Lower values will determine the maximum
    // offset from the start of a marshalled structure at which an interior pointer can appear. Higher values
    // will bound the amount of time it takes to report an error in the case where code has been incorrectly
    // DAC-ized.
    const DWORD kMaxSearchIterations = 100;

#ifdef _PREFIX_

    // Dac accesses are not interesting for PREfix and cause alot of PREfix noise
    // so we just return the unmodified pointer for our PREFIX builds
    return (TADDR) ptr;

#else // !_PREFIX_

    // Preserve special pointer values.
    if (ptr == NULL || ((TADDR) ptr == (TADDR)-1))
    {
        return 0;
    }
    else
    {
        TADDR addr = 0;
        HRESULT status = E_FAIL;

        EX_TRY
        {
            // We're going to search backwards through memory from the pointer looking for a valid DAC
            // instance header. Initialize this search pointer to the first legal value it could hold.
            // Intuitively this would be ptr - sizeof(DAC_INSTANCE), but DAC_INSTANCE headers are further
            // constrained to lie on DAC_INSTANCE_ALIGN boundaries. DAC_INSTANCE_ALIGN is large (16 bytes) due
            // to the need to keep the marshalled structure also aligned for any possible need, so we gain
            // considerable performance from only needing to test for DAC_INSTANCE headers at
            // DAC_INSTANCE_ALIGN aligned addresses.
            DAC_INSTANCE * inst = (DAC_INSTANCE*)(((ULONG_PTR)ptr - sizeof(DAC_INSTANCE)) & ~(DAC_INSTANCE_ALIGN - 1));

            // When code is DAC'ized correctly then our search algorithm is guaranteed to terminate safely
            // before reading memory that doesn't belong to the containing DAC instance. Since people do make
            // mistakes we want to limit how long and far we search however. The counter below will let us
            // assert if we've likely tried to locate an interior host pointer in a non-marshalled structure.
            DWORD cIterations = 0;

            bool tryAgain = false;

            // Scan backwards in memory looking for a DAC_INSTANCE header.
            while (true)
            {
                // Step back DAC_INSTANCE_ALIGN bytes at a time (the initialization of inst above guarantees
                // we start with an aligned pointer value. Stop every time our potential DAC_INSTANCE header
                // has a correct signature value.
                while (tryAgain || inst->sig != DAC_INSTANCE_SIG)
                {
                    tryAgain = false;
                    inst = (DAC_INSTANCE*)((BYTE*)inst - DAC_INSTANCE_ALIGN);

                    // If we've searched a lot of memory (currently 100 * 16 == 1600 bytes) without success,
                    // then assume this is due to an issue DAC-izing code (if you really do have a field within a
                    // DAC marshalled structure whose offset is >1600 bytes then feel free to update the
                    // constant at the start of this method).
                    if (++cIterations > kMaxSearchIterations)
                    {
                        status = E_INVALIDARG;
                        break;
                    }
                }

                // Fall through to a DAC error if we searched too long without finding a header candidate.
                if (status == E_INVALIDARG)
                    break;

                // Validate our candidate header by looking up the target address it claims to map in the
                // instance hash. The entry should both exist and correspond exactly to our candidate instance
                // pointer.
                // TODO: but what if the same memory was marshalled more than once (eg. once as a DPTR, once as a VPTR)?
                if (inst == g_dacImpl->m_instances.Find(inst->addr))
                {
                    // We've found a valid DAC instance. Now validate that the marshalled structure it
                    // represents really does enclose the pointer we're asking about. If not, someone hasn't
                    // marshalled a containing structure before trying to map a pointer within that structure
                    // (we've just gone and found the previous, unrelated marshalled structure in host memory).
                    BYTE * parent = (BYTE*)(inst + 1);
                    if (((BYTE*)ptr + sizeof(LPCVOID)) <= (parent + inst->size))
                    {
                        // Everything checks out: we've found a DAC instance header and its address range
                        // encompasses the pointer we're interested in. Compute the corresponding target
                        // address by taking into account the offset of the interior pointer into its
                        // enclosing structure.
                        addr = inst->addr + ((BYTE*)ptr - parent);
                        status = S_OK;
                    }
                    else
                    {
                        // We found a valid DAC instance but it doesn't cover the address range containing our
                        // input pointer. Fall though to report an erroring DAC-izing code.
                        status = E_INVALIDARG;
                    }
                    break;
                }
                else
                {
                    // This must not really be a match, perhaps a coincidence?
                    // Keep searching
                    tryAgain = true;
                }
            }
        }
        EX_CATCH
        {
            status = E_INVALIDARG;
        }
        EX_END_CATCH(SwallowAllExceptions)

        if (status != S_OK)
        {
            if (g_dacImpl && g_dacImpl->m_debugMode)
            {
                DebugBreak();
            }

            if (throwEx)
            {
                // This means a pointer was supplied which doesn't actually point to somewhere in a marshalled
                // DAC instance.
                _ASSERTE_MSG(false, "DAC coding error: Attempt to get target address from a host interior "
                                    "pointer which is not an instance marshalled by DAC!");
                DacError(status);
            }
        }

        return addr;
    }
#endif // !_PREFIX_
}
Exemplo n.º 4
0
TADDR
DacGetTargetAddrForHostAddr(LPCVOID ptr, bool throwEx)
{
#ifdef _PREFIX_

    // Dac accesses are not interesting for PREfix and cause alot of PREfix noise
    // so we just return the unmodified pointer for our PREFIX builds
    return (TADDR) ptr;

#else // !_PREFIX_

    // Preserve special pointer values.
    if (ptr == NULL || ((TADDR) ptr == (TADDR)-1))
    {
        return 0;
    }
    else
    {
        TADDR addr = 0;
        HRESULT status = E_FAIL;

        EX_TRY
        {
            DAC_INSTANCE* inst = (DAC_INSTANCE*)ptr - 1;
            if (inst->sig == DAC_INSTANCE_SIG)
            {
                addr = inst->addr;
                status = S_OK;
            }
            else
            {
                status = E_INVALIDARG;
            }
        }
        EX_CATCH
        {
            status = E_INVALIDARG;
        }
        EX_END_CATCH(SwallowAllExceptions)

        if (status != S_OK)
        {
            if (g_dacImpl && g_dacImpl->m_debugMode)
            {
                DebugBreak();
            }

            if (throwEx)
            {
                // This means a pointer was supplied which doesn't actually point to the beginning of 
                // a marshalled DAC instance.
                _ASSERTE_MSG(false, "DAC coding error: Attempt to get target address from a host pointer "
                                    "which is not an instance marshalled by DAC!");
                DacError(status);
            }
        }

        return addr;
    }

#endif // !_PREFIX_
}
Exemplo n.º 5
0
PVOID
DacInstantiateClassByVTable(TADDR addr, ULONG32 minSize, bool throwEx)
{
#ifdef _PREFIX_

    // Dac accesses are not interesting for PREfix and cause alot of PREfix noise
    // so we just return the unmodified pointer for our PREFIX builds
    return (PVOID)addr;

#else // !_PREFIX_

    if (!g_dacImpl)
    {
        DacError(E_UNEXPECTED);
        UNREACHABLE();
    }

    // Preserve special pointer values.
    if (!addr || addr == (TADDR)-1)
    {
        return (PVOID)addr;
    }
    
    // Do not attempt to allocate more than 64megs for one object instance.  While we should
    // never even come close to this size, in cases of heap corruption or bogus data passed
    // into the dac, we can allocate huge amounts of data if we are unlucky.  This santiy
    // checks the size to ensure we don't allocate gigs of data.
    if (minSize > 0x4000000)
    {
        if (throwEx)
        {
            DacError(E_OUTOFMEMORY);
        }
        return NULL;
    }

    //
    // Check the cache for an existing VPTR instance.
    // If there is an instance we assume that it's
    // the right object.
    //

    DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr);
    DAC_INSTANCE* oldInst = NULL;
    if (inst)
    {
        // If the existing instance is a VPTR we can
        // reuse it, otherwise we need to promote.
        if (inst->usage == DAC_VPTR)
        {
            // Sanity check that the object we're returning is big enough to fill the PTR type it's being
            // accessed with.  For more information, see the similar check below for the case when the 
            // object isn't already cached
            _ASSERTE_MSG(inst->size >= minSize, "DAC coding error: Attempt to instantiate a VPTR from an object that is too small");

            return inst + 1;
        }
        else
        {
            // Existing instance is not a match and must
            // be superseded.
            // Promote the new instance into the hash
            // in place of the old, but keep the
            // old instance around in case code still
            // has a pointer to it. But ensure that we can
            // create the larger instance and add it to the
            // hash table before removing the old one.
            oldInst = inst;
        }
    }

    HRESULT status;
    TADDR vtAddr;
    ULONG32 size;
    PVOID hostVtPtr;

    // Read the vtable pointer to get the actual
    // implementation class identity.
    if ((status = DacReadAll(addr, &vtAddr, sizeof(vtAddr), throwEx)) != S_OK)
    {
        return NULL;
    }

    //
    // Instantiate the right class, using the vtable as
    // class identity.
    //

#define VPTR_CLASS(name)                       \
    if (vtAddr == g_dacImpl->m_globalBase +    \
        g_dacGlobals.name##__vtAddr)           \
    {                                          \
        size = sizeof(name);                   \
        hostVtPtr = g_dacHostVtPtrs.name;      \
    }                                          \
    else
#define VPTR_MULTI_CLASS(name, keyBase)        \
    if (vtAddr == g_dacImpl->m_globalBase +    \
        g_dacGlobals.name##__##keyBase##__mvtAddr) \
    {                                          \
        size = sizeof(name);                   \
        hostVtPtr = g_dacHostVtPtrs.name##__##keyBase; \
    }                                          \
    else
#include <vptr_list.h>
#undef VPTR_CLASS
#undef VPTR_MULTI_CLASS

    {
        // Can't identify the vtable pointer.
        if (throwEx)
        {
            _ASSERTE_MSG(false,"DAC coding error: Unrecognized vtable pointer in VPTR marshalling code");
            DacError(E_INVALIDARG);
        }
        return NULL;
    }

    // Sanity check that the object we're returning is big enough to fill the PTR type it's being
    // accessed with.
    // If this is not true, it means the type being marshalled isn't a sub-type (or the same type)
    // as the PTR type it's being used as.  For example, trying to marshal an instance of a SystemDomain 
    // object into a PTR_AppDomain will cause this ASSERT to fire (because both SystemDomain and AppDomain
    // derived from BaseDomain, and SystemDomain is smaller than AppDomain).
    _ASSERTE_MSG(size >= minSize, "DAC coding error: Attempt to instantiate a VPTR from an object that is too small");

    inst = g_dacImpl->m_instances.Alloc(addr, size, DAC_VPTR);
    if (!inst)
    {
        DacError(E_OUTOFMEMORY);
        UNREACHABLE();
    }

    // Copy the object contents into the host instance.  Note that this assumes the host and target
    // have the same exact layout.  Specifically, it assumes the host and target vtable pointers are
    // the same size.
    if ((status = DacReadAll(addr, inst + 1, size, false)) != S_OK)
    {
        g_dacImpl->m_instances.ReturnAlloc(inst);
        if (throwEx)
        {
            DacError(status);
        }
        return NULL;
    }

    // We now have a proper target object with a target
    // vtable.  We need to patch the vtable to the appropriate
    // host vtable so that the virtual functions can be
    // called in the host process.
    *(PVOID*)(inst + 1) = hostVtPtr;

    if (!g_dacImpl->m_instances.Add(inst))
    {
        g_dacImpl->m_instances.ReturnAlloc(inst);
        DacError(E_OUTOFMEMORY);
        UNREACHABLE();        
    }

    if (oldInst)
    {
        g_dacImpl->m_instances.Supersede(oldInst);
    }
    return inst + 1;

#endif // !_PREFIX_
}
Exemplo n.º 6
0
PVOID
DacInstantiateTypeByAddressHelper(TADDR addr, ULONG32 size, bool throwEx, bool fReport)
{
#ifdef _PREFIX_

    // Dac accesses are not interesting for PREfix and cause alot of PREfix noise
    // so we just return the unmodified pointer for our PREFIX builds
    return (PVOID)addr;

#else // !_PREFIX_

    if (!g_dacImpl)
    {
        DacError(E_UNEXPECTED);
        UNREACHABLE();
    }

    // Preserve special pointer values.
    if (!addr || addr == (TADDR)-1)
    {
        return (PVOID)addr;
    }

    // DacInstanceManager::Alloc will assert (with a non-obvious message) on 0-size instances. 
    // Fail sooner and more obviously here.
    _ASSERTE_MSG( size > 0, "DAC coding error: instance size cannot be 0" );
    
    // Do not attempt to allocate more than 64megs for one object instance.  While we should
    // never even come close to this size, in cases of heap corruption or bogus data passed
    // into the dac, we can allocate huge amounts of data if we are unlucky.  This santiy
    // checks the size to ensure we don't allocate gigs of data.
    if (size > 0x4000000)
    {
        if (throwEx)
        {
            DacError(E_OUTOFMEMORY);
        }
        return NULL;
    }

    //
    // Check the cache for an existing DPTR instance.
    // It's possible that a previous access may have been
    // smaller than the current access, so we have to
    // allow an existing instance to be superseded.
    //

    DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr);
    DAC_INSTANCE* oldInst = NULL;
    if (inst)
    {
        // If the existing instance is large enough we
        // can reuse it, otherwise we need to promote.
        // We cannot promote a VPTR as the VPTR data
        // has been updated with a host vtable and we
        // don't want to lose that.  This shouldn't
        // happen anyway.
        if (inst->size >= size)
        {
            return inst + 1;
        }
        else
        {
            // Existing instance is too small and must
            // be superseded.
            if (inst->usage == DAC_VPTR)
            {
                // The same address has already been marshalled as a VPTR, now we're trying to marshal as a 
                // DPTR.  This is not allowed.
                _ASSERTE_MSG(false, "DAC coding error: DPTR/VPTR usage conflict");
                DacError(E_INVALIDARG);
                UNREACHABLE();
            }

            // Promote the larger instance into the hash
            // in place of the smaller, but keep the
            // smaller instance around in case code still
            // has a pointer to it. But ensure that we can
            // create the larger instance and add it to the
            // hash table before removing the old one.
            oldInst = inst;
        }
    }

    inst = g_dacImpl->m_instances.Alloc(addr, size, DAC_DPTR);
    if (!inst)
    {
        DacError(E_OUTOFMEMORY);
        UNREACHABLE();
    }

    if (fReport == false)
    {
        // mark the bit if necessary
        inst->noReport = 1;
    }
    else
    {
        // clear the bit
        inst->noReport = 0;
    }
    HRESULT status = DacReadAll(addr, inst + 1, size, false);
    if (status != S_OK)
    {
        g_dacImpl->m_instances.ReturnAlloc(inst);
        if (throwEx)
        {
            DacError(status);
        }
        return NULL;
    }

    if (!g_dacImpl->m_instances.Add(inst))
    {
        g_dacImpl->m_instances.ReturnAlloc(inst);
        DacError(E_OUTOFMEMORY);
        UNREACHABLE();        
    }

    if (oldInst)
    {
        g_dacImpl->m_instances.Supersede(oldInst);
    }

    return inst + 1;

#endif // !_PREFIX_
}
Exemplo n.º 7
0
// impl of interface method ICorDebugDataTarget::GetPlatform
HRESULT STDMETHODCALLTYPE
DataTargetAdapter::GetPlatform( 
    CorDebugPlatform * pPlatform)
{
    SUPPORTS_DAC_HOST_ONLY;

    // Get the target machine type, and assume it's Windows
    HRESULT hr;

    ULONG32 ulMachineType;
    IfFailRet(m_pLegacyTarget->GetMachineType(&ulMachineType));
    
    ULONG32 ulExpectedPointerSize;
    CorDebugPlatform platform;

    switch(ulMachineType)
    {
#ifdef FEATURE_PAL        
    case IMAGE_FILE_MACHINE_I386:
        ulExpectedPointerSize = 4;
        platform = CORDB_PLATFORM_POSIX_X86;
        break;

    case IMAGE_FILE_MACHINE_AMD64:
        ulExpectedPointerSize = 8;
        platform = CORDB_PLATFORM_POSIX_AMD64;
        break;

    case IMAGE_FILE_MACHINE_IA64:
    case IMAGE_FILE_MACHINE_ARMNT:
    case IMAGE_FILE_MACHINE_ARM64:
        _ASSERTE_MSG(false, "Not supported platform.");
        return E_NOTIMPL;
        
#else   // FEATURE_PAL        
    case IMAGE_FILE_MACHINE_I386:
        ulExpectedPointerSize = 4;
        platform = CORDB_PLATFORM_WINDOWS_X86;
        break;

    case IMAGE_FILE_MACHINE_AMD64:
        ulExpectedPointerSize = 8;
        platform = CORDB_PLATFORM_WINDOWS_AMD64;
        break;

    case IMAGE_FILE_MACHINE_IA64:
        ulExpectedPointerSize = 8;
        platform = CORDB_PLATFORM_WINDOWS_IA64;
        break;
        
    case IMAGE_FILE_MACHINE_ARMNT:
        ulExpectedPointerSize = 4;
        platform = CORDB_PLATFORM_WINDOWS_ARM;
        break;

    case IMAGE_FILE_MACHINE_ARM64:
        ulExpectedPointerSize = 8;
        platform = CORDB_PLATFORM_WINDOWS_ARM64;
        break;        
#endif  // FEATURE_PAL
        
    default:
        // No other platforms are current supported
        return E_NOTIMPL;
    }

    // Validate that the target pointer size matches
    ULONG32 ulPointerSize;
    IfFailRet(m_pLegacyTarget->GetPointerSize(&ulPointerSize));

    if (ulPointerSize != ulExpectedPointerSize)
    {
        return E_UNEXPECTED;
    }

    // Found a match
    *pPlatform = platform;
    return S_OK;
}
Exemplo n.º 8
0
//*****************************************************************************
// Map the file contents to a memory mapped file and return a pointer to the 
// data.  For read/write with a backing store, map the file using an internal
// paging system.
//*****************************************************************************
HRESULT StgIO::MapFileToMem(            // Return code.
    void        *&ptr,                  // Return pointer to file data.
    ULONG       *pcbSize,               // Return size of data.
    LPSECURITY_ATTRIBUTES pAttributes)  // Security token.
{
    char        rcShared[MAXSHMEM];     // ANSI version of shared name.
    HRESULT     hr = S_OK;

    // Don't penalize for multiple calls.  Also, allow calls for mem type so
    // callers don't need to do so much checking.
    if (IsBackingStore() || 
        IsMemoryMapped() || 
        (m_iType == STGIO_MEM) || 
        (m_iType == STGIO_SHAREDMEM) ||
        (m_iType == STGIO_HFILEMEM))
    {
        ptr = m_pData;
        if (pcbSize)
            *pcbSize = m_cbData;
        return (S_OK);
    }

    //#CopySmallFiles
    // Check the size of the data we want to map.  If it is small enough, then
    // simply allocate a chunk of memory from a finer grained heap.  This saves
    // virtual memory space, page table entries, and should reduce overall working set.
    // Also, open for read/write needs a full backing store.
    if ((m_cbData <= SMALL_ALLOC_MAP_SIZE) && (SMALL_ALLOC_MAP_SIZE > 0))
    {
        DWORD cbRead = m_cbData;
        _ASSERTE(m_pData == 0);

        // Just malloc a chunk of data to use.
        m_pBaseData = m_pData = AllocateMemory(m_cbData);
        if (!m_pData)
        {
            hr = OutOfMemory();
            goto ErrExit;
        }

        // Read all of the file contents into this piece of memory.
        IfFailGo( Seek(0, FILE_BEGIN) );
        if (FAILED(hr = Read(m_pData, cbRead, &cbRead)))
        {
            FreeMemory(m_pData);
            m_pData = 0;
            goto ErrExit;
        }
        _ASSERTE(cbRead == m_cbData);

        // If the file isn't being opened for exclusive mode, then free it.
        // If it is for exclusive, then we need to keep the handle open so the
        // file is locked, preventing other readers.  Also leave it open if
        // in read/write mode so we can truncate and rewrite.
        if (m_hFile == INVALID_HANDLE_VALUE ||
            ((m_fFlags & DBPROP_TMODEF_EXCLUSIVE) == 0 && (m_fFlags & DBPROP_TMODEF_WRITE) == 0))
        {
            // If there was a handle open, then free it.
            if (m_hFile != INVALID_HANDLE_VALUE)
            {
                VERIFY(CloseHandle(m_hFile));
                m_hFile = INVALID_HANDLE_VALUE;
            }
            // Free the stream pointer.
            else
            if (m_pIStream != 0)
            {
                m_pIStream->Release();
                m_pIStream = 0;
            }

            // Switch the type to memory only access.
            m_iType = STGIO_MEM;
        }
        else
            m_iType = STGIO_HFILEMEM;

        // Free the memory when we shut down.
        m_bFreeMem = true;
    }
    // Finally, a real mapping file must be created.
    else
    {
        // Now we will map, so better have it right.
        _ASSERTE(m_hFile != INVALID_HANDLE_VALUE || m_iType == STGIO_STREAM);
        _ASSERTE(m_rgPageMap == 0);

        // For read mode, use a memory mapped file since the size will never
        // change for the life of the handle.
        if ((m_fFlags & DBPROP_TMODEF_WRITE) == 0 && m_iType != STGIO_STREAM)
        {
            // Create a mapping object for the file.
            _ASSERTE(m_hMapping == 0);

            DWORD dwProtectionFlags = PAGE_READONLY;
            
            if ((m_hMapping = WszCreateFileMapping(m_hFile, pAttributes, dwProtectionFlags,
                0, 0, nullptr)) == 0)
            {
                return (MapFileError(GetLastError()));
            }
            m_mtMappedType = MTYPE_FLAT;
            // Check to see if the memory already exists, in which case we have
            // no guarantees it is the right piece of data.
            if (GetLastError() == ERROR_ALREADY_EXISTS)
            {
                hr = PostError(CLDB_E_SMDUPLICATE, rcShared);
                goto ErrExit;
            }

            // Now map the file into memory so we can read from pointer access.
            // <REVISIT_TODO>Note: Added a check for IsBadReadPtr per the Services team which
            // indicates that under some conditions this API can give you back
            // a totally bogus pointer.</REVISIT_TODO>
            if ((m_pBaseData = m_pData = MapViewOfFile(m_hMapping, FILE_MAP_READ,
                        0, 0, 0)) == 0)
            {
                hr = MapFileError(GetLastError());
                if (SUCCEEDED(hr))
                {
                    _ASSERTE_MSG(FALSE, "Error code doesn't indicate error.");
                    hr = PostError(CLDB_E_FILE_CORRUPT);
                }
                
                // In case we got back a bogus pointer.
                m_pBaseData = m_pData = NULL;
                goto ErrExit;
            }
        }
        // In write mode, we need the hybrid combination of being able to back up
        // the data in memory via cache, but then later rewrite the contents and
        // throw away our cached copy.  Memory mapped files are not good for this
        // case due to poor write characteristics.
        else
        {
            ULONG iMaxSize;         // How much memory required for file.

            // Figure out how many pages we'll require, round up actual data
            // size to page size.
            iMaxSize = (((m_cbData - 1) & ~(m_iPageSize - 1)) + m_iPageSize);
            // Check integer overflow in previous statement
            if (iMaxSize < m_cbData)
            {
                IfFailGo(PostError(COR_E_OVERFLOW));
            }
            
            // Allocate a bit vector to track loaded pages.
            if ((m_rgPageMap = new (nothrow) BYTE[iMaxSize / m_iPageSize]) == 0)
                return (PostError(OutOfMemory()));
            memset(m_rgPageMap, 0, sizeof(BYTE) * (iMaxSize / m_iPageSize));

            // Allocate space for the file contents.
            if ((m_pBaseData = m_pData = ::ClrVirtualAlloc(0, iMaxSize, MEM_RESERVE, PAGE_NOACCESS)) == 0)
            {
                hr = PostError(OutOfMemory());
                goto ErrExit;
            }
        }
    }

    // Reset any changes made by mapping.
    IfFailGo( Seek(0, FILE_BEGIN) );

ErrExit:

    // Check for errors and clean up.
    if (FAILED(hr))
    {
        if (m_hMapping)
            CloseHandle(m_hMapping);
        m_hMapping = 0;
        m_pBaseData = m_pData = 0;
        m_cbData = 0;
    }
    ptr = m_pData;
    if (pcbSize)
        *pcbSize = m_cbData;
    return (hr);
}