user3832512
user3832512

Reputation: 87

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;
}

Upvotes: 0

Views: 667

Answers (3)

zelanix
zelanix

Reputation: 3562

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;
}

Upvotes: 0

gnasher729
gnasher729

Reputation: 52530

Because you have a buffer overflow, which invokes undefined behaviour. Anything can happen. One of the things that can happen is that the string is printed completely. Other things that can happen is that your program crashes, or that a hacker attacking a user's computer uses this undefined behaviour to break in.

That's why beginners would comment on a buffer overflow "if you are unlucky, your program crashes" and more experienced programmers say "if you are lucky, your program crashes". You were not lucky.

Upvotes: 4

Tommy
Tommy

Reputation: 100612

C doesn't perform bounds checking. Writing beyond the end of an array simply produces undefined behaviour. In your empirical test on one particular implementation of the C runtime, your length of string produces the same thing as correct behaviour. It's not guaranteed to.

(in practise, on most modern architectures: if you access an address you definitely don't have the right to, that'll raise an exception; however there's only a broad resolution for such checks and malloc attempts tightly to pack allocated space so as to minimise wasted RAM; given that there is no bounds check when you do the array access all that's happening is that you're storing and subsequently retrieving bytes from memory your process owns; but it's not guaranteed that you own it in the general case and, even if you do on your particular architecture, you may well be overwriting something else; hence what you're doing is relying on undefined behaviour)

Upvotes: 2

Related Questions