Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is StringCbprintf and how's this different than general sprintf?

I am going through a previously written code and I found StringCbPrintf() function

I found declaration on msdn site like this :

HRESULT StringCbPrintf(
  _Out_  LPTSTR pszDest,
  _In_   size_t cbDest,
  _In_   LPCTSTR pszFormat,
  _In_    ...
);

What is _in_ and _out_ here ?

And why is it needed when we already have sprintf() ?

like image 672
Omkant Avatar asked Nov 07 '12 11:11

Omkant


3 Answers

_In_ and _Out_ (note: neither _in_/_out_ as you wrote, nor __In__/__Out__ with double underscores, as written in some other answer) are so called SAL Annotations. They can be used with /analyze compiler option, and can help identify bugs and problems like buffer overruns etc. with raw C buffers and pointers. In addition to MSDN documentation on SAL, you can read also this blog post.

Someone ironically (and wrongly) wrote that:

"In the rest of the world, inputs are const pointers but I guess that was too simple. :)"

missing the fact that SAL is more powerful than that. In fact, with SAL you can also specify the maximum size of a destination buffer, indicating which parameter contains the destination buffer size; e.g. if you open <strsafe.h> header, you can read that the actual SAL annotations used for StringCbPrintfW (the Unicode version of StringCbPrintf) is something like that:

STRSAFEAPI
StringCbPrintfW(
    __out_bcount(cbDest) STRSAFE_LPWSTR pszDest,
    __in size_t cbDest,
    __in __format_string STRSAFE_LPCWSTR pszFormat,
    ...)
{
    ....

Note how the __out_bcount(cbDest) SAL annotation applied to the pszDest parameter specifies that this is a pointer to an output buffer (__out), which size is expressed in bytes (_bcount) by the parameter cbDest. As you can see, this is a rich annotation (richer than simple "const" or "non const").

In my opinion, SAL is kind of useless if you write C++ code with robust container classes like std::vector or std::string, which know their own size, etc. But SAL can be useful in C-ish code with raw pointers (like several Win32 APIs).

About the second part of your question:

"Why we need StringCbPrintf if we already have sprintf"

the main reason is that sprintf is an unsafe and buffer overruns-prone function; instead with StringCbPrintf you must specify the maximum size of the destination buffer, and this can help preventing buffer overruns (which are security enemies).

like image 86
Mr.C64 Avatar answered Oct 23 '22 22:10

Mr.C64


The documentation tries to explain that for you:

Compared to the functions it replaces, StringCbPrintf provides additional processing for proper buffer handling in your code. Poor buffer handling is implicated in many security issues that involve buffer overruns. StringCbPrintf always null-terminates a nonzero-length destination buffer.

The __In__ and __Out__ decorators are used in Microsoft API:s to denote how a pointer argument is used. In the rest of the world, inputs are const pointers but I guess that was too simple. :)

like image 3
unwind Avatar answered Oct 23 '22 20:10

unwind


As it is said here:

StringCbPrintf is a replacement for the following functions:

  • sprintf, swprintf, _stprintf
  • wsprintf
  • wnsprintf
  • _snprintf, _snwprintf, _sntprintf

So it doesn't only replace sprintf, but also those to work with wchar, for example. It also introduces additional buffer processing to prevent buffer overruns (as stated in the same msdn article). It also always null-terminates the destination buffer. _in_ and _out_ are there to show you which parameters are input ones, and which are output ones. Those are most likely #defined as nothing, and go away before the compilation begins.

like image 2
SingerOfTheFall Avatar answered Oct 23 '22 22:10

SingerOfTheFall