C programming / Program is Crushing when in release

I got this Unhandled exception when I try to run my program in release mod.
I don't know what am I doing wrong, and I can't find where I'm exceeded the array bounds like the thrown exception says:

Unhandled exception at 0x00007FF729038141 in Game_RPG.exe: Stack cookie instrumentation code detected a stack-based buffer overrun.

In this function here I allocate memory to the prop based on the formal parameter 'propNum' as is needed. Then the 'prop' is passed along with other formal parameters to another function, where the array elements are modified.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void setMagicExtraProperties(ITEMS* item, int propNum)
{
    int* prop = NULL;
    int propStage = 0;

    if (item->level >= 1 && item->level < 6)
        propStage = 1;
    else if (item->level >= 6 && item->level < 10)
        propStage = 2;
    else if (item->level >= 10 && item->level < 15)
        propStage = 3;
    else if (item->level >= 15 && item->level <= 50)
        propStage = 4;

    prop = (int*)calloc(propNum, sizeof(int));

    if (prop != NULL)
    {
        selectProperties(item, prop, propStage, propNum);
        arrangeItemProperties(prop, propNum);
        applyMagicPropToItem(item, propNum, prop);

        free(prop);
        prop = NULL;
    }
}


I did switch back to debug and I just comment the function 'selectProperties' where the array elements are modified, and I don't get anymore the Unhandled exception.

