3

I'm currently recoding malloc() and need to deal with the case where a caller does a buffer size calculation that results in a negative value which is then passed to malloc() ?

I know that the parameter is a size_t, so an unsigned int am I right ?

This way, I wanted to check the size that will be passed to my recoded malloc(), but how can I do ?

Because if I pass a negative parameter it will be changed into a random number like 18446744073709551613 I just get.

So my question is : How can I check if the parameter is negative when the parameter is a size_t (unsigned int), it will be directly converted to an astronomical value, no ?

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
nookonee
  • 871
  • 2
  • 8
  • 19
  • 3
    It is not random, `-1` will always be [max unsigned value for that type](http://stackoverflow.com/a/22801135/1708801) – Shafik Yaghmour Feb 13 '15 at 13:05
  • 4
    it makes no sense to check if an unsigned int value is negative – BЈовић Feb 13 '15 at 13:06
  • "How can I check if the parameter is negative" - its `size_t`; by definition and unsigned integral type, thus it is already non-negative by the time you get it. – WhozCraig Feb 13 '15 at 13:07
  • @all For sure, I know that, but when I try like `malloc(-3)` and I print out at the first line in my `malloc(size_t size)`, I get 18446744073709551613. That's why I posted here. – nookonee Feb 13 '15 at 13:09

4 Answers4

2
void *malloc(size_t size);

As you can see, the argument is an unsigned type, meaning you cannot pass a negative value.

Anyway, conversion from integral value to unsigned type is defined to be value-preserving modulo max_value+1.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Yes I know, but as I said to the others, I did `malloc(size_t size)` and if I do like `malloc(-2)` and I printf directly at the first line of my `malloc()` I get I know that, but when I try like malloc(-3) and print out what is passed to `malloc()` it's 18446744073709551613 – nookonee Feb 13 '15 at 13:12
  • @nookonee: -3 modulo (SIZE_MAX+1) is a big number, yes. What's your point there? – Deduplicator Feb 13 '15 at 13:14
  • @nookonee and again, whats is the *question* ? what if **I** called your `malloc` function with `18446744073709551613` as my *actual* size request and not `-3` ? What/why do you care whether it came from a signed to unsigned conversion that you didn't even *see*? All you should care about is whether the requested size is fulfillable. – WhozCraig Feb 13 '15 at 13:15
  • As I'm recoding it, I must take care of all the posibilities. And when someone pass a negative parameter I should do like the real `malloc()` which return `NULL`. But I can't do that because I don't know how should I do to know when a negative parameter is given to my function. – nookonee Feb 13 '15 at 13:17
  • @nookonee **there is no negative parameter**. You're looking for something that doesn't exist. If you want to protect against someone going off the deep end and asking for the moon on a string regarding a massive allocation, so be it, but you do not, and **cannot**, know the `18446744073709551613` the caller sent you was due to actual intent or signed-to-unsigned conversion. – WhozCraig Feb 13 '15 at 13:19
  • 2
    @nookonee: The "real" `malloc` returns 0 because the request is unsupportably large. Not because it was caused by having a negative number earlier. – Deduplicator Feb 13 '15 at 13:20
  • @Deduplicator Okay, but in my case it passes, I do a `malloc()` of that unsupportably size and so on .... That's why I'm trying to avoid it, but I can't really no ? If I test the size and return NULL in that case what if like @Whozcraig said someone passes intentionnally that ize to my `malloc()` I will return NULL which is not the correct behavior.. I'm really confused with this. – nookonee Feb 13 '15 at 13:23
  • 3
    @nookonee If you can't fulfill the requested allocation, `NULL` is **precisely** what you're supposed to return. Don't make this more complicated than it needs to be. Someone asked for some memory and sent you a number. If you can fulfill it, do so; otherwise return NULL. – WhozCraig Feb 13 '15 at 13:24
2

Since it is an unsigned datatype, the value cannot be negative.

Your question is more, if/how you can distinguish between a huge value being passed intentionally and a huge value coming from the wrap-around.

In general, this is not possible.

undur_gongor
  • 15,657
  • 5
  • 63
  • 75
  • Except than on current 64 bits machines, no sane developer would intentionally `malloc` 1e18 bytes (i.e. one billion gigabytes) because everyone knows that no such huge machine exist today. – Basile Starynkevitch Feb 13 '15 at 13:14
  • 1
    @BasileStarynkevitch: As a fun-fact, lots of (nominally sane) C++ users do so daily: clang makes sure to pass a huge value to the allocator when the size-calculation for `new T[n]` overflows. And as that normally delegates to `malloc`... – Deduplicator Feb 13 '15 at 13:17
  • @BasileStarynkevitch: And what if someone tries to malloc -1e18 bytes? Suddenly the number would look reasonable. – undur_gongor Feb 13 '15 at 13:18
  • 1
    My point was simply that `malloc` should reject any too big allocation by failing. It does not matter if it is a negative value casted to `unsigned` (that's a bug) or a huge value (e.g. because of corrupted input data). – Basile Starynkevitch Feb 13 '15 at 13:20
2

Generally it is a good idea do all size calculations in which a value is subtracted from another value using signed numeric types allowing a check for a negative value. Though the prototype for malloc() calls for an size_t which is an unsigned value, you can pass a signed value and the compiler will do the quite simple conversion for you.

This is a general rule I follow for any kind of a buffer size calculation. If you use signed variables for the calculation it is easy to detect a buffer size calculation problem.

You write in your question "Because if I pass a negative parameter it will be changed into a random number like 18446744073709551613 I just get." and this is not really true. the large number is the unsigned representation of a negative value. It is not random.

One other alternative is to do a bounds check on the value. For instance you may check if the value of the size_t is greater than 0x7ffffff which is the largest 32 bit signed value and a really large buffer size. On the computers that I work with a negative value expressed as an unsigned would be a number greater than 0x8000000.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
  • Thanks a lot, you gave me all answers ! I understood that a negative parameter would be changed onto the largest number possible. But then what I asked "How can I compare it" ? But then you just gave me the perfect answer when I compare with `0x8000000`, really, really thanks ! – nookonee Feb 13 '15 at 13:28
1

Yes you are correct.
size_t value is always positive even if you pass a negative value in case of malloc function. If at all if you pass the negative value, this negative value is converted to an unsigned value of type size_t which leads to a large positive integer.

Example:

int *p = (int*)malloc(-5);
is equivalent to:

int*p = malloc(SIZE_MAX - 1); // SIZE_MAX is the maximum of size_t..!

Shivaraj Bhat
  • 841
  • 2
  • 9
  • 20
  • Oh okay, thanks ! So if I want to try it I should compare the size in parameter with the largest size_t possible ? Am I right ? But I tried it, and it's not possible I tried to compare my parameter to it. But gcc says : src/malloc.c:21:15: error: integer constant is so large that it is unsigned [-Werror] if (size >= 18446744073709551613) ^ src/malloc.c:21:3: error: this decimal constant is unsigned only in ISO C90 [-Werror] if (size >= 18446744073709551613) ^ Am I doing something wrong ? – nookonee Feb 13 '15 at 13:13
  • 1
    Pardon me, but since when `malloc()` takes 2 arguments? :-) – Sourav Ghosh Feb 13 '15 at 13:16
  • `malloc()` does not have two arguments. And your answer looks quite similar to this one: http://stackoverflow.com/a/17925794/1187415. – Martin R Feb 13 '15 at 13:16
  • @Martin: Yes Martin. That i have already mentioned in the question's comment - Possible duplicate. Please check..! – Shivaraj Bhat Feb 13 '15 at 13:18
  • 1
    @ShivarajBhat: If you cite an existing answer then you should always include a link to the original. – Btw., the example (with `-5`) is now wrong. – Martin R Feb 13 '15 at 13:21
  • New to site..! Got it now ! :) – Shivaraj Bhat Feb 13 '15 at 13:23