Strcpy ошибка сегментирования

There are three types of standards behaviour you should be interested in.

1/ Defined behaviour. This will work on all complying implementations. Use this freely.

2/ Implementation-defined behaviour. As stated, it depends on the implementation but at least it’s still defined. Implementations are required to document what they do in these cases. Use this if you don’t care about portability.

3/ Undefined behaviour. Anything can happen. And we mean anything, up to and including your entire computer collapsing into a naked singularity and swallowing itself, you and a large proportion of your workmates. Never use this. Ever! Seriously! Don’t make me come over there.

Copying more that 4 characters and a zero-byte to a char[5] is undefined behaviour.

Seriously, it doesn’t matter why your program crashes with 14 characters but not 13, you’re almost certainly overwriting some non-crashing information on the stack and your program will most likely produce incorrect results anyway. In fact, the crash is better since at least it stops you relying on the possibly bad effects.

Increase the size of the array to something more suitable (char[14] in this case with the available information) or use some other data structure that can cope.


Update:

Since you seem so concerned with finding out why an extra 7 characters doesn’t cause problems but 8 characters does, let’s envisage the possible stack layout on entering main(). I say «possible» since the actual layout depends on the calling convention that your compiler uses. Since the C start-up code calls main() with argc and argv, the stack at the start of main(), after allocating space for a char[5], could look like this:

+------------------------------------+
| C start-up code return address (4) |
| argc (4)                           |
| argv (4)                           |
| x = char[5] (5)                    |
+------------------------------------+

When you write the bytes Hello1234567\0 with:

strcpy (x, "Hello1234567");

to x, it overwrites the argc and argv but, on return from main(), that’s okay. Specifically Hello populates x, 1234 populates argv and 567\0 populates argc. Provided you don’t actually try to use argc and/or argv after that, you’ll be okay:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |
| argc (4)                           |   '567<NUL>'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

However, if you write Hello12345678\0 (note the extra «8») to x, it overwrites the argc and argv and also one byte of the return address so that, when main() attempts to return to the C start-up code, it goes off into fairy land instead:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |   '<NUL>'
| argc (4)                           |   '5678'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

Again, this depends entirely on the calling convention of your compiler. It’s possible a different compiler would always pad out arrays to a multiple of 4 bytes and the code wouldn’t fail there until you wrote another three characters. Even the same compiler may allocate variables on the stack frame differently to ensure alignment is satisfied.

That’s what they mean by undefined: you don’t know what’s going to happen.

There are actually three segmentation faults here:

fread(content,1,lsize,file_pointer);
strcpy(temp,buffer);
row = strtok(temp,"\n");

The first one is fread() which is attempting to write to memory that does not yet exist as far as your process is concerned.

The second one is strcpy(), (expounding on the first) you are attempting to copy to a pointer that points to nothing. No memory (other than the pointer reference itself) has been allocated for temp, statically or dynamically.

Fix this via changing temp to look like this (allocating it statically):

char temp[1024];

Or use malloc() to dynamically allocate memory for it (as well as your other pointers, so they actually point to something), likewise for content. If you know the needed buffer size at compile time, use static allocation. If not, use malloc(). ‘Knowing’ is the subject of another question.

The third one is strtok() , which is going to modify temp en situ (in place), which it obviously can not do, since temp was never allocated. In any event, don’t expect temp to be the same once strtok() is done with it. By the name of the variable, I assume you know that.

Also, Initializing a pointer is not the same thing as allocating memory for it:

char *temp = NULL; // temp is initialized
char *temp = (char *) malloc(size); // temp is allocated if malloc returns agreeably, cast return to not break c++

Finally, please get in the habit of using strncpy() over strcpy(), its much safer.

I have this code that I need to use to perform a ret2libc

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

int main(int argc, char *argv[])
{
    char buf[256];

    printf("buff is at:%p\n",buf);
  printf("%s",argv[1]);
  strcpy(buf, argv[1]);

  printf(buf);
}

I compile it as gcc -m32 -fno-stack-protector ./rt2.c -ort2
and than start it with a cyclic patter (generated with pwntools) as follows:

./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac

I was expecting a segmentation fault at the end of the main…it instead happens at the end of the strcpy…actually what happens (by looking with gdb) is that at the end of the strcpy the ESP points to 0x6361616e which is part of the input string.

Another strange thing is that printf before the strcpy does not print out anything

this is the result of the execution:

$ ./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac


buff is at:0xffffcf20
Segmentation fault (core dumped)

$ dmesg | tail -1
[ 4432.704356] rt2[3280]: segfault at 6361616e ip 00000000565555e0 sp 000000006361616e error 4 in rt2[56555000+1000]

Even more strange, to me, if I comment the strcpy the printf before of it does instead print out…

I tried to execute it with with valgrind and it confirmed that at some point ESP got overwritten.

valgrind ./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac
==2735== Memcheck, a memory error detector
==2735== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2735== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2735== Command: ./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac
==2735== 
buff is at:0xfeffce80
==2735== Warning: client switching stacks?  SP change: 0xfeffcf98 --> 0x6361616e
==2735==          to suppress, use: --max-stackframe=1684115926 or greater
==2735== Invalid read of size 4
==2735==    at 0x1085E0: main (rt2.c:20)
==2735==  Address 0x6361616e is on thread 1's stack
==2735== 
==2735== 
==2735== Process terminating with default action of signal 11 (SIGSEGV)
==2735==  Access not within mapped region at address 0x6361616E
==2735==    at 0x1085E0: main (rt2.c:20)
==2735==  If you believe this happened as a result of a stack
==2735==  overflow in your program's main thread (unlikely but
==2735==  possible), you can try to increase the size of the
==2735==  main thread stack using the --main-stacksize= flag.
==2735==  The main thread stack size used in this run was 8388608.
--2735-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--2735-- si_code=1;  Faulting address: 0x6361616E;  sp: 0x82d8cf20

