0

This is my code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{

   char* p;
   p = (char*)malloc(0);
   scanf("%s", p);
   printf("%s", p);
   free(p);
}

Could someone explain to me why every word i am typing via terminal is printed out to the user? I have malloc(0). Isn't supposed when i try to scanf to give me a segmentation fault?

Edit

Why this gives me a compilation error:

p = malloc(sizeof(char) * 2)

when i try to to avoid (void*)

error: cannot initialize a variable of type 'char *' with an rvalue of type 'void *'
Korpel
  • 2,432
  • 20
  • 30
  • 5
    you are casuing undefined behaviour. – David Haim Oct 26 '15 at 13:13
  • I'm pretty sure there's a duplicate somewhere, but all I can find is about automatic arrays. – Quentin Oct 26 '15 at 13:15
  • maybe undefined, but implementation defined behaviour depending on compiler/runtime. – t0mm13b Oct 26 '15 at 13:16
  • i did search the web for some time before writing in stack overflow. I couldn't find a specific answer why this particular piece of code works – Korpel Oct 26 '15 at 13:17
  • @t0mm13b: writing to it is still UB. – Karoly Horvath Oct 26 '15 at 13:17
  • 3
    @Korpel: it *doesn't work*. You were just lucky. https://en.wikipedia.org/wiki/Undefined_behavior – Karoly Horvath Oct 26 '15 at 13:18
  • 4
    Also, as usual [please don't cast the result of `malloc()`](http://stackoverflow.com/a/605858/3233393). – Quentin Oct 26 '15 at 13:22
  • 1
    whyd you think scanning a string of arbitrary length into a buffer of size 1 byte is going to be any more defined than a buffer of size 0 bytes? – Tom Tanner Oct 26 '15 at 13:25
  • @TomTanner you are correct. I am doing exactly the same but in the first case i had a "buffer" of 0 size and after that i had one of 1 byte. So yeah same case. Thanks for pointing that out – Korpel Oct 26 '15 at 13:27
  • 4
    If the last line (without the cast) triggers a compilation error, it's probably because you're using a C++ compiler instead of a C one. In C there's a well-defined implicit conversion to and from `void*`. – Quentin Oct 26 '15 at 13:27
  • @Quentin that was the issue thanks – Korpel Oct 26 '15 at 13:33

3 Answers3

4

The C Standard for malloc explicitly specifies this:

If the size of the space requested is 0, the behavior is implementation-defined: the value returned shall be either a null pointer or a unique pointer.

And for the return value from malloc:

If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() shall be returned. Otherwise, it shall return a null pointer and set errno to indicate the error.

In regards to segmentation fault from the call to scanf, that is purely on the basis of the implementation and runtime behaviour of the environment, just down to luck rather than anything, the next time it is run, it may crash with segmentation fault.

t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • 1
    You are actually citing the POSIX standard, not the C standard. Although the POSIX standard contains a lot of copy / paste from the C standard. – Lundin Oct 26 '15 at 13:34
  • @Lundin - the language in the C standard is largely the same, it's just under a different section (7.22.3): "If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object." – John Bode Oct 26 '15 at 15:04
  • Note: The C standard does not specify to set `errno`. Recommend to added citations to the quote sections. – chux - Reinstate Monica Oct 26 '15 at 15:12
3

The C standard 9899:2011 7.22.3 states that:

If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

Meaning that what is returned from malloc is implementation-defined behavior. You'll have to read your specific compiler documentation to see what it does in your case: return a null pointer or a non-zero pointer pointing at 0 bytes of data (likely a random garbage location).

In either case, the returned pointer is not pointing at a valid memory location. So if you attempt to write to it, you'll invoke undefined behavior. Meaning anything can happen: the program can crash & burn, or it can seem to work correctly and crash one month later, or anything else.

Why this gives me a compilation error: p = malloc(sizeof(char) * 2)

Because you are trying to compile C code with a C++ compiler. Don't do that. Some C++ compilers have an option you can set to compile with a C compiler instead.


Side note about an inconsistency in the C standard:

The standard Annex J actually list the above as unspecified behavior. I suspect this must be an error in Annex J, as the normative text cited above clearly states that this is implementation-defined. 7.22.3 is normative and Annex J is informative, so I would just ignore Annex J.

Lundin
  • 195,001
  • 40
  • 254
  • 396
2

From opengroup -

If the size of the space requested is 0, the behavior is implementation-defined: the value returned shall be either a null pointer or a unique pointer.

Nothing is allocated by malloc(0). So , when you try to take input using scanf you invoke undefined behaviour .

Isn't supposed when i try to scanf to give me a segmentation fault?

No , it's not necessary when you have UB . Maybe you are not that lucky to get segmentation fault and got desired output( which may confuse).

ameyCU
  • 16,489
  • 2
  • 26
  • 41