0

While debugging my code I have noticed that something strange is going on, So I have added more lines and got confused even more:

#include <iostream>
#include <memory>

struct Node
{
    size_t size = 0;
};

class MallocMetadata {
public:
    size_t size; /** Effective allocation - requested size **/
    bool is_free;
    MallocMetadata *next;
    MallocMetadata *prev;
    MallocMetadata *next_free;
    MallocMetadata *prev_free;
};

int main()
{
    size_t size = 0;
    auto node = std::make_shared<Node>();
    int tmp_res=node->size - size - sizeof(MallocMetadata);
    bool test=(node->size - size - sizeof(MallocMetadata)) < 128;
    bool test1=tmp_res<128;
    std::cout << tmp_res << "\n";
    std::cout << test << "\n";
    std::cout << test1 << "\n";
}

After running these 3 lines I saw:

tmp_res=-48
test = false
test1 = true

How is this even possible! why test is false, -48 is smaller than 128

Here's a proof:

enter image description here

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • 1
    please show a [mre] – Alan Birtles Jun 25 '21 at 12:39
  • @AlanBirtles the code is enormous that it can't be split. I swear tried too hard but unless you don't want to see 700 lines it's hard. –  Jun 25 '21 at 12:39
  • 1
    Change the code to: `auto tmp_res=node->size - size - sizeof(MallocMetadata);` – Eljay Jun 25 '21 at 12:40
  • you dont need enormous code to show us the types of the variables involved. It does not matter that `size` is member of some `node` but we need to know its type – 463035818_is_not_an_ai Jun 25 '21 at 12:40
  • @463035818_is_not_a_number for that I have updated the question –  Jun 25 '21 at 12:41
  • What are the values of `node->size` and `sizeof(MallocMetadata)`? – MikeCAT Jun 25 '21 at 12:41
  • what is `size` ? I mean the one that is not member of `node` ? – 463035818_is_not_an_ai Jun 25 '21 at 12:42
  • Please, note that `sizeof` returns `size_t` which is an unsigned type. Negative values, expressed in unsigned result in (possibly huge) positive values. Hence, `node->size - size - sizeof(MallocMetadata)` may be not `< 128` while casted to `int` it is. – Scheff's Cat Jun 25 '21 at 12:42
  • @463035818_is_not_a_number it's 4 please notice the image the value is written there –  Jun 25 '21 at 12:42
  • what type is it? Please do read the link that was posted in the first comment: [mcve] – 463035818_is_not_an_ai Jun 25 '21 at 12:43
  • @Scheff'sCat but the result is saved in int not in size_t –  Jun 25 '21 at 12:43
  • @463035818_is_not_a_number that's in my question too you can clearly see it's size_t in the signature... –  Jun 25 '21 at 12:43
  • I've added a [mre] for you – Alan Birtles Jun 25 '21 at 12:44
  • 3
    please consider that not everybody can view images. Code should be posted as code not as images: https://meta.stackoverflow.com/questions/285551/why-not-upload-images-of-code-errors-when-asking-a-question. I don't understand why asking for the code in questions about code ends in a discussion that often. Hrmpf. Nevermind. – 463035818_is_not_an_ai Jun 25 '21 at 12:48

2 Answers2

7

It looks like the part node->size - size - sizeof(MallocMetadata) is calculated in unsigned integer.

When calculation of unsigned integer is going to be negative, the maximum number of the type plus one is added and the result wraparounds.

Therefore, the value looks like being big value (128 or more), making the expression (node->size - size - sizeof(MallocMetadata)) < 128 false.

In the other hands, int tmp_res=node->size - size - sizeof(MallocMetadata); will convert the big value to int. int is signed and it may give different value than the expression above that doesn't perform convertion to int.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • 1
    @mick `bool test2 = node->size < 128 + size + sizeof(MallocMetadata);`? (if `size` won't be too big) – MikeCAT Jun 25 '21 at 12:43
  • 2
    How is this the same? I want their sum to be less that 128 not only `node->size` –  Jun 25 '21 at 12:45
  • 2
    @mick basic algebra `a - b - c < d === a < d + b + c` – Alan Birtles Jun 25 '21 at 12:48
  • just now saw it but again why this happened? The result (which should be negative) was saved in int not size_t so it should be correct. @AlanBirtles –  Jun 25 '21 at 12:56
  • `tmp_res` is an `int` and using it in `test1` gives you the correct result however the left hand side of the inequality when assigning to `test` only contains `size_t` variables so it is calculated as an unsigned `size_t` resulting in a large positive number which is not less than `128` – Alan Birtles Jun 25 '21 at 12:58
  • 2
    I'm a little disappointed and concerned to see at least 2 people agreed with the "How is this the same" comment, when this is basic algebra that is learned in grade-school... – Human-Compiler Jun 25 '21 at 13:41
0

I believe whenever there is an unsigned value in an expression, the result tends to be unsigned aswell.

size_t size = 0;
auto val = 1 + 100 + (-100) + size;
std::cout << typeid(val).name();

'val' will be a size_t aswell. So in your case, you're trying to store a negative value in size_t which causes overflow. You can explicitly typecast it to a signed integer and that should be enough if I'm not mistaken.Like so:

bool test=int(node->size - size - sizeof(MallocMetadata)) < 128;
Staz
  • 348
  • 1
  • 2
  • 6
  • `whenever there is an unsigned value in an expression, the result tends to be unsigned aswell`, not necessarily: https://stackoverflow.com/questions/25609091/what-happens-when-i-mix-signed-and-unsigned-types https://godbolt.org/z/cj6YqYYn8 – Alan Birtles Jun 25 '21 at 13:12
  • 1
    note that the cast relies on signed integer overflow which is [undefined behaviour](https://stackoverflow.com/questions/16188263/is-signed-integer-overflow-still-undefined-behavior-in-c) – Alan Birtles Jun 25 '21 at 13:15
  • Oh, correct. I was just considering same width types, mb. About the note, I'll look into it. Thanks for corrections. – Staz Jun 25 '21 at 13:45