How to make variable to be a literal string - c++

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.

Related

Trouble understanding __attribute__ tag

extern "C" int asnprintf (char **ret, size_t max_sz, const char *format, ...)
__attribute__ ((format (printf, 3, 4)));
Reading the source code of nmap I came accross this function declaration and I am having troubles understanding it.
Here is what this webpage says about it:
Based on
__attribute__((format(printf, m, n)));
The (m) is the number of the "format string" parameter, and (n) is the number of the first variadic parameter.
I don't understand what is he refering to when saying "format string"; are they just the arguments which affects the behaviour of the function?
Also, what is the number of the first variadic parameter? In all the examples I have seen it is always one more than m, is this always true? Could you give a practical example where is not?
Thanks.
extern "C" int asnprintf (char **ret, size_t max_sz, const char *format, ...)
^1 ^2 ^3 ^4
I don't understand what is he refering to when saying "format string"; are they just the arguments which affects the behaviour of the function?
The format string is the one you generally find in printf for example, like "%0.3f %s" ecc. and of course the function will act accordingly.
Also, what is the number of the first variadic parameter? In all the examples I have seen it is always one more than m, is this always true? Could you give a practical example where is not?
In that case, m = 3 and n = 4, but it need not be so. Let's say you have
int blablabla(const void *const data, const char *format, int data, ...)
then m = 2 and n = 4.
The answer is in the gcc manual:
The format attribute specifies that a function takes printf, scanf,
strftime or strfmon style arguments which should be type-checked
against a format string.
format (archetype, string-index, first-to-check)
The parameter archetype determines how the format string is
interpreted, and should be printf, scanf, strftime or strfmon. (You
can also use printf, scanf, strftime or strfmon.) The
parameter string-index specifies which argument is the format string
argument (starting from 1), while first-to-check is the number of the
first argument to check against the format string. For functions where
the arguments are not available to be checked (such as vprintf),
specify the third parameter as zero. In this case the compiler only
checks the format string for consistency. For strftime formats, the
third parameter is required to be zero. Since non-static C++ methods
have an implicit this argument, the arguments of such methods should
be counted from two, not one, when giving values for string-index and
first-to-check.

Is it possible to get attribute printf format checks on an expanded variadic template pack? [duplicate]

I have a C++ class that is the frontend for a logging system. Its logging function is implemented using C++11's variadic templates:
template <typename... Args>
void Frontend::log(const char *fmt, Args&&... args) {
backend->true_log(fmt, std::forward<Args>(args)...);
}
Each logging backend implements its own version of true_log, that, among other things, uses the forwarded parameters to call vsnprintf. E.g.:
void Backend::true_log(const char *fmt, ...) {
// other stuff..
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, buffer_length, fmt, ap);
va_end(ap);
// other stuff..
}
Everything works great, and I am happy.
Now, I want to add a static check on the log() parameters: specifically, I would like to use GCC's printf format attribute.
I started by tagging the log() function with __attribute__ ((format (printf, 2, 3))) (as this is the first "hidden" parameter, I need to shift parameter indices by one). This does not work, because if fails with a compilation error:
error: args to be formatted is not ‘...’
Then, I tried to add the same attribute to the true_log() function. It compiles, but no error checking is actually performed: I tried to pass to log() some invalid format/variable combinations, and no warning was issued. Maybe this kind of check is "too late", or, in other words, the information about the variable has been lost in the chain of calls?
As a last resort, if I annotated log() with __attribute__ ((format (printf, 2, 0))), I would receive warnings about wrong format strings, but no diagnostic would be issued for invalid format/variable combinations.
Summarizing the problem: how can I have full format checking from GCC if I use C++11's variadic templates?
I don't believe you can. I bet that GCC only verifies the format string if it's a literal. This is why putting the format attribute on true_log doesn't work - that function is called with what looks (syntactically) like a runtime-determined string. Putting it on log directly would circumvent that, but would require format attributes to support variadic template, which you proved it doesn't.
I suggest that you look at more C++-ish ways to do formatted output. There is, for example, boost::format which works kind of like printf, but dynamically verifies that the number and types of the parameters types match the format string. It doesn't use variadic templates, though, but instead consumes parameters fed to it (via operator %) one-by-one.
For the record, I ended up removing the C++11 variadic templates altogether, and using a traditional va_list.
__attribute__((format(printf, 2, 3)))
void Frontend::log(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
backend->true_log(fmt, ap);
va_end(ap);
}
void Backend::true_log(const char *fmt, va_list ap) {
// log the message somehow
}
There is a workaround if you are willing to use a macro.
There are constructs that will cause the compiler to do the checking for you, but will not generate any called code. One such construct is sizeof. So, you could use a macro for your logger to pass the arguments to printf directly but in the context of a sizeof calculation, and then call the logger itself.
The reason to use a macro is to make sure the format string is treated just like a string literal would be treated.
In the illustration below, I treat the sizeof calculation as a throwaway argument, but there should be other ways to apply the same technique.
template <typename... Ts>
void Frontend::log(size_t, const char *fmt, Ts&&... args) {
backend->true_log(fmt, std::forward<Ts>(args)...);
}
#define log(...) log(sizeof(printf(__VA_ARGS__)), __VA_ARGS__)
Try it online!
Of course, this is a workaround. There are numerous reasons not to use a macro. And in this case, the log macro would interfere with any other function or method with the same name.

