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?
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.
dest
was declared an array! Because if dest
is pointer this is typically be a code breaking catastrophe. –
Geaghan 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 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.
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.
© 2022 - 2024 — McMap. All rights reserved.
strcpy_s()
is pointless anyway. – Hernandodest
could be declared anywhere, it seems very hard to do anything in an automated way. – Resurrectstrcpy_s()
is nowadays part of the C standard, with the C11 bounds-checking interface. – Schoolhousestrncpy()
then? – Juniperstrcpy()
.strncpy()
was never intended to be used for that - it was in fact not originally intended to be used for null-terminated strings. – Schoolhousestrncpy()
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 ofstrncpy()
that's insane, given that all the otherstr*()
functions are intended for nul-terminated strings? ;-) – Juniperstrncpy
, here is the history: #2115396 – Schoolhousestrcpy_s()
? Recommend reading the "Common Mistakes" section to see what you are getting into. – Bolero