0

When I use the whole code in the main function it works perfectly but now I want to use the function for some "Strings" which I initialize in a 2D-Array.

The idea behind the function is to create a product of a struct globally initialized. The line with strcpy gives the error:

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).

I am using Xcode 11.3.1 on a Mac.

Can you guys help me with that?

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

struct produkt neues_angebot(char *produktname);

struct produkt{
    char name[5];
    int produkt_zahl;
    float produkt_preis;
};

struct produkt neues_angebot(char *produktname){
    time_t t;
    srand((unsigned) time(&t));
    struct produkt Zwischenname = {
        "xxx",(rand() % 49),((rand()% 600)/100)
    };
    strcpy(Zwischenname.name, produktname);
    return Zwischenname;     
}

int main(int argc, const char * argv[]) {
    char teste[]="hello";
    printf("%s\n",neues_angebot(teste).name); 
}
Sinval
  • 1,315
  • 1
  • 16
  • 25

2 Answers2

2

Strings in C are null terminated. The string "hello" uses 6 bytes of storage: the 5 characters h e l l o plus the terminating null character.

Now strcpy does no length checking, so strcpy(Zwischenname.name, produktname) will attempt to copy all 6 of those bytes into the array Zwischenname.name, which only has space for 5 bytes. That overflows the array and is undefined behavior - the crash you observed is one of the many possible results.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • It is UB but it does not write outside the struct allocated space. For sure it will not end that way. – 0___________ Feb 07 '21 at 17:15
  • Thanks a lot! Is there any elegant way to reserve memory? Maybe using malloc etc. – Anton Gnudliw Feb 07 '21 at 17:20
  • Though the answer may not be complete, there is no sufficient reason for a dv, imo. – anastaciu Feb 07 '21 at 17:44
  • @0___________ *It is UB but it does not write outside the struct allocated space.* Irrelevant. If the function `neues_angebot()` writes the `'\0'` terminator outside the space for the `name` field in the structure, when that structure in the function is returned by value, the padding that was overwritten by the `strcpy() ` call is returned with an indeterminate value. So this answer is correct. – Andrew Henle Feb 07 '21 at 17:47
  • @0___________: Well, I don't know about OP's setup, but on my system (gcc 9.3.0 on Ubuntu 20.04 with `-O2`), gcc emits a call to the `__strcpy_chk` function which checks the destination against the length of the destination (which is known at compile time) and aborts the program if exceeded. So the program does crash, though not with the same message that OP sees. – Nate Eldredge Feb 07 '21 at 18:59
  • @AntonGnudliw: One design would be to have `product.name` be a pointer instead of an array, and use `malloc` to allocate a buffer of appropriate size for the string that is to be stored there. This does mean that you are then responsible for freeing it later, though. – Nate Eldredge Feb 07 '21 at 19:02
1

The strcpy will copy the last character of teste, the null terminator '\0', to outside the bounds of the the destination buffer as it is one byte shorter than it needs to be, this will cause Zwischenname.name to not be null terminated.

The problem is printf will need the null-terminator to know where the string ends in order work correctly, passing a non null-terminated character array as an argument to printf("%s", argument); invokes undefined behavior.

Remember, in order for an array of characters to be treated as a propper string it needs to be null terminated, many library fuctions in C rely on this principle. Always make sure that it is.

anastaciu
  • 23,467
  • 7
  • 28
  • 53