C++ Error: String Formatting - c++

Here is my code:
void subroutine(const char *message) { printf(message); }
And here is the error I get:
Error: In function ' ': warning: format not a string literal and no format arguements [-Wformat-security]
What is the error here? I can't solve it.
Any suggestions?

You should use
printf("%s", message);
Longer explanation:
printf treats its first argument as format specifier. If you are lucky and the message doesn't contain %s or other substrings special for printf, the message will be printed "as is".
But if the message contains something like that, your program will try to interpret other arguments to printf as the parameters. As there are no actual arguments, it will, for example, consider some arbitrary memory location as a pointer, and try to dereference it. This would in the best case lead to a crash; in the worst case, this may leak some sensitive data.
(printf can even overwrite some memory if %n is encountered in the format string.)

You can solve it by doing
printf("%s", message);
Or use something else, such as fputs() instead of printf.
gcc warns you because it doesn't know the format string you supply to printf, and thus the arguments cannot be verified.
Imagine you call your function like
message("It's 100%s");
That ends up being printf("It's 100%s"); , which is wrong and ends up causing undefined behavio since the format string contains a %s, and you need to supply an additional argument to printf that's a string..

If you pass "%d" to subroutine, you're going to be in big trouble since printf will look for another argument.
The compiler kindly warns you that if message contains format specification, the program may crash.
You can use vprintf if you intend to write something like
void subroutine(const char *message, ...)
{
va_list args;
va_start(args, format);
vprintf(message, args);
va_end(args);
}
but if you just want to display message, use puts(message) or printf("%s", message).

Related

Coverity issue: Copy of overlapping memory (OVERLAPPING_COPY) on sprintf statement

char arr[512];
...
sprintf(arr, "%s %30s", arr, "Some Text");
I'm getting the following message for the sprintf statement:
In the call to function sprintf, the arguments arr and arr may point to the same object.
Is there another way to implement this kind of formatting?
This code code contains two unrelated errors. As for the PVS-Studio analyzer, it issues two following warnings:
V576 Incorrect format. A different number of actual arguments is expected while calling 'sprintf' function. Expected: 4. Present: 3. test.cpp 54
V541 It is dangerous to print the 'arr' string into itself. test.cpp 54
The first one implies that the function is passed insufficient number of actual arguments. Indeed, the format string indicates that a string and an integer number are expected as arguments. But only a string is passed. There is no numeric argument, resulting in the usage of an amount of memory with a random value and consequently undefined behavior.
The second warning tells us that there is no guarantee that the sprintf function works correctly if one buffer is used as an input and output buffer. Such code might work correctly or it might not. It all depends on the implementation of the sprintf function. In any case, there is no reason to write code in such a way.
Therefore, Coverity is absolutely right when issuing the warning for this code. The code is definitely incorrect.
P.S. It reminded me of another funny case related to the usage of a "fake sprintf" :).
The overlapping warning has to do with the fact that you are copying arr to itself, thus overwriting it's content.
Furthermore in the code:
sprintf(arr, "%s %0x", arr);
^^^
%s takes the arr string, but %0x doesn't take an unsigned hexadecimal integer variable as it should, so you are probably missing a parameter.
Something along the lines of:
char arr[512];
char arr2[1024];
unsigned int x = 15;
sprintf(arr2, "%s %0x", arr, x);

How to make variable to be a literal string

