0

I am using C for a custom IOS library. Now I have upgraded my XCode to 5.0 developer preview. Now strcpy not work for me its crash the app at that point. Anyone can explain me what is the issue?

Update

Here is my code:

char global[] = " ";
printf("Error opening %s for constants input\n", lang); 
strcpy(global, lang); 

In printf lang is working and its but strcpy not working.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Shinning River
  • 813
  • 1
  • 10
  • 23
  • 9
    `strcpy` works fine. Your code has a bug. You'll need to find that bug and fix it. My crystal ball is currently broken so I cannot tell you what your bug is. – David Heffernan Sep 04 '13 at 09:28
  • 1
    Post the code. What have you done? –  Sep 04 '13 at 09:29
  • @NJMR Here is mycode char global[] = " ";printf("Error opening %s for constants input\n", lang); strcpy(global, lang); In printf lang is working and its but strcpy not working – Shinning River Sep 04 '13 at 09:38
  • @ShinningRiver Please don't post code in comments. Edit your question to include it and then you can format it. – David Heffernan Sep 04 '13 at 09:46

4 Answers4

5

When you declare global as

char global[] = " ";

It only is enough space for two characters. The space and the string terminator. Either set a size big enough to contain the whole string you try to copy to it, or make it a pointer and allocate it dynamically (in which case you should not forget to allocate space for the string terminator).

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • In lang I have a string of 5 character like "av-dv". Its work perfect in xcode 4.6 but create problem in Xcode 5 – Shinning River Sep 04 '13 at 10:09
  • 2
    @ShinningRiver Please realize that if someone of repute here says "your code is broken because X", it's more polite of you try to understand X than say "no it's not, it worked for me". Code can be perfectly broken yet still *happen* to work when you test it, that's one of the joys of unsafe programming languages. :) – unwind Sep 04 '13 at 10:11
  • Out of curiosity, is there any safe programming language, given your context of safe? – jnovacho Sep 04 '13 at 10:48
  • @ShinningRiver That's the joy of [*undefined behavior*](http://en.wikipedia.org/wiki/Undefined_behavior), you can't really predict how it will work. Sometimes it crashes, sometimes it *seems* to work (but you overwrite data somewhere, making something else unrelated possibly not working). – Some programmer dude Sep 04 '13 at 11:04
1

Avoid using strcpy, unless you are absolutely sure you have enough space in the target array.

Try this for a safe version. It still works quite bad, because lang probably does not fit, but it is safe.

char global[] = " ";

// alternative 1
snprintf(global, sizeof global, "%s", lang);

// alternative 2, more lines but also slightly more efficient
global[0] = 0;
strncat(global, lang, (sizeof global) - 1); // -1 needed to allow room for '\0'

For reference, man pages of snprintf and strncat.


To solve the space issue, you should probably make global big enough to hold all possible lang strings, if you know the limit and it is reasonably small:

char global[16] = ""; // room for 15 characters, contents initialized to all 0
snprintf(global, sizeof global, "%s", lang);

Alternative is to use dynamic memory:

int bufsize = strlen(lang) + 1;
char *global = malloc(bufsize); // contents uninitialized
// can't use sizeof, it would give size of pointer, not allocated buffer
snprintf (global, bufsize, "%s", lang);
...
free(global); global = NULL;

For using dynamic memory, also check out asprintf, documented in same man page as snprintf (link above).

You can also consider using Variable Length Arrays of C99, though if variable name is global, it will probably not work for your case:

char global[strlen(lang) + 1] = ""; // +1 for '\0', contents initialized to all 0
snprintf (global, sizeof global, "%s", lang); // now sizeof works again
// global is unallocated when it goes out of scope

Note that with dynamic memory, where you allocated enough memory for current contents of lang, you could use strcpy too, because then it is a case where you do know it fits safely. Still, using safe versions may be more robust against future modifications introducing new bugs.

hyde
  • 60,639
  • 21
  • 115
  • 176
0

The most likely cause for the error is that the global array is not long enough to contain lang. Without knowing the value of lang, we cannot say for certain. As it stands, if lang contains more than a single character and the null-terminator, then the call to strcpy results in buffer overrun.

You need to make sure that global is large enough to contain the contents of lang. You state in a comment that lang is an iso language code of the form "**-**". The example you give is "ad-dv". If you are sure that lang is never more than 6 characters long (including the null-terminator) then you can write your code like this:

char global[6];
strcpy(global, lang); 

The other obvious option is to allocate the string dynamically:

char *global = malloc(strlen(lang)+1);
strcpy(global, lang); 

Remember to call free(global) when you have finished with the variable.

The other common failure mode for strcpy is that the source string is not null-terminated which also leads to buffer overrun.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Sorry I am not C developer.I have set it to global = lang but its showing error for me.Array type char[5] not assignable – Shinning River Sep 04 '13 at 09:53
  • I'm sorry, I don't understand that. – David Heffernan Sep 04 '13 at 10:12
  • @ShinningRiver `global = lang` is trying to assign to array variable, which is not allowed in C (except the special case of defining it and initializing from string literal, `char global[] = "foo";` is allowed). – hyde Sep 04 '13 at 11:21
0

Being the writer of the original C-code I think it's in order for me to explain.

A more complete and accurate piece of the code:

char predictLanguage[] = "    ";

void openPredictionConstants(char* language){
  strcpy(predictLanguage, language);

  if ((file = fopen(strcat(DATFILEPATH, predictLanguage), "_constants"), ".dat"), "rb")) == NULL){
    printf("Error opening %s for constants input\n", filename);
    exit(EXIT_FAILURE);
  }
  // Code for processing if file is opened successfully
}

The languageparameter is always a 5-char locale, i.e. "en-GB", "en-US" etc., so a statically allocated char array is fine for the job.

However, the predictLanguage parameter is only 4 chars long + 0-termination for 5 chars total. language is 5 chars + 0-termination for a total of 6 chars. In other words - and as several people already pointed out - predictLanguage is not long enough to contain the locale passed in language.

Under normal circumstances I would have initialized the char array with a defined length, like char predictLanguage[6], but because I wanted to make sure predictLanguage didn't contain garbage I initialized it with an empty string.

Turns out I had a brain fart when counting out the spaces and came up with the incorrect length. The error just didn't manifest itself in iOS6.

Woodgnome
  • 2,281
  • 5
  • 28
  • 52