简体   繁体   中英

Heap corruption using strcat

One of my weaknesses is effectively using chars in C++ which is what I am trying to do right now. I have a player class in my game and within the player class, I create a playerCard object which displays various information. This works fine for a single instance of the player object (ie Player player) but when I attempt to push_back a player object in to a vector it all goes wrong.

Basically, the program continues to run but the player doesn't render to the screen. When I quit the program, I then get a breakpoint error when main tries to return MSG. The comment about the breakpoint reads:

    /*
     * If this ASSERT fails, a bad pointer has been passed in. It may be
     * totally bogus, or it may have been allocated from another heap.
     * The pointer MUST come from the 'local' heap.
     */
    _ASSERTE(_CrtIsValidHeapPointer(pUserData));

I have located the error to here

    strcat(nameCard, nameChar);
    strcat(nameCard, genderChar);
    strcat(nameCard, ageChar);
    strcat(nameCard, cashHeldChar);
    strcat(nameCard, productWantedChar);

within the playerCard class because when I comment this out, I do not get the error. Here is the full playerCard class (Again, it is messy and probably the wrong way for going about things but I am trying to get my head round using chars/strings etc) #include "Headers.h";

class Playercard{

private:

    RECT textbox;
    LPD3DXFONT font;

    std::string nameStr;
    std::string genderStr;
    std::string ageStr;
    std::string cashHeldStr;
    std::string prodWantedStr;

    char nameCard[1000];

public:

    Playercard()
    {
    }

    void load(char* name, bool male, int age, double cash, char* prod)
    {

        if(male)
        {
            genderStr = "Gender: Male\n";
        }
        else
        {
            genderStr = "Gender: Female\n";
        }

        nameStr = "Name: " + static_cast<std::ostringstream*>( &(std::ostringstream() << name))->str() + "\n";
        ageStr = "Age: " + static_cast<std::ostringstream*>( &(std::ostringstream() << age))->str() + "\n";
        cashHeldStr = "Cash Held: " + static_cast<std::ostringstream*>( &(std::ostringstream() << cash))->str() + "\n";
        prodWantedStr = "Product Wanted: " + static_cast<std::ostringstream*>( &(std::ostringstream() << prod))->str() + "\n";

        char * nameChar = new char [nameStr.length()+1];
        char * genderChar = new char [genderStr.length()+1];
        char * ageChar = new char [ageStr.length()+1];
        char * cashHeldChar = new char [cashHeldStr.length()+1];
        char * productWantedChar = new char [prodWantedStr.length()+1];

        strcpy(nameChar, nameStr.c_str());
        strcpy(genderChar, genderStr.c_str());
        strcpy(ageChar, ageStr.c_str());
        strcpy(cashHeldChar, cashHeldStr.c_str());
        strcpy(productWantedChar, prodWantedStr.c_str());

        strcat(nameCard, nameChar);
        strcat(nameCard, genderChar);
        strcat(nameCard, ageChar);
        strcat(nameCard, cashHeldChar);
        strcat(nameCard, productWantedChar);

        diagFile.open("Diag.txt");
        diagFile.write("Test", 100);
        diagFile.close();
    }

    void setUp(int L, int T, int R, int B)
    {
        SetRect(&textbox, L,T,R,B);
    }

    void draw()
    {
        font->DrawTextA(d3dSprite, nameCard, -1, &textbox, DT_LEFT, D3DCOLOR_XRGB(255, 255, 255));
    }

    LPCSTR plCard()
    {
        return nameCard;
    }
};

Any help would be greatly appreciated. Thank you.

Your nameCard is uninitialized. Replace the first strcat with strcpy , or initialize it with a zero string.

Now, how about using std::string exclusively?

Your main problem is that nameCard is uninitialized. strcat requires a null-terminated string to do its magic, and there's no guarantee that the first, or any, character in nameCard is a null.

However, C strings are unnecessary. Just use std::string all the time. After changing nameCard to a string, I'd change load to (file writing excluded):

void load(const std::string &name, bool male, int age, double cash, const std::string &prod)
{
    nameStr = "Name: " + name + "\n";
    genderStr = "Gender: " + (male ? "Male" : "Female") + "\n";
    ageStr = "Age: " + std::to_string(age) + "\n";
    cashHeldStr = "Cash Held: " + std::to_string(cash) + "\n";
    prodWantedStr = "Product Wanted: " + prod + "\n";

    nameCard = nameStr + genderStr + ageStr + cashHeldStr + prodWantedStr;
}

I would actually just make nameCard a data member, removing the others, and use this:

nameCard.clear();
nameCard += "Name: " + name + "\n";
//add on other parts

Other than that, make plCard() return a std::string and in draw() , use nameCard.c_str() . I hope that clears up what you can do with strings a bit more.

Do note, however, that std::to_string is C++11. C++03 has two common solutions:

std::string str = boost::lexical_cast<std::string>(someNumber);

Or

std::ostringstream oss;
oss << someNumber;
std::string str = oss.str();

I find the three-liner much more readable than a one-liner or two-liner.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM