Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bus error while running a simple string C program [duplicate]

I was running this simple program, the output i get is a "bus error". using some debugging statements i found the point at which it occurs was at the strcat() call.

#include<stdio.h>
#include<string.h>
main()
{
char *s = "this is ";
char *s1 = "me";  
strcat(s,s1); 
printf("%s",s);
return 0;
}

I run it using a gcc compiler on a MAC, 64-bit OS. Please let me know if i need to provide any more specification.

Thanks!

like image 225
Maverickgugu Avatar asked Dec 02 '22 02:12

Maverickgugu


2 Answers

A little background:

The expressions "this is " and "me" are string literals; they are 9- and 3-element arrays of char (const char in C++) respectively with static extent (meaning the memory for them is allocated at program startup and held until the program exits). That memory may or may not be writable, depending on the platform, so attempting to modify a string literal results in undefined behavior (meaning the compiler can literally do anything it wants to). In short, you cannot write to a string literal.

When you write strcat(s, s1);, you're running into two problems: first, the target array is a string literal, which as I mentioned above is not writable. Secondly, it's not large enough to hold the additional characters; it's sized to hold 9 characters (including the 0 terminator), but you're attempting to store 11 characters to it. This is a buffer overflow, which can lead to Bad Things if you clobber something important.

You'll have to allocate a target buffer that is writable. You have several choices:

  1. You can declare an array that's big enough to hold the resulting string, although in general you're not going to know how big "big enough" is at compile time:

    
    char *s = "this is ";
    char *s1 = "me";
    char target[11];
    strcpy(target, s);
    strcat(target, s1);
    // alternately, sprintf(target, "%s%s", s, s1);
    
  2. In C99, you can declare a variable-length array (VLA) whose size isn't known until runtime:

    
    char *s = "this is ";
    char *s1 = "me";
    char target[strlen(s) + strlen(s1) + 1];
    strcpy(target, s);
    strcat(target, s1);
    // alternately, sprintf(target, "%s%s", s, s1);
    
  3. You can dynamically allocate a target buffer using malloc or calloc (this is actually the preferred method, since the buffer can be resized as necessary, unlike a VLA):

    
    char *s = "this is ";
    char *s1 = "me";
    char *target = malloc(strlen(s) + strlen(s1) + 1);
    strcpy(target, s);
    strcat(target, s1); 
    // or sprintf(target, "%s%s", s, s1);
    ...
    free(target); // when you're finished with the buffer
    
like image 142
John Bode Avatar answered Dec 05 '22 02:12

John Bode


"this is " and "me" are string literals which may reside in a read-only part of your address space. You should not attempt to modify these.

char s[] = "this is ";
char s1[] = "me";  

This will ensure the literals are copied to stack - which is writable. Then your following strcat will overflow the stack buffers, which is just as bad.

The below will work - even though using strcat and not strncat is in general bad practice.

#include <stdio.h>
#include <string.h>
int main()
{
  char s[100] = "this is ";
  char *s1 = "me";  
  strcat(s,s1); 
  printf("%s",s);
  return 0;
}
like image 23
Erik Avatar answered Dec 05 '22 02:12

Erik