-2

Why does this work?

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

int main()
{

    char * abc = malloc(1) + 4; //WRONG use of malloc.
    char * xyz = "abc";
    strcpy(abc, xyz); //Should fail.
    printf("%s\n", abc); //Prints abc
}

I would expect the strcpy to fail for not having enough memory, as I'm passing in 1 to the argument of malloc(). Instead, this compiles and runs flawlessly (in both GCC on linux and dev c++ on Windows).

Is this expected behavior, or a happy coincidence?

I assume this isn't good practice, but why does it work?

Without the +4 at the end of malloc(), I get a segmentation fault. This is mostly what I'm curious about.

ale10ander
  • 942
  • 5
  • 22
  • 42
  • 2
    That's not what "work" means. – Kerrek SB Apr 19 '16 at 19:50
  • Can you elaborate? – ale10ander Apr 19 '16 at 19:50
  • 4
    Invoking undefined behaviour is always a bad idea. And there is no use in researching why code behaves a certain way once invoked. Not sure why you suspect not having enough memory to allocate 1 byte, but you might have some missconception about `malloc` & friends. And arithmetic on `void *` is also not defined. – too honest for this site Apr 19 '16 at 19:50
  • I expect to have enough memory to allocate 1 byte, I don't expect to have enough for the strcpy to succeed. – ale10ander Apr 19 '16 at 19:51
  • 3
    You cannot perform pointer arithmetic on void pointers. – Kerrek SB Apr 19 '16 at 19:52
  • are you running on a system so constrained that it doesn't have 1 byte of free memory? you're accessigning/changing memory that hasn't been allocated, by virtue of fiddling with the address that malloc() returns. you're lucky it runs at all. – Marc B Apr 19 '16 at 19:52
  • 1
    As for why there's space: `malloc` must return memory suitably aligned for `_Alignof(max_align_t)` (typically 16), so presumably it will get valid memory from the OS in units of 16B at a time. – Kerrek SB Apr 19 '16 at 19:58

3 Answers3

6

This is undefined behavior. Don't do that!!.

You're trying to access memory location beyond the allocated region. So, the memory location is invalid and accessing invalid memory invokes UB.

FWIW,

  • there is noting in the C standard that stops you from accessing out of bound (invalid) memory and

  • neither does strcpy() check for the size of the destination buffer compared to the source length

so, this code (somehow) compiles. As soon as you run it and it hits UB, nothing is guaranteed anymore.

P.S - the only guaranteed thing here is undefined behavior.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
5

This is basically another demonstration of the fact that pointers in C are low-level and (typically) not checked. You said you expected it to "fail for not having enough memory", but think about it: what did you expect to fail? The strcpy function most assuredly does not check that there's enough room for the string it's copying. It has no way to do so; all it gets is a pointer. It just starts copying characters, and in practice it either succeeds or dies on a segmentation violation. (But the point is it does not die on "out of memory".)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
1

Do not rely on that behavior. The answerers responding "vigorously" are justified in that relying on such behavior can lurk undetected for years and then, one day, a minor adjustment to the runtime system suddenly causes catastrophic failure.

It seems to work because, since the advent of 32-bit computers, many—if not most—C runtime libraries implement malloc/free which manage the heap with 16-byte granularity. That is, calling malloc() with a parameter from 1 to 16 provides the same allocation. SO you get a little more memory than you asked for and that allows it to execute.

A tool like valgrind would certainly detect a problem.

wallyk
  • 56,922
  • 16
  • 83
  • 148