Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'strncpy' vs. 'sprintf'

Tags:

c

printf

strncpy

I can see many sprintf's used in my applications for copying a string.

I have a character array:

char myarray[10];
const char *str = "mystring";

Now if I want want to copy the string str into myarray, is is better to use:

sprintf(myarray, "%s", str);

or

strncpy(myarray, str, 8);

?

like image 911
Vijay Avatar asked Sep 05 '12 06:09

Vijay


People also ask

Why is Sprintf unsafe?

Warning: The sprintf function can be dangerous because it can potentially output more characters than can fit in the allocation size of the string s . Remember that the field width given in a conversion specification is only a minimum value. To avoid this problem, you can use snprintf or asprintf , described below.

Which is better strcpy or strncpy?

strcpy( ) function copies whole content of one string into another string. Whereas, strncpy( ) function copies portion of contents of one string into another string. If destination string length is less than source string, entire/specified source string value won't be copied into destination string in both cases.

What can I use instead of strncpy?

C11 Annex K specifies the strncpy_s() and strncat_s() functions as close replacements for strncpy() and strncat(). The strncpy_s() function copies not more than a specified number of successive characters (characters that follow a null character are not copied) from a source string to a destination character array.

What is the difference between Sprintf and Snprintf?

The main difference between sprintf and snprintf is that in snprintf, the buffer number to be specified in the function which is represented by 'n' in snprintf. While doing concatenation, the functions are used differently in both sprintf and snprintf.


3 Answers

Neither should be used, at all.

  1. sprintf is dangerous, deprecated, and superseded by snprintf. The only way to use the old sprintf safely with string inputs is to either measure their length before calling sprintf, which is ugly and error-prone, or by adding a field precision specifier (e.g. %.8s or %.*s with an extra integer argument for the size limit). This is also ugly and error-prone, especially if more than one %s specifier is involved.

  2. strncpy is also dangerous. It is not a buffer-size-limited version of strcpy. It's a function for copying characters into a fixed-length, null-padded (as opposed to null-terminated) array, where the source may be either a C string or a fixed-length character array at least the size of the destination. Its intended use was for legacy unix directory tables, database entries, etc. that worked with fixed-size text fields and did not want to waste even a single byte on disk or in memory for null termination. It can be misused as a buffer-size-limited strcpy, but doing so is harmful for two reasons. First of all, it fails to null terminate if the whole buffer is used for string data (i.e. if the source string length is at least as long as the dest buffer). You can add the termination back yourself, but this is ugly and error-prone. And second, strncpy always pads the full destination buffer with null bytes when the source string is shorter than the output buffer. This is simply a waste of time.

So what should you use instead?

Some people like the BSD strlcpy function. Semantically, it's identical to snprintf(dest, destsize, "%s", source) except that the return value is size_t and it does not impose an artificial INT_MAX limit on string length. However, most popular non-BSD systems lack strlcpy, and it's easy to make dangerous errors writing your own, so if you want to use it, you should obtain a safe, known-working version from a trustworthy source.

My preference is to simply use snprintf for any nontrivial string construction, and strlen+memcpy for some trivial cases that have been measured to be performance-critical. If you get in a habit of using this idiom correctly, it becomes almost impossible to accidentally write code with string-related vulnerabilities.

like image 122
R.. GitHub STOP HELPING ICE Avatar answered Oct 03 '22 02:10

R.. GitHub STOP HELPING ICE


The different versions of printf/scanf are incredibly slow functions, for the following reasons:

  • They use variable argument lists, which makes parameter passing more complex. This is done through various obscure macros and pointers. All the arguments have to be parsed in runtime to determine their types, which adds extra overhead code. (VA lists is also quite a redundant feature of the language, and dangerous as well, as it has farweaker typing than plain parameter passing.)

  • They must handle a lot of complex formatting and all different types supported. This adds plenty of overhead to the function as well. Since all type evaluations are done in runtime, the compiler cannot optimize away parts of the function that are never used. So if you only wanted to print integers with printf(), you will get support for float numbers, complex arithmetic, string handling etc etc linked to your program, as complete waste of space.

  • Functions like strcpy() and particularly memcpy() on the other hand, are heavily optimized by the compiler, often implemented in inline assemble for maximum performance.

Some measurements I once made on barebone 16-bit low-end microcontrollers are included below.

As a rule of thumb, you should never use stdio.h in any form of production code. It is to be considered as a debugging/testing library. MISRA-C:2004 bans stdio.h in production code.

EDIT

Replaced subjective numbers with facts:

Measurements of strcpy versus sprintf on target Freescale HCS12, compiler Freescale Codewarrior 5.1. Using C90 implementation of sprintf, C99 would be more ineffective yet. All optimizations enabled. The following code was tested:

  const char str[] = "Hello, world";
  char buf[100];

  strcpy(buf, str);
  sprintf(buf, "%s", str);

Execution time, including parameter shuffling on/off call stack:

strcpy   43 instructions
sprintf  467 instructions

Program/ROM space allocated:

strcpy   56 bytes
sprintf  1488 bytes

RAM/stack space allocated:

strcpy   0 bytes
sprintf  15 bytes

Number of internal function calls:

strcpy   0
sprintf  9

Function call stack depth:

strcpy   0 (inlined)
sprintf  3 
like image 24
Lundin Avatar answered Oct 03 '22 02:10

Lundin


I would not use sprintf just to copy a string. It's overkill, and someone who reads that code would certainly stop and wonder why I did that, and if they (or I) are missing something.

like image 20
Thomas Padron-McCarthy Avatar answered Oct 03 '22 02:10

Thomas Padron-McCarthy