-1

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
  • 27,579
  • 4
  • 25
  • 50

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
  • 69,090
  • 10
  • 44
  • 65
  • 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
  • 318
  • 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