HRESULT MicrosoftInstrumentationEngine::CTypeCreator::FromSignature()

in src/InstrumentationEngine/TypeCreator.cpp [60:324]


HRESULT MicrosoftInstrumentationEngine::CTypeCreator::FromSignature(_In_ DWORD cbBuffer, _In_ const BYTE* pCorSignature, _Out_ IType ** ppType, _Out_opt_ DWORD* pdwSigSize)
{
    IfNullRetPointer(pCorSignature);
    IfNullRetPointer(pdwSigSize);
    IfNullRetPointer(ppType);
    if (cbBuffer == 0)
    {
        return E_INVALIDARG;
    }

    *ppType = nullptr;
    *pdwSigSize = 0;

    HRESULT hr = S_OK;
    PCCOR_SIGNATURE currentSignature = pCorSignature;
    CorElementType sigElement = ELEMENT_TYPE_END;
    DWORD currentSize = 1;

    CComPtr<IType> createdType;

    switch ((sigElement = static_cast<CorElementType>(*currentSignature)))
    {
        case ELEMENT_TYPE_VOID:
        case ELEMENT_TYPE_BOOLEAN:
        case ELEMENT_TYPE_CHAR:
        case ELEMENT_TYPE_I1:
        case ELEMENT_TYPE_U1:
        case ELEMENT_TYPE_I2:
        case ELEMENT_TYPE_U2:
        case ELEMENT_TYPE_I4:
        case ELEMENT_TYPE_U4:
        case ELEMENT_TYPE_I8:
        case ELEMENT_TYPE_U8:
        case ELEMENT_TYPE_R4:
        case ELEMENT_TYPE_R8:
        case ELEMENT_TYPE_I:
        case ELEMENT_TYPE_U:
        case ELEMENT_TYPE_STRING:
        case ELEMENT_TYPE_OBJECT:
        case ELEMENT_TYPE_TYPEDBYREF:
        {
            createdType.Attach(new CSimpleType(sigElement));
            if (createdType == nullptr)
            {
                return E_OUTOFMEMORY;
            }
        }
        break;
    case ELEMENT_TYPE_CLASS:
    case ELEMENT_TYPE_VALUETYPE:
        {
            mdToken tokenValue;
            currentSize += CorSigUncompressToken(&currentSignature[currentSize], &tokenValue);
            IfFailRet(FromToken(sigElement, tokenValue, &createdType));
        }
        break;
    case ELEMENT_TYPE_PTR:
    case ELEMENT_TYPE_BYREF:
    case ELEMENT_TYPE_SZARRAY:
        {
            DWORD newSize;
            CComPtr<IType> relatedType;
            IfFailRet(FromSignature(cbBuffer - currentSize, &currentSignature[currentSize], &relatedType, &newSize));
            createdType.Attach(new CCompositeType(sigElement, relatedType));
            if (createdType == nullptr)
            {
                return E_OUTOFMEMORY;
            }
            currentSize += newSize;
        }
        break;
    case ELEMENT_TYPE_FNPTR:
        {
            CComPtr<IType> pReturnType;
            ULONG convention = IMAGE_CEE_CS_CALLCONV_MAX;
            CComPtr<IEnumTypes> pEnumTypes;
            DWORD genericCount = 0;

            DWORD newSize = 0;
            IfFailRet(ParseMethodSignature(
                &currentSignature[currentSize],
                cbBuffer - currentSize,
                &convention,
                &pReturnType,
                &pEnumTypes,
                &genericCount,
                &newSize));
            currentSize += newSize;

            vector<CComPtr<IType>> parameterTypes;

            ULONG cTypes;
            CComPtr<IType> pType;
            while (S_OK == (hr = pEnumTypes->Next(1, &pType, &cTypes)))
            {
                parameterTypes.push_back(pType);

                pType.Release();
            }
            IfFailRet(hr);
            hr = S_OK;

            createdType.Attach(new CFunctionType((CorCallingConvention)convention, pReturnType, parameterTypes, genericCount));
            if (createdType == nullptr)
            {
                return E_OUTOFMEMORY;
            }
        }
        break;
    case ELEMENT_TYPE_ARRAY:
        {
            DWORD newSize;
            CComPtr<IType> relatedType;
            IfFailRet(FromSignature(cbBuffer - currentSize, &currentSignature[currentSize], &relatedType, &newSize));
            currentSize += newSize;
            IfFailRet(cbBuffer > currentSize ? S_OK : E_UNEXPECTED);
            ULONG rank;
            ULONG sizeCount;
            ULONG boundsCount;

            currentSize += CorSigUncompressData(&currentSignature[currentSize], &rank);
            currentSize += CorSigUncompressData(&currentSignature[currentSize], &sizeCount);
            std::vector<ULONG> counts(sizeCount);

            for (ULONG iSizeIndex = 0; iSizeIndex < sizeCount; iSizeIndex++)
            {
                ULONG count;
                currentSize += CorSigUncompressData(&currentSignature[currentSize], &count);
                counts[iSizeIndex] = count;
            }

            currentSize += CorSigUncompressData(&currentSignature[currentSize], &boundsCount);
            std::vector<ULONG> bounds(boundsCount);

            for (ULONG iBoundIndex = 0; iBoundIndex < boundsCount; iBoundIndex++)
            {
                ULONG bound;
                currentSize += CorSigUncompressData(&currentSignature[currentSize], &bound);
                bounds[iBoundIndex] = bound;
            }

            createdType.Attach(new CArrayType(relatedType, rank, counts, bounds));
            if (createdType == nullptr)
            {
                return E_OUTOFMEMORY;
            }
        }
        break;
    case ELEMENT_TYPE_MVAR:
    case ELEMENT_TYPE_VAR:
         {
            ULONG position;
            currentSize += CorSigUncompressData(&currentSignature[currentSize], &position);

            createdType.Attach(new CGenericParameterType(sigElement, position));
            if (createdType == nullptr)
            {
                return E_OUTOFMEMORY;
            }
        }
        break;
    case ELEMENT_TYPE_GENERICINST:
        {
            DWORD newSize;
            CComPtr<IType> relatedType;
            IfFailRet(FromSignature(cbBuffer - currentSize, &currentSignature[currentSize], &relatedType, &newSize));
            currentSize += newSize;
            IfFailRet(cbBuffer > currentSize ? S_OK : E_UNEXPECTED);
            ULONG argumentCount = 0;
            currentSize += CorSigUncompressData(&currentSignature[currentSize], &argumentCount);
            std::vector<IType*> parameters;
            for (ULONG i = 0; i < argumentCount; i++)
            {
                IType* parameterType = nullptr;
                IfFailRet(FromSignature(cbBuffer - currentSize, &currentSignature[currentSize], &parameterType, &newSize));
                currentSize += newSize;
                IfFailRet(cbBuffer >= currentSize ? S_OK : E_UNEXPECTED);
                parameters.push_back(parameterType);
            }

            createdType.Attach(new CGenericInstance(relatedType, parameters));
            for (IType* parameter : parameters)
            {
                parameter->Release();
            }
            if (createdType == nullptr)
            {
                return E_OUTOFMEMORY;
            }
        }
        break;
    case ELEMENT_TYPE_PINNED:
        {
            DWORD newSize = 0;
            IfFailRet(FromSignature(cbBuffer - currentSize, &currentSignature[currentSize], &createdType, &newSize));
            static_cast<CType*>(createdType.p)->SetIsPinned(true);
            currentSize += newSize;
        }
        break;
    case ELEMENT_TYPE_SENTINEL:
        {
            DWORD newSize = 0;
            IfFailRet(FromSignature(cbBuffer - currentSize, &currentSignature[currentSize], &createdType, &newSize));
            static_cast<CType*>(createdType.p)->SetIsSentinel(true);
            currentSize += newSize;
        }
        break;
    case ELEMENT_TYPE_CMOD_REQD:
    case ELEMENT_TYPE_CMOD_OPT:
        {
            mdToken token = mdTokenNil;
            currentSize += CorSigUncompressToken(&currentSignature[currentSize], &token);
            std::vector<CComPtr<IType>> modifiers;

            CComPtr<IType> pModifierType;
            pModifierType.Attach(new CModifierType(sigElement, token));
            if (pModifierType == nullptr)
            {
                return E_OUTOFMEMORY;
            }

            modifiers.push_back(pModifierType);

            CorElementType modifierElementType = (CorElementType)currentSignature[currentSize];
            while ((modifierElementType == ELEMENT_TYPE_CMOD_REQD) || (modifierElementType == ELEMENT_TYPE_CMOD_OPT))
            {
                ++currentSize;
                mdToken tokenInner = mdTokenNil;
                currentSize += CorSigUncompressToken(&currentSignature[currentSize], &tokenInner);
                CComPtr<IType> pNextModifierType;
                pNextModifierType.Attach(new CModifierType(modifierElementType, tokenInner));
                if (pNextModifierType == nullptr)
                {
                    return E_OUTOFMEMORY;
                }
                modifiers.push_back(pNextModifierType);
                modifierElementType = (CorElementType)currentSignature[currentSize];
            }

            DWORD newSize = 0;
            IfFailRet(FromSignature(cbBuffer - currentSize, &currentSignature[currentSize], &createdType, &newSize));
            currentSize += newSize;

            static_cast<CType*>(createdType.p)->SetModifers(modifiers);
        }
        break;
    default:
        CLogging::LogError(_T("Unexpected element type %d. This usually indicates a signature parsing bug"), sigElement);
        return E_NOTIMPL;
    }

    if (createdType)
    {
        *ppType = createdType.Detach();
        *pdwSigSize = currentSize;
        hr = S_OK;
    }
    else
    {
        CLogging::LogError(_T("Type %d is not yet supported"), sigElement);
        hr = E_FAIL;
    }

    return hr;
}