Search code examples
cmemory-managementmallocdynamic-memory-allocationc-strings

dynamic memory allocation(malloc): why does the whole string get printed even though I did not allocate required memory?


even when I give the string size as 1, whatever string I enter gets entirely printed, why does this happen? I thought that the surplus elements would be ignored.

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

int main ()
{
  int i;
  char * buffer;

  printf ("How long do you want the string? ");
  scanf ("%d", &i);

  buffer = (char*) malloc (i+1);
  if (buffer==NULL) exit (1);

  printf("\n enter string");
  scanf("%s",buffer);                 
  printf ("\n string: %s\n",buffer);
  free (buffer);

  return 0;
}

Solution

  • To add to the excellent answers already given, the following is a practical example of a buffer overrun in in practice:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main ()
    {
      int i;
      char * buffer;
      static char * oops = "oops!";
    
      printf ("How long do you want the string? ");
      scanf ("%d", &i);
    
      buffer = (char*) malloc (i+1);
      if (buffer==NULL) exit (1);
    
      char * other_variable = (char*) malloc (strlen(oops) + 1);
    
      printf ("\n memory location of buffer: %u\n", (unsigned int)&buffer[0]);
      printf ("\n memory location of other variable: %u\n", (unsigned int)&other_variable[0]);
    
      printf("\n enter string without spaces longer than %u characters>", (unsigned int)&other_variable[0] - (unsigned int)&buffer[0]);
      scanf("%s",buffer);
      memcpy(other_variable, oops, strlen(oops) + 1);
      printf ("\n string: %s\n",buffer);
      free (buffer);
    
      return 0;
    }
    

    Example output:

    How long do you want the string? 1
    
     memory location of buffer: 3671064576
    
     memory location of other variable: 3671064592
    
     enter string without spaces longer than 16 characters>aaaaaaaaaaaaaaaaaaaaaaaaaaa
    
     string: aaaaaaaaaaaaaaaaoops!
    

    Conversely, the following example shows how a buffer overrun in the buffer can overwrite another important variable:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main ()
    {
      int i;
      char * buffer;
      static char * important_command = "Important Command!";
    
      printf ("How long do you want the string? ");
      scanf ("%d", &i);
    
      buffer = (char*) malloc (i+1);
      if (buffer==NULL) exit (1);
    
      char * other_variable = (char*) malloc (strlen(important_command) + 1);
      memcpy(other_variable, important_command, strlen(important_command) + 1);
    
      printf ("\n memory location of buffer: %u\n", (unsigned int)&buffer[0]);
      printf ("\n memory location of other variable: %u\n", (unsigned int)&other_variable[0]);
    
      printf("\n enter string without spaces longer than %u characters>", (unsigned int)&other_variable[0] - (unsigned int)&buffer[0]);
      scanf("%s",buffer);
      printf ("\n Contents of buffer: %s\n", buffer);
      printf ("\n Contents of other variable (should be '%s'): %s\n",important_command, other_variable);
      free (buffer);
    
      return 0;
    }
    

    Example output:

    How long do you want the string? 1
    
     memory location of buffer: 1766850560
    
     memory location of other variable: 1766850576
    
     enter string without spaces longer than 16 characters>aaaaaaaaaaaaaaaaaaaaaa
    
     Contents of buffer: aaaaaaaaaaaaaaaaaaaaaa
    
     Contents of other variable (should be 'Important Command!'): aaaaaa
    

    Now you can imagine that if that was a SQL command or something similar then this could be catastrophic to the operation of the application and would cause a major security risk.


    The real answer to your question is: you should use the fgets() function instead (and then parse it with sscanf() if you need to).

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main ()
    {
      #define num_length 10
    
      int i;
      char * buffer;
      buffer = (char*) malloc (num_length);
    
      printf ("How long do you want the string? ");
      fgets(buffer, num_length, stdin);
      sscanf (buffer, "%d", &i);
      free(buffer);
    
      buffer = (char*) malloc (i+1);
      if (buffer==NULL) exit (1);
    
      printf("\n enter string less than %i characters>", i);
      fgets(buffer, i+1, stdin);
      printf ("\n string: %s\n",buffer);
      free (buffer);
    
      return 0;
    }