0

I was trying out a sample program to understand about the generic swap function.

/* A simple generic swap function */

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

void swap(void* xp,void* yp,int size){
        //void temp = *xp; // we cant declare a variable as void , as we need to konw to de-reference as its not specifying any size info
        // Hence used the smallest type info - char
        char buffer[size];
        memcpy(buffer,xp,size);
        memcpy(xp,yp,size);
        memcpy(yp,buffer,size);
}

int main(){
        int a = 10;
        int b = 20;
        double d=1.34;
        double e=2.34;
        char* s = "Hello";
        char* t = "World";
        printf("\n a : %s b : %s \n",s,t);
        swap(s,t,sizeof(char*));
        printf("\n a : %s b : %s \n",s,t);
        return 0;
}

I got a segmentation fault when I ran the above program with the function call as swap(s,t,sizeof(char*)). But if I run it with swap(&s,&t,sizeof(char*)), I don't get any segmentation fault.

gdb o/p:

Breakpoint 2, swap (xp=0x4007ac, yp=0x4007b2, size=8) at swap_generic1.c:5
5   void swap(void* xp,void* yp,int size){
(gdb) s
8       char buffer[size];
(gdb) s
9       memcpy(buffer,xp,size);
(gdb) s
10      memcpy(xp,yp,size);
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b64fe4 in ?? () from /lib/x86_64-linux-gnu/libc.so.6

what might be the cause of the problem. Is that when passed as s and t, the argument is assigned with the address of the strings "Hello" and "World" respectively, and the pointer increments goes sto some other location to fetch the values.

Angus
  • 12,133
  • 29
  • 96
  • 151
  • *ahem* strict aliasing http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – Kos Jun 30 '14 at 10:52
  • http://stackoverflow.com/questions/12795850/string-literals-pointer-vs-char-array – Jeyaram Jun 30 '14 at 10:59
  • @Kos This has nothing to do with "strict aliasing", assuming there's documentation stating that the parameters passed are always of the same type. – Lundin Jun 30 '14 at 11:39
  • @Lundin: This could even be used for type punning (if the types are of the same size), `char *` and `void *` may alias everything. And imo it's not a duplicate (at least not a duplicate of the linked question); the two posts not from Unwind answer the question as if it were (and Unwind got the actual question, I think). – mafso Jun 30 '14 at 12:02
  • @mafso Perhaps there are better duplicates, but we get approximately one question per day on the topic "why am I getting seg faults when I do silly things with pointers to string literals". – Lundin Jun 30 '14 at 12:36

3 Answers3

3

You are calling the swap functions with sizeof (char *), so you expect to only swap pointers. But you fail to pass pointers to the pointers, instead passing the values of the pointers themselves.

This will make swap() try to swap sizeof (char *) characters in the strings, which is not allowed since character literals generate constant data which cannot be written.

You should call it as:

swap(&s, &t, sizeof s);

to just swap the pointer values, not move any character data around.

unwind
  • 391,730
  • 64
  • 469
  • 606
1
  char* s = "Hello";
  char* t = "World";

Both are pointer pointing to string literal (constant string). The compiler puts that in a part of memory that is marked as read-only. If you try to change that it will result in a memory access violation.

Jayesh Bhoi
  • 24,694
  • 15
  • 58
  • 73
1

The pointers you pass to your swap function are string literals and writing to an element in a string literal is undefined behaviour. That is why you get the segfault

mathematician1975
  • 21,161
  • 6
  • 59
  • 101