Thoughts on C-language string functions

Source: Internet
Author: User

C language is not a very convenient language, and its string is an example. According to the C language definition, "a string is a piece of memory space, which contains ASCII characters and ends with" \ 0 ". It can store a total of N-1 characters ." According to this description, string processing is indeed troublesome and error-prone.

To make it easier for you, the c Standard Library provides you with some string functions, such as copying, constructing, and clearing strings. However, I accidentally discovered that these functions still have some potential risks.

The process is very simple. I noticed that some programs I wrote always have memory read/write errors. However, after carefully checking all the data buffers and related processing functions, I did not find any errors. So I turned to some of my commonly used string processing functions, such as strcpy and sprintf. After several careful tracking, I found that memory errors come from this. So I began to study how to safely use strings.

1 string copying function 1.1 unsafe strcpy
First, I wrote a test function:

Void strcpyTest0 ()

{

Int I;

Char szBuf [128];

For (I = 0; I <128; I ++) szBuf [I] = '*';

SzBuf [127] = '\ 0'; // construct a string of all characters *

Char szBuf2 [256];

For (I = 0; I <256; I ++) szBuf2 [I] = '#';

SzBuf2 [255] = '\ 0'; // construct a string that is all #

Strcpy (szBuf, szBuf2 );

Printf ("% s \ n", szBuf );

}

It is easy to copy a string to another space. However, unfortunately, the source string is longer than the target address, so the program died sadly.

1.2 or insecure strncpy
In the previous example, I found that I needed to input another parameter during the copy operation to indicate how long the destination address is. Check the Library Function Description in C language and there is a strncpy to achieve this purpose, the prototype of this function is as follows:

Char * strncpy (char * strDest, const char * strSource, size_t count );

Now we have solved the problem. I wrote the following code:

Void strcpyTest1 ()

{

Int I;

Char szBuf [128];

For (I = 0; I <128; I ++) szBuf [I] = '*';

SzBuf [127] = '\ 0 ';

Char szBuf2 [256];

For (I = 0; I <256; I ++) szBuf2 [I] = '#';

SzBuf2 [255] = '\ 0 ';

Strncpy (szBuf, szBuf2, 128 );

Printf ("% s \ n", szBuf );

}

Everything looks good, but when I output the results, I find the problem. Sometimes there are several strange characters behind the string, and it seems that "\ 0" is not used to end, so I changed the copy statement above to "strncpy (szBuf, szBuf2, 8);" and only copied 8 characters. The problem occurred and the program output was as follows:

########******************************** **************************************** **************************************** *******

Sure enough, when the requested target address space is smaller than the source string space, strncpy will no longer end the string with "\ 0. Great potential risks.

1.3 secure string copy Function
I think I need to copy the function as follows:

1. An integer is allowed to define the size of the target address space.

2. When the target address space nD is less than the source String Length nS, only nD bytes should be copied.

3. In any case, the destination address space should end with "\ 0" to maintain a valid string identity. Therefore, the maximum length of the obtained string is the nD-1.

So I wrote such a string copy function:

Void xg_strncpy1 (char * pD, char * pS, int nDestSize)

{

Memcpy (pD, pS, nDestSize );

* (PD + nDestSize-1) = '\ 0 ';

}

It's EASY. No, just output 7 "#" in the example above. The result is correct.

1.4 memory read errors
I thought it was okay. However, it wasn't long before I found a strange phenomenon. This function was wrong in the Debug mode of VC, but everything went fine in the Release mode.

After a long time, I finally couldn't help it. I decided to solve this problem. I replaced the above memcpy with my own replication loop and tracked it in a single step to see what happened?

The reason is found. I want to copy a 256-byte long string, but an error occurred while copying it to 33rd Bytes. Check the program and find that my source string space is only 32 Bytes, the code above only prevents writing out of the memory, but does not check the read out. In the Debug mode of VC, the read out of the memory is also an invalid error, so an error is reported.

After knowing the cause, the solution is simple. I changed the copy function to the following shape:

Void xg_strncpy2 (char * pD, char * pS, int nDestSize)

{

Int nLen = strlen (pS) + 1;

If (nLen> nDestSize) nLen = nDestSize;

Memcpy (pD, pS, nLen );

* (PD + nLen-1) = '\ 0 ';

}

Everything is OK.

2 string constructor 2.1 insecure sprintf
As in the previous example, while modifying the copy function, I also thought of another common string constructor sprintf. Obviously, this function does not define the size of the target address space, the following code will cause a crash:

Void sprintfTest0 ()

{

Int I;

Char szBuf [128];

For (I = 0; I <128; I ++) szBuf [I] = '*';

SzBuf [127] = '\ 0 ';

Char szBuf2 [256];

For (I = 0; I <256; I ++) szBuf2 [I] = '#';

SzBuf2 [255] = '\ 0 ';

Sprintf (szBuf, szBuf2 );

Printf ("% s \ n", szBuf );

}

2.2 or insecure _ snprintf
Read the library function manual and find such a function _ snprintf. Its function prototype is as follows:

Int _ snprintf (char * buffer, size_t count, const char * format [, argument]...);

This function allows defining the target address size. However, due to the study of the copy function experience, I suspect it also has the same issue with strncpy, so I wrote such a code test:

Void sprintfTest1 ()

{

Int I;

Char szBuf [128];

For (I = 0; I <128; I ++) szBuf [I] = '*';

SzBuf [127] = '\ 0 ';

Char szBuf2 [256];

For (I = 0; I <256; I ++) szBuf2 [I] = '#';

SzBuf2 [255] = '\ 0 ';

_ Snprintf (szBuf, 8, szBuf2 );

Printf ("% s \ n", szBuf );

}

Sure enough, the program output is as follows:

########******************************** **************************************** **************************************** *******

The same error does not end with "\ 0". I must try another method.

In addition, we also found another deficiency, that is, at this time, the _ snprintf function returns-1 and no longer returns the number of printed characters. If we use the following code, a logical error will occur, it may even crash:

Char szBuf [256];

Int nCount = 0;

While (1) // here indicates the cyclic structure

{

NCount + = _ snprintf (szBuf + nCount, 256-nCount, "..."); // multiple strings are constructed into one string

}

Note that the Code uses the value returned by _ snprintf to determine the next starting point, which is very common, but when _ snprintf returns-1, it may be written to * (szBuf-1) the typical memory write field.

2.3 safe string Constructor
After careful consideration, I constructed the following function:

Int xg_printf (char * szBuf, int nDestSize, char * szFormat ,...)

{

Int nListCount = 0;

Va_list pArgList;

Va_start (pArgList, szFormat );

NListCount + = _ vsnprintf (szBuf + nListCount,

NDestSize-nListCount, szFormat, pArgList );

Va_end (pArgList );

* (SzBuf + nDestSize-1) = '\ 0 ';

Return strlen (szBuf );

}

Note: Here I use the Variable Parameter Function Design to make it as convenient as sprintf. In addition, the last return is also very important, because in many cases, we need to know exactly how many characters are printed. After this function is substituted into the above example, everything works normally.

Summary: C-language string library functions may be used to improve performance. when the conditions are insufficient, they often return directly and forget to use "\ 0" to end the string. This will cause the data boundary to be uncontrollable during the next string reading. Formatting and printing functions. The return value is not always a positive integer, which may cause logical risks. Therefore, if you are interested, refer to the two functions I provide.

In addition, the above is only for my personal test. It is limited to my own level. You are welcome to discuss it. If you need the source code above, please contact me

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.