Why would __FUNCTION__ be undefined?

I have a C++ library that uses the predefined macro __FUNCTION__, by way of crtdefs.h. The macro is documented here. Here is my usage:
my.cpp
#include <crtdefs.h>
...
void f()
{
L(__FUNCTIONW__ L" : A diagnostic message");
}
static void L(const wchar_t* format, ...)
{
const size_t BUFFERLENGTH = 1024;
wchar_t buf[BUFFERLENGTH] = { 0 };
va_list args;
va_start(args, format);
int count = _vsnwprintf_s(buf, BUFFERLENGTH, _TRUNCATE, format, args);
va_end(args);
if (count != 0)
{
OutputDebugString(buf);
}
}
crtdefs.h
#define __FUNCTIONW__ _STR2WSTR(__FUNCTION__)
The library (which is compiled as a static library, if that matters) is consumed by another project in the same solution, a WPF app written in C#.
When I compile the lib, I get this error:
identifier "L__FUNCTION__" is undefined.
According to the docs, the macro isn't expanded if /P or /EP are passed to the compiler. I have verified that they are not. Are there other conditions where this macro is unavailable?
You list the error as this:
identifier "L__FUNCTION__" is undefined.
Note it's saying "L__FUNCTION__" is not defined, not "__FUNCTION__".
Don't use __FUNCTIONW__ in your code. MS didn't document that in the page you linked, they documented __FUNCTION__. And you don't need to widen __FUNCTION__.
ETA: I also note that you're not assigning that string to anything or printing it in anyway in f().
Just use
L(__FUNCTION__ L" : A diagnostic message");
When adjacent string literals get combined, the result will be a wide string if any of the components were.
There's nothing immediately wrong with using L as the name of a function... it's rather meaningless however. Good variable and function identifiers should be descriptive in order to help the reader understand the code. But the compiler doesn't care.
Since your L function wraps vsprintf, you may also use:
L(L"%hs : A diagnostic message", __func__);
since __func__ is standardized as a narrow string, the %hs format specifier is appropriate.
The rule is found in 2.14.5p13:
In translation phase 6 (2.2), adjacent string literals are concatenated. If both string literals have the same encoding-prefix, the resulting concatenated string literal has that encoding-prefix. If one string literal has no encoding-prefix, it is treated as a string literal of the same encoding-prefix as the other operand. If a UTF-8 string literal token is adjacent to a wide string literal token, the program is ill-formed. Any other concatenations are conditionally-supported with implementation-defined behavior.
I think the definition of __FUNCTIONW__ is incorrect. (I know you did not write it.)
From: http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
These identifiers are not preprocessor macros. In GCC 3.3 and earlier,
in C only, __FUNCTION__ and __PRETTY_FUNCTION__ were treated as string
literals; they could be used to initialize char arrays, and they could
be concatenated with other string literals. GCC 3.4 and later treat
them as variables, like __func__. In C++, __FUNCTION__ and
__PRETTY_FUNCTION__ have always been variables.
At least in current GCC then you cannot prepend L to __FUNCTION__, because it is like trying to prepend L to a variable. There probably was a version of VC++ (like there was of GCC) where this would have worked, but you are not using that version.

