c++/clr StructureToPtr Stack buffer overflow

2019-08-17 16:07发布

问题:

as I have asked in this question c++/clr StructureToPtr exit application without any exception or error and thanks to the comment, I found out the exit code is -1073740791, which means Stack buffer overflow / overrun. So let me post my two structures,

[StructLayout(LayoutKind::Sequential)]
public ref struct ThostFtdcInputOrderField
{
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 11)]
    String^ BrokerID;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
    String^ InvestorID;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 31)]
    String^ InstrumentID;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
    String^ OrderRef;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 16)]
    String^ UserID;

    EnumOrderPriceTypeType OrderPriceType;

    EnumDirectionType Direction;

    EnumOffsetFlagType CombOffsetFlag;

    EnumOffsetFlagType CombHedgeFlag;

    double LimitPrice;

    int VolumeTotalOriginal;

    EnumTimeConditionType TimeCondition;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 9)]
    String^ GTDDate;

    EnumVolumeConditionType VolumeCondition;

    int MinVolume;

    EnumContingentConditionType ContingentCondition;

    double StopPrice;

    EnumForceCloseReasonType ForceCloseReason;

    int IsAutoSuspend;

    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 21)]
    String^ BusinessUnit;

    int RequestID;

    int UserForceClose;
};

The Enums

public enum struct EnumOrderPriceTypeType
{
    AnyPrice = (Byte)'1',
    LimitPrice = (Byte)'2',
    BestPrice = (Byte)'3',
    LastPrice = (Byte)'4',
    LastPricePlusOneTicks = (Byte)'5',
    LastPricePlusTwoTicks = (Byte)'6',
    LastPricePlusThreeTicks = (Byte)'7',
    AskPrice1 = (Byte)'8',
    AskPrice1PlusOneTicks = (Byte)'9',
    AskPrice1PlusTwoTicks = (Byte)'A',
    AskPrice1PlusThreeTicks = (Byte)'B',
    BidPrice1 = (Byte)'C',
    BidPrice1PlusOneTicks = (Byte)'D',
    BidPrice1PlusTwoTicks = (Byte)'E',
    BidPrice1PlusThreeTicks = (Byte)'F'
};

public enum struct EnumDirectionType
{
    Buy = (Byte)'0',
    Sell = (Byte)'1'
};
public enum struct EnumOffsetFlagType
{
    Open = (Byte)'0',
    Close = (Byte)'1',
    ForceClose = (Byte)'2',
    CloseToday = (Byte)'3',
    CloseYesterday = (Byte)'4',
    ForceOff = (Byte)'5',
    LocalForceClose = (Byte)'6'
};

public enum struct EnumTimeConditionType
{
    IOC = (Byte)'1',
    GFS = (Byte)'2',
    GFD = (Byte)'3',
    GTD = (Byte)'4',
    GTC = (Byte)'5',
    GFA = (Byte)'6'
};
public enum struct EnumVolumeConditionType
{
    AV = (Byte)'1',
    MV = (Byte)'2',
    CV = (Byte)'3'
};
public enum struct EnumContingentConditionType
{
    Immediately = (Byte)'1',
    Touch = (Byte)'2',
    TouchProfit = (Byte)'3',
    ParkedOrder = (Byte)'4',
    LastPriceGreaterThanStopPrice = (Byte)'5',
    LastPriceGreaterEqualStopPrice = (Byte)'6',
    LastPriceLesserThanStopPrice = (Byte)'7',
    LastPriceLesserEqualStopPrice = (Byte)'8',
    AskPriceGreaterThanStopPrice = (Byte)'9',
    AskPriceGreaterEqualStopPrice = (Byte)'A',
    AskPriceLesserThanStopPrice = (Byte)'B',
    AskPriceLesserEqualStopPrice = (Byte)'C',
    BidPriceGreaterThanStopPrice = (Byte)'D',
    BidPriceGreaterEqualStopPrice = (Byte)'E',
    BidPriceLesserThanStopPrice = (Byte)'F',
    BidPriceLesserEqualStopPrice = (Byte)'H'
};
public enum struct EnumForceCloseReasonType
{
    NotForceClose = (Byte)'0',
    LackDeposit = (Byte)'1',
    ClientOverPositionLimit = (Byte)'2',
    MemberOverPositionLimit = (Byte)'3',
    NotMultiple = (Byte)'4',
    Violation = (Byte)'5',
    Other = (Byte)'6',
    PersonDeliv = (Byte)'7'
};