Now this function looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void selectProperties(ITEMS* item, int* propArray, int propStage, int propNum)
{
    int availableProp[] = { 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
    int numAvailable = sizeof(availableProp) / sizeof(availableProp[0]);
    int count = 0;

    switch(propStage)
    {
        case 1:
            numAvailable -= 3;
            break;
        case 2:
            numAvailable -= 2;
            break;
        case 3:
            numAvailable -= 1;
            break;
        case 4:
            break;
        default: ASSERT(FALSE, "The propStage variable is out of range. Available from 1 to 4. Check the function before!");
    }

    while (count < propNum)
    {
        // randomize the properties from the given array and assign to the selectedProp
        int randProp = rand() % numAvailable;
        int selectedProp = availableProp[randProp];

        // add some condition, and if failed skip and continue to try with other properties again.
        if ((selectedProp == 10) && (item->category != SHIELD && item->category != JEWELRY))
            continue;
        else if ((selectedProp == 16) && item->category != JEWELRY)
            continue;
        else if ((selectedProp == 17) && item->jewel_kind != AMULET)
            continue;
        else
        {
            // add prop if it doesn't already exist in the array
            if (!inArray(selectedProp, propArray, count))
            {
                propArray[count] = selectedProp;
                count++;
            }
        }
    }
}


I don't think the 'inArray()' function is that important , but there is something I'm doing wrong in the 'selectProperties'.. the problem is ..I don't know what am I doing wrong cause I can't debug it in release and when passed to debug everything is good.

I only changed in the first function the memory allocation to 'prop' like this:

 
prop = (int*)calloc(((size_t)propNum + 1), sizeof(int));


..but I get the same result of Unhandled exception. Please help me understand what am I doing wrong.. thank you !
Last edited on
Are you sure that propNum <= numAvailable?
Last edited on
OMG... I just used the address sanitizer and seems that is nothing wrong with these functions I provided.


Address 0x005cd98ff188 is located in stack of thread T0 at offset 40 in frame
This frame has 3 object(s):
[32, 40) 'propValue' <== Memory access at offset 40 overflows this variable
[48, 52) 'minValue'
[64, 68) 'maxValue'


So if I go further in the applyMagicPropToItem(item, propNum, prop); that looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void applyMagicPropToItem(ITEMS* item, int propNum, int prop[])
{
    int propValue[MAX_MAGIC_PROP_NUM] = { 0 };

    for (int idx = 0; idx < propNum; idx++)
    {
        int minValue = 0;
        int maxValue = 0;

        if (item->jewel_kind == AMULET)
            minValue = maxValue = 1;
        else setItemExtraPropValues(item->level, &minValue, &maxValue, prop[idx]);

        propValue[idx] = randSeed(minValue, maxValue);

        if (item->category == JEWELRY)
            item->buyPrice += (maxValue * (propValue[idx] * 2));
        else  item->buyPrice += (maxValue * propValue[idx]);
        item->sellPrice += (minValue * propValue[idx]);

        propNr[prop[idx]] = propValue[idx];
        setItemProperties(item);
    }

    int maxV = 0;

    if (prop[1] != 0) maxV = sortAndFindMax(propValue, 5);
    else maxV = propValue[0];

    if (maxV > item->properties.reqLevel)
        item->properties.reqLevel = randSeed(maxV - 2, maxV + 2);

    if (item->properties.reqLevel <= 0) item->properties.reqLevel = 1;
    if (item->properties.reqLevel > MAX_LEVEL) item->properties.reqLevel = MAX_LEVEL;
}


in some how I owerflow this variable int propValue[MAX_MAGIC_PROP_NUM] = { 0 }; where MAX_MAGIC_PROP_NUM is defined as 2.
What is the value of function applyMagicPropToItem() param propNum? It must be positive and not greater than 2.

The propNum is never modified starting from void setMagicExtraProperties(ITEMS* item, int propNum) this function here until the function ends. The propNum is only modified randomly between 1 and 2 values here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
void setRandItemProperties(ITEMS* item)
{
    int randType = 0;
    int extraProp = 0;
    resetPropToZero();

    // set any properties that are set from the prototype after we reset all properties to 0;
    propNr[_DURABILITY_LEFT] = item->properties.DurabilityLeft;
    propNr[_DURABILITY_TOTAL] = item->properties.DurabilityTotal;

    // set first the type of the item, that will mostly be generated
    // the order is:  most of the time NORMAL, occasionally MAGIC and less RARE, the unique are separated from these tyes.
    randType = randSeed(0, _NORMAL_MAGIC_RARE);

    if (item->category != JEWELRY)
    {
        if (randType < MAGIC_CHANCE)
        {
            item->type = NORMAL;
            extraProp = 0;
        }
        else if (randType >= MAGIC_CHANCE && randType < _NORMAL_MAGIC_RARE)
        {
            item->type = MAGIC;
            extraProp = randSeed(1, MAX_MAGIC_PROP_NUM);
        }
    }
    else // JEWELRY HERE <---- ONLY magic and rare spawn
    {
        if (randType < _NORMAL_MAGIC_RARE)
        {
            item->type = MAGIC;
            extraProp = randSeed(1, MAX_MAGIC_PROP_NUM);
        }
    }

    if (randType == _NORMAL_MAGIC_RARE)
    {
        item->type = RARE;

        if (item->level < 15) extraProp = 3;
        else if (item->level >= 15 && item->level < 25)
            extraProp = randSeed(3, 4);
        else if (item->level >= 25 && item->level < 40)
            extraProp = randSeed(4, 5);
        else if (item->level >= 40)
            extraProp = randSeed(5, MAX_RARE_PROP_NUM);
    }

    if (item->suit == BASIC)
    {
        if (item->category != JEWELRY)
            setBasicProperties(item);

        // set extra prop for magic or rare if the case
        if (item->type == MAGIC)
        {
            setMagicExtraProperties(item, extraProp);
            setMagicItemName(item, extraProp);
        }
        else if (item->type == RARE)
        {
            setRareExtraProperties(item, extraProp);
            setRareItemPrefix(item);
            setRareItemSuffix(item);
        }

        if (item->type == MAGIC || item->type == RARE)
        {
            item->unIdentified = TRUE;

            if ((item->unidentifySellPrice = (item->sellPrice / SELL_UNIDENT_EXPONENT)) == 0)
                item->unidentifySellPrice = 1;

        }
    }
}


The propNum is always between 1 and 2 and never 0 or negative number. If the variable is 0 it never enter to this function void setMagicExtraProperties(ITEMS* item, int propNum) cose it has no extra properties so it goes with normal items prototypes.
Here are the defined MACROS if it matters:

1
2
3
4
5
#define MAGIC_CHANCE        4
#define MAX_MAGIC_PROP_NUM      2
#define MAX_RARE_PROP_NUM       6
#define _UNIQUE                 50
#define _NORMAL_MAGIC_RARE      _UNIQUE / 2 
Of course.. propNum can be greater than 2 but when that happen it goes in setRareExtraProperties(item, extraProp);, where accepts it to be even 6 included, but never greater or 0 if goes here setMagicExtraProperties(item, extraProp);.
> #define _NORMAL_MAGIC_RARE _UNIQUE / 2
Beware of unintended precedence issues.

All #define expressions should be fully surrounded by ( )
Aha.. ok that one is my mistake you're rightsalem_c, still there is space between #define _NORMAL_MAGIC_RARE and _UNIQUE / 2 which the compiler understands.. still verified that one .. and the value of _NORMAL_MAGIC_RARE is 25 which is intended. how ever that's a good point I should surrounded with (). Thank you.
Well surprisingly I have looked my all compounded macros and all are surrounded with () :D.
Problem solved.. always debug from close to close.. and there will be results
In the void applyMagicPropToItem(ITEMS* item, int propNum, int prop[]) at the bottom I'm doing this:

1
2
3
4
int maxV = 0;

    if (prop[1] != 0) maxV = sortAndFindMax(propValue, 5);
    else maxV = propValue[0];


So doing if (prop[1] != 0) when the prop[1] could be out of the bounds sometimes when propNum is 1..means the int*prop formal parameter is 1 as well.. so what I have to do is to verify that prop[1] is valid... Like I was doing I just access a piece of memory that is not allocated, I'm not supposed to go and check anything there, doing that in debug mode is not always a problem but in release the compiler is optimizing the code. So now I modified and it works just fine.
Do you guys agreed with that.. ?
Also here sortAndFindMax(propValue, 5); I'm sorting the array and the max number which is 5 when it has to be MAX_MAGIC_PROP_NUM whixh is 2
Doing that I'm accessing way past the propValue bounds. That was a mistake for the other function that accepts 5 properties and I was copied and never realized that I have to modify the parameter and has remain 5 so that's the problem.
Topic archived. No new replies allowed.