How to use GCC's printf format attribute with C++11 variadic templates?

I have a C++ class that is the frontend for a logging system. Its logging function is implemented using C++11's variadic templates:
template <typename... Args>
void Frontend::log(const char *fmt, Args&&... args) {
backend->true_log(fmt, std::forward<Args>(args)...);
}
Each logging backend implements its own version of true_log, that, among other things, uses the forwarded parameters to call vsnprintf. E.g.:
void Backend::true_log(const char *fmt, ...) {
// other stuff..
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, buffer_length, fmt, ap);
va_end(ap);
// other stuff..
}
Everything works great, and I am happy.
Now, I want to add a static check on the log() parameters: specifically, I would like to use GCC's printf format attribute.
I started by tagging the log() function with __attribute__ ((format (printf, 2, 3))) (as this is the first "hidden" parameter, I need to shift parameter indices by one). This does not work, because if fails with a compilation error:
error: args to be formatted is not ‘...’
Then, I tried to add the same attribute to the true_log() function. It compiles, but no error checking is actually performed: I tried to pass to log() some invalid format/variable combinations, and no warning was issued. Maybe this kind of check is "too late", or, in other words, the information about the variable has been lost in the chain of calls?
As a last resort, if I annotated log() with __attribute__ ((format (printf, 2, 0))), I would receive warnings about wrong format strings, but no diagnostic would be issued for invalid format/variable combinations.
Summarizing the problem: how can I have full format checking from GCC if I use C++11's variadic templates?
I don't believe you can. I bet that GCC only verifies the format string if it's a literal. This is why putting the format attribute on true_log doesn't work - that function is called with what looks (syntactically) like a runtime-determined string. Putting it on log directly would circumvent that, but would require format attributes to support variadic template, which you proved it doesn't.
I suggest that you look at more C++-ish ways to do formatted output. There is, for example, boost::format which works kind of like printf, but dynamically verifies that the number and types of the parameters types match the format string. It doesn't use variadic templates, though, but instead consumes parameters fed to it (via operator %) one-by-one.
For the record, I ended up removing the C++11 variadic templates altogether, and using a traditional va_list.
__attribute__((format(printf, 2, 3)))
void Frontend::log(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
backend->true_log(fmt, ap);
va_end(ap);
}
void Backend::true_log(const char *fmt, va_list ap) {
// log the message somehow
}
There is a workaround if you are willing to use a macro.
There are constructs that will cause the compiler to do the checking for you, but will not generate any called code. One such construct is sizeof. So, you could use a macro for your logger to pass the arguments to printf directly but in the context of a sizeof calculation, and then call the logger itself.
The reason to use a macro is to make sure the format string is treated just like a string literal would be treated.
In the illustration below, I treat the sizeof calculation as a throwaway argument, but there should be other ways to apply the same technique.
template <typename... Ts>
void Frontend::log(size_t, const char *fmt, Ts&&... args) {
backend->true_log(fmt, std::forward<Ts>(args)...);
}
#define log(...) log(sizeof(printf(__VA_ARGS__)), __VA_ARGS__)
Try it online!
Of course, this is a workaround. There are numerous reasons not to use a macro. And in this case, the log macro would interfere with any other function or method with the same name.

C++ Error: String Formatting

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).