Code as below:
FILE *sfp;
....
void test(char *s, ...)
{
va_list ap;
va_start(ap, s);
vfprintf(sfp, s, ap);
fflush(sfp);
va_end(ap);
}
below compile error reported:
error: format string is not a string literal [-Werror,-Wformat-nonliteral]
vfprintf(sfp, s, ap);
How to fix this error?
A variable is never a string literal. A string literal is a sequence of characters surrounded by double quote marks (i.e. "foo").
The purpose of that warning is to warn you that the compiler cannot confirm that the types of the parameters given to vfptrintf match the format string. To get rid of that warning, you will need to either
Pass a literal format string to vfprintf (i.e. vfprintf(sfp, "%d\n", ap))
Disable (or rather, don't enable) that warning and accept that the compiler cannot warn you if your arguments don't match the format specifier.
Add the format attribute to your function declaration (thanks to #chris in the comments):
i.e.
__attribute__((format(printf, 2, 3)))
void test(FILE* sfp, const char *s, ...)
{
//...
}
Or with the standardized C++11 attribute syntax:
[[gnu::format(printf, 2, 3)]]
void test(FILE* sfp, const char *s, ...)
{
//...
}
Note that that last option is not a standard C++ attribute, and therefore will not work on all compilers. You may need something else to appease MSVC for example. By the standard, compilers should ignore unknown attributes if you use the C++11 syntax, but they may still emit a warning about it, putting you right back in the same situation you're in now.
You will also still provoke a warning if test is called with a second argument that is not itself a string literal.
As a side note, it doesn't look like clang can check the argument types of the va_list printf functions anyway, so -Wformat-nonliteral isn't actually helpful in this case. GCC does not emit this warning, likely for that exact reason.

vsnprintf crash program in case %s is set with an integer

I'm writing a logger in C++ and to simplify entering lines I use vsnprintf function to build log line
void CLogger::RegManLog(const LogLevel & logLevelMask, char * Format, ...)
...
...
va_start(marker_, Format);
vsnprintf(buffer_ ,MaxLogBuffSize , Format, marker_)
va_end(marker_);
printer_ += buffer_;
...
...
every thing works great up until I accidently enter a number into a string
integer test = 10;
eg.: "now I'll show a string %s" , test
tried to add "try and catch", but I think vsnprintf does have throw, so it crashes any way.
tried to get return value from vsnprintf, it return value, while string are fine, when reaching the same issue, it crashes
any thoughts of I can i solve this issue?
thanks
%s expects to get a char*. When you pass in 10, it treats it like an address, goes there and kills your program.
If you wish to print integers, use %d. For more information look at http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html
In C++ it is best to use other methods to accomplish what you need, like std::stringstream
You could avoid printf and friends and instead use std::stringstream or boost::format
Well, when passed to printf() and family, the %s formatter is here as a placeholder for a -eventually const- char * pointer.
What is happening, is that your integer is read as a pointer, and it's likely that the memory address (10 in your example) is invalid.

printf with std::string?

My understanding is that string is a member of the std namespace, so why does the following occur?
#include <iostream>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString);
cin.get();
return 0;
}
Each time the program runs, myString prints a seemingly random string of 3 characters, such as in the output above.
C++23 Update
We now finally have std::print as a way to use std::format for output directly:
#include <print>
#include <string>
int main() {
// ...
std::print("Follow this command: {}", myString);
// ...
}
This combines the best of both approaches.
Original Answer
It's compiling because printf isn't type safe, since it uses variable arguments in the C sense1. printf has no option for std::string, only a C-style string. Using something else in place of what it expects definitely won't give you the results you want. It's actually undefined behaviour, so anything at all could happen.
The easiest way to fix this, since you're using C++, is printing it normally with std::cout, since std::string supports that through operator overloading:
std::cout << "Follow this command: " << myString;
If, for some reason, you need to extract the C-style string, you can use the c_str() method of std::string to get a const char * that is null-terminated. Using your example:
#include <iostream>
#include <string>
#include <stdio.h>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString.c_str()); //note the use of c_str
cin.get();
return 0;
}
If you want a function that is like printf, but type safe, look into variadic templates (C++11, supported on all major compilers as of MSVC12). You can find an example of one here. There's nothing I know of implemented like that in the standard library, but there might be in Boost, specifically boost::format.
[1]: This means that you can pass any number of arguments, but the function relies on you to tell it the number and types of those arguments. In the case of printf, that means a string with encoded type information like %d meaning int. If you lie about the type or number, the function has no standard way of knowing, although some compilers have the ability to check and give warnings when you lie.
Please don't use printf("%s", your_string.c_str());
Use cout << your_string; instead. Short, simple and typesafe. In fact, when you're writing C++, you generally want to avoid printf entirely -- it's a leftover from C that's rarely needed or useful in C++.
As to why you should use cout instead of printf, the reasons are numerous. Here's a sampling of a few of the most obvious:
As the question shows, printf isn't type-safe. If the type you pass differs from that given in the conversion specifier, printf will try to use whatever it finds on the stack as if it were the specified type, giving undefined behavior. Some compilers can warn about this under some circumstances, but some compilers can't/won't at all, and none can under all circumstances.
printf isn't extensible. You can only pass primitive types to it. The set of conversion specifiers it understands is hard-coded in its implementation, and there's no way for you to add more/others. Most well-written C++ should use these types primarily to implement types oriented toward the problem being solved.
It makes decent formatting much more difficult. For an obvious example, when you're printing numbers for people to read, you typically want to insert thousands separators every few digits. The exact number of digits and the characters used as separators varies, but cout has that covered as well. For example:
std::locale loc("");
std::cout.imbue(loc);
std::cout << 123456.78;
The nameless locale (the "") picks a locale based on the user's configuration. Therefore, on my machine (configured for US English) this prints out as 123,456.78. For somebody who has their computer configured for (say) Germany, it would print out something like 123.456,78. For somebody with it configured for India, it would print out as 1,23,456.78 (and of course there are many others). With printf I get exactly one result: 123456.78. It is consistent, but it's consistently wrong for everybody everywhere. Essentially the only way to work around it is to do the formatting separately, then pass the result as a string to printf, because printf itself simply will not do the job correctly.
Although they're quite compact, printf format strings can be quite unreadable. Even among C programmers who use printf virtually every day, I'd guess at least 99% would need to look things up to be sure what the # in %#x means, and how that differs from what the # in %#f means (and yes, they mean entirely different things).
use myString.c_str() if you want a c-like string (const char*) to use with printf
thanks
Use std::printf and c_str()
example:
std::printf("Follow this command: %s", myString.c_str());
You can use snprinft to determine the number of characters needed and allocate a buffer of the right size.
int length = std::snprintf(nullptr, 0, "There can only be %i\n", 1 );
char* str = new char[length+1]; // one more character for null terminator
std::snprintf( str, length + 1, "There can only be %i\n", 1 );
std::string cppstr( str );
delete[] str;
This is a minor adaption of an example on cppreference.com
printf accepts a variable number of arguments. Those can only have Plain Old Data (POD) types. Code that passes anything other than POD to printf only compiles because the compiler assumes you got your format right. %s means that the respective argument is supposed to be a pointer to a char. In your case it is an std::string not const char*. printf does not know it because the argument type goes lost and is supposed to be restored from the format parameter. When turning that std::string argument into const char* the resulting pointer will point to some irrelevant region of memory instead of your desired C string. For that reason your code prints out gibberish.
While printf is an excellent choice for printing out formatted text, (especially if you intend to have padding), it can be dangerous if you haven't enabled compiler warnings. Always enable warnings because then mistakes like this are easily avoidable. There is no reason to use the clumsy std::cout mechanism if the printf family can do the same task in a much faster and prettier way. Just make sure you have enabled all warnings (-Wall -Wextra) and you will be good. In case you use your own custom printf implementation you should declare it with the __attribute__ mechanism that enables the compiler to check the format string against the parameters provided.
The main reason is probably that a C++ string is a struct that includes a current-length value, not just the address of a sequence of chars terminated by a 0 byte. Printf and its relatives expect to find such a sequence, not a struct, and therefore get confused by C++ strings.
Speaking for myself, I believe that printf has a place that can't easily be filled by C++ syntactic features, just as table structures in html have a place that can't easily be filled by divs. As Dykstra wrote later about the goto, he didn't intend to start a religion and was really only arguing against using it as a kludge to make up for poorly-designed code.
It would be quite nice if the GNU project would add the printf family to their g++ extensions.
Printf is actually pretty good to use if size matters. Meaning if you are running a program where memory is an issue, then printf is actually a very good and under rater solution. Cout essentially shifts bits over to make room for the string, while printf just takes in some sort of parameters and prints it to the screen. If you were to compile a simple hello world program, printf would be able to compile it in less than 60, 000 bits as opposed to cout, it would take over 1 million bits to compile.
For your situation, id suggest using cout simply because it is much more convenient to use. Although, I would argue that printf is something good to know.
Here’s a generic way of doing it.
#include <string>
#include <stdio.h>
auto print_helper(auto const & t){
return t;
}
auto print_helper(std::string const & s){
return s.c_str();
}
std::string four(){
return "four";
}
template<class ... Args>
void print(char const * fmt, Args&& ...args){
printf(fmt, print_helper(args) ...);
}
int main(){
std::string one {"one"};
char const * three = "three";
print("%c %d %s %s, %s five", 'c', 3+4, one + " two", three, four());
}

c++ _vsnprintf unexpected format string

I have a logging function that takes in a variable number of arguments and uses _vsnprintf to format them. My problem is that when I debug my OCR automation the string it returns is sent to the log, so if the file said something like this:
This bitmap says %n
then it would get sent to my logging function like this:
void log(LPCSTR msg, ...)
{
char log[MAX_ALLOWED];
int length = sizeof(log) / sizeof(log[0]);
va_list argptr;
va_start( argptr, pzMsg );
// our msg accidentally has a %
if ( strchr(msg, '%') ) {
// debug assertion - no parameters were passed
_vsnprintf( log, length, msg, argptr );
}
log[length-1] = (char)0;
va_end( arg_ptr );
}
is there a way, along with the check for '%' that i can check if there were no arguments? thank you.
The traditional way to make sure something can't be expanded by printf is
log("%s", yourString);
Of course, you could also add a variant of log that only takes one argument, or you could count the number of variable arguments and not format the string if there aren't any.
If I understand you correctly, you would like to check the number of arguments actually passed to log().
Unfortunately, this is highly machine-specific. I know of only one architecture which provides an unambiguous argument count. That is the VAX. All the others depend on the caller and the callee to "get it right".