The C++ struct

struct CThostFtdcInputOrderField
{
    TThostFtdcBrokerIDType  BrokerID;
    TThostFtdcInvestorIDType    InvestorID;
    TThostFtdcInstrumentIDType  InstrumentID;
    TThostFtdcOrderRefType  OrderRef;
    TThostFtdcUserIDType    UserID;
    TThostFtdcOrderPriceTypeType    OrderPriceType;
    TThostFtdcDirectionType Direction;
    TThostFtdcCombOffsetFlagType    CombOffsetFlag;
    TThostFtdcCombHedgeFlagType CombHedgeFlag;
    TThostFtdcPriceType LimitPrice;
    TThostFtdcVolumeType    VolumeTotalOriginal;
    TThostFtdcTimeConditionType TimeCondition;
    TThostFtdcDateType  GTDDate;
    TThostFtdcVolumeConditionType   VolumeCondition;
    TThostFtdcVolumeType    MinVolume;
    TThostFtdcContingentConditionType   ContingentCondition;
    TThostFtdcPriceType StopPrice;
    TThostFtdcForceCloseReasonType  ForceCloseReason;
    TThostFtdcBoolType  IsAutoSuspend;
    TThostFtdcBusinessUnitType  BusinessUnit;
    TThostFtdcRequestIDType RequestID;
    TThostFtdcBoolType  UserForceClose;
};

The types

typedef char TThostFtdcBrokerIDType[11];
typedef char TThostFtdcInvestorIDType[13];
typedef char TThostFtdcInstrumentIDType[31];
typedef char TThostFtdcOrderRefType[13];
typedef char TThostFtdcUserIDType[16];
typedef char TThostFtdcOrderPriceTypeType;
typedef char TThostFtdcDirectionType;
typedef char TThostFtdcCombOffsetFlagType[5];
typedef char TThostFtdcCombHedgeFlagType[5];
typedef double TThostFtdcPriceType;
typedef int TThostFtdcVolumeType;
typedef char TThostFtdcTimeConditionType;
typedef char TThostFtdcDateType[9];
typedef char TThostFtdcVolumeConditionType;
typedef char TThostFtdcContingentConditionType;
typedef char TThostFtdcForceCloseReasonType;.
typedef int TThostFtdcBoolType;
typedef char TThostFtdcBusinessUnitType[21];
typedef int TThostFtdcRequestIDType;
typedef int TThostFtdcBoolType;

As I dont know much of c++, so I have present the whole demo I was given. The demo calls this function to do the transform,

class MNConv
{
public:
    /// Native to Managed
    static M N2M(N* pNative){
        return safe_cast<M>(Marshal::PtrToStructure(IntPtr(pNative), M::typeid));
    };
    // Managed to Native
    static void M2N(M managed, N* pNative){
        Marshal::StructureToPtr(managed, IntPtr(pNative), true);
    };
};

  MNConv<ThostFtdcInputOrderField^, CThostFtdcInputOrderField>::M2N(pInputOrder, &native);

The problem is this exit with exit code is -1073740791, with no exception. I am not sure what went wrong, as the same demo actually convert a few other structure with success.

回答1:

When you use UnmanagedType::ByValTStr you MUST also specify the encoding.

Because your C++ typedef lines all use char, not wchar_t, you need

[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Ansi)]

If the marshaller incorrectly uses Unicode, it will write twice as much data for each string as it should, overflowing the buffer and corrupting nearby memory.



标签: c++-cli clr