How to convert current strcpy to strcpy_s?
Asked Answered
I

3

6

I have large project having strcpy used everywhere. I am thinking to use strcpy_s instead of strcpy. I think almost 10,000 times I have used strcpy. It's so cumbersome to change every strcpy. Is there any efficient way for conversion?

Incise answered 3/5, 2017 at 9:31 Comment(11)
You mean besides the obvious? (I.e. global s&r, then fix everything that is broken). Everyplace that breaks, by definition, needs inspection anyway, so branch your code and see how bad the malaise is.Sandalwood
strcpy_s() is pointless anyway.Hernando
Since the size of dest could be declared anywhere, it seems very hard to do anything in an automated way.Resurrect
10,000 times! And why is this tagged C++?Kisung
@EOF strcpy_s() is pointless anyway. Vendor lock-in.Juniper
@AndrewHenle strcpy_s() is nowadays part of the C standard, with the C11 bounds-checking interface.Schoolhouse
@Schoolhouse Thanks. I missed that over the years. So it's a sane implementation of strncpy() then?Juniper
@AndrewHenle No, it is a bounds-checking version of strcpy(). strncpy() was never intended to be used for that - it was in fact not originally intended to be used for null-terminated strings.Schoolhouse
@Schoolhouse strncpy() was never intended to be used for that - it was in fact not originally intended to be used for null-terminated strings So you're saying it's the naming of strncpy() that's insane, given that all the other str*() functions are intended for nul-terminated strings? ;-)Juniper
@AndrewHenle When they decided what would go into the standard library, they were looking at which functions that already existed in UNIX. Lots of unmentionable substances were smoked and the result was a pretty random, completely inconsistent standard library, with lots of outright bad and broken things in it. As for the specific case of strncpy, here is the history: #2115396Schoolhouse
Consider n1967 which proposes "... that Annex K be either removed from the next revision of the C standard, or deprecated and then removed." Sure you want to switch code to strcpy_s()? Recommend reading the "Common Mistakes" section to see what you are getting into.Bolero
U
6

You really shouldn't do this without inspecting since the point of tightening up buffer management is lost if it's not done intelligently.

Since the nature of the destination buffer (static or heap allocation, for instance) is very important when it comes to the proper arguments for strcpy_s(), and that information of course is not present in the existing strcpy() call, you must add it in any way. This requires a human.

Often a call like strcpy(dest, src); can be transformed into strcpy_s(dest, sizeof dest, src);, but if dest is heap-allocated this will just be the size of the pointer rather than the pointed-at buffer which of course is wrong.

Ulberto answered 3/5, 2017 at 9:39 Comment(2)
You'd have to be sure dest was declared an array! Because if dest is pointer this is typically be a code breaking catastrophe.Geaghan
To further add confusion, at least one C++ vendor (MS) provides a template wrapper for deducing the size_t argument when using a declared-fixed destination char array (i.e. char dst[N]; strcpy_s(dst, src);). Thusly, depending on the language and vendor, blanket replacement of strcpy with strcpy_s will compile correctly in such use cases, leaving the places where compilation breaks being the actual raw pointers for dest arguments. I never know whether to thank them or curse them for that.Sandalwood
G
2

Given that you have to provide an additional parameter that can't be deduced (size_t destsz) that is required to be accurate to benefit from the change you've got a real problem.

An application with 10,000 uses of strcpy() sounds insane but you are where you are.

First If your time/resources are limited then all I can suggest is a bit of risk assessment. Which calls are copying external data (from a file, the operating system, the user, a port or socket, etc.). Focus on making sure those don't overwrite and you'll be reducing risk more effectively.

Second If you've got any standard variable names and standard 'max sizes' you might be able to do a bit of global search and replace.

Say if you use filename a lot and filenames are up to 255 characters (plus NUL) on your platform you can replace strcpy(filename, with (say) strcpy_s(filename,FILENAME_MAX_SZ.

If the code is 'all over the place' you've got a lot of work cut out.

Replacing strcpy(v, with strcpy_s(v,SIZE_MAX (use regular expressions) is a superficial bodge that doesn't actually gain you anything except for potentially sneaking under your organisations code quality script. I did not tell you to do this! ;)

Third If you want to take a stroll in the world of C11 _Generic you can try something like:

#define __STDC_WANT_LIB_EXT1__

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

int strcpy_s(char *dest,size_t destsz,const char *src){
    if(strlen(src)>=destsz){
        return 1;
    }
    strcpy(dest,src);
    return 0;
}

char *d_strcpy(char *dest,const char *src){
#ifndef NDEBUG
 fprintf(stdout,"unsafe copy of %s\n",src);
#endif
    return strcpy(dest,src);
}


#define strcpy(dest,src) _Generic (dest,\
    char[100] : strcpy_s(dest,sizeof dest,src),\
    char*: d_strcpy(dest,src)\
    )

int main(void) {
    char a[100]={'A','B','\0'};
    char *b=malloc(10*sizeof(char));

    strcpy(a,"XXX");
    strcpy(b,"XYX");

    printf("%s %s\n",a,b);

    free(b);
    return 0;
}

Unfortunately you do need to specify the array size so need to be using probably a limited list of 'max sizes' and while this should work on Clang (untested) it fails on GCC because they don't agree how to resolve the controlling type! See Document: N1930 (controlling expression of _Generic)

Happy hunting.

Geaghan answered 3/5, 2017 at 9:43 Comment(1)
The controlling type thingie has been agreed upon. GCC was right.Tristis
S
2

Why do you want to replace the strcpy() function? There is nothing wrong with strcpy. Dogmatically changing it to strcpy_s won't fix anything. What you need to do is to consider each and every individual case:

  • Is the size of the source buffer known and is its contents verified?
  • Is the source buffer even of a dynamic nature? Can it vary in size or do you know the maximum size at compile time?
  • Is the size of the target buffer large enough? Is it at all pointing at allocated memory?

This isn't something unique to strcpy or even strings, but something that must be considered for every array in your code.

Schoolhouse answered 3/5, 2017 at 13:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.