valgrind: the 'impossible' happened:
   Killed by fatal signal

host stacktrace:
==2735==    at 0x5803F9F6: ??? (in /usr/lib/valgrind/memcheck-x86-linux)

sched status:
  running_tid=1

Thread 1: status = VgTs_Runnable (lwpid 2735)
==2735==    at 0x482A4D0: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-x86-linux.so)

I also tried to compile with as: gcc -g -m32 -fno-stack-protector -z stack-size=4194304 ./rt2.c -ort2 but nothing changed

Segmentation faults are common errors that occur when a program tries to access memory that does not belong to it. This error can be caused by many things, but one common culprit is the inappropriate use of the strcpy function.

In C programming, strcpy is used for copying one string to another. However, if not used correctly, it can lead to a segmentation fault. The following are some ways to fix segmentation faults when using strcpy.

1. Use strncpy instead

One way to avoid segmentation faults when using strcpy is to use strncpy instead. strncpy is a safer function that copies a specified number of characters from one string to another, while strcpy is not limited in the number of characters it copies.

char dest[100] = "hello";
char src[] = "world";
strncpy(dest, src, sizeof(dest)-1);
dest[sizeof(dest)-1] = '\0';

In the above example, strncpy copies the entire src string into dest, but only up to the size of dest minus one character (to leave room for the null terminator). It then adds a null terminator to the end of dest. This ensures that dest does not exceed its boundary, avoiding a segmentation fault.

2. Use strlcpy

Another way to avoid segmentation faults when using strcpy is to use strlcpy. strlcpy is a function that has been created to replace strcpy in many libraries, as it is safer than strcpy.

char dest[100] = "hello";
char src[] = "world";
strlcpy(dest, src, sizeof(dest));

In the above example, strlcpy copies the entire src string into dest, but only up to the size of dest. This ensures that dest does not exceed its boundary, avoiding a segmentation fault.

3. Check boundaries

If you must use strcpy, it is important to check your boundaries. This means ensuring that the destination string has enough space to hold the entire source string, plus a null terminator.

char dest[10];
char *src = "this is too long";
if(sizeof(src) < sizeof(dest))
{
    strcpy(dest, src);
}

In the above example, we are checking that the size of the source string is less than or equal to the size of the destination string. If it is, we can safely use strcpy. If not, we could use strncpy or strlcpy.

4. Use malloc

If the size of the string is unknown, you can allocate memory dynamically using malloc. This ensures that you are not limited by the size of the destination string.

char *dest = malloc(strlen(src)+1);
strcpy(dest, src);

In the above example, we are using malloc to allocate enough memory to hold the entire source string plus a null terminator. We can then safely use strcpy to copy the string into dest.

In conclusion, segmentation faults can occur when using strcpy in C programming, but there are ways to avoid them. You can use strncpy or strlcpy instead of strcpy, check boundaries before using strcpy, or allocate memory dynamically using malloc. By following these tips, you can write safer code and avoid segmentation faults.

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>

typedef struct client{
int threadid;
int argc;
char *argv[3];
}client;

void exit(int status);
void error(char *msg);

void *threadClient(void *socket_desc);

int main(int argc, char *argv[]){
    client info[10];
    pthread_t thread[10];

    printf("%s\n%s\n%s\n", argv[0], argv[1], argv[2]);

    // Error happens here

    for (int i=0; i<=10; i++){
    info[i].threadid = i;
    strcpy(info[i].argv[0], argv[0]);
    strcpy(info[i].argv[1], argv[1]);
    strcpy(info[i].argv[2], argv[2]);
    info[i].argc = argc;
    printf("here");
        if( pthread_create( &thread[i] , NULL , threadClient , (void*)&info[i]) < 0){
            perror("could not create thread");
            return 1;
        }
        sleep(3);
    }
    pthread_exit(NULL);
    return 0;

}

During the loop, when I am trying to copy the info from argv to my struct I get a segmentation fault. Why does it happen?

Program received signal SIGSEGV, Segmentation fault. __strcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:296 296 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.


There are two problem here.

First, your argv array in your info structure is an array of pointers. These start out uninitialized. When you later call strcpy, giving one of these array elements as the first parameter, it expects that pointer to point to valid memory. So you end up dereferencing an uninitialized pointer. This invokes undefined behavior, which in this case manifests as a segfault.

You need to assign something to these pointers. You can either use strdup to make a copy of these strings:

info[i].argv[0] = strdup(argv[0]);
info[i].argv[1] = strdup(argv[1]);
info[i].argv[2] = strdup(argv[2]);

Or, if you don’t plan on modifying these values, you can just copy the pointer values directly:

info[i].argv[0] = argv[0];
info[i].argv[1] = argv[1];
info[i].argv[2] = argv[2];

The second issue is an off-by-one error in your loop:

for (int i=0; i<=10; i++){

Because you use <=, your indexes into the array will range from 0 to 10. However, your array only has 10 elements (with indexes 0 to 9), so you’re writing past the end of the array. This also invokes undefined behavior.

Change your conditional to < as follows:

for (int i=0; i<10; i++){

Понравилась статья? Поделить с друзьями:
  • Str object has no attribute append ошибка
  • Sun ошибка на стиральной машине самсунг
  • Sumitomo коды ошибок
  • Summoners war ошибка при соединении сети
  • Strcpy c ошибка c4996