I am porting Einstein#Home (Radio Pulsar Edition) to Solaris and am stuck on erp_execinfo_plus.c that reports the error below.
builder#bertha:~/brp/src$ g++ -g -I/export/home/builder/brp/install/include/libxml2 -I/export/home/builder/brp/install/include/boinc -I/usr/gnu/include -I/export/home/builder/brp/install/include -DHAVE_INLINE -DBOINCIFIED -DUSE_CPU_RESAMP -DUSE_FFTW_FFT -DNDEBUG -DLOGLEVEL=info -ggdb3 -rdynamic -O3 -Wall -fprofile-use -c /export/home/builder/brp/src/erp_extract.c
/export/home/builder/brp/src/erp_extract.c:8:12: error: expected initializer before 'VPARAMS'
void fatal VPARAMS ((const char *format, ...)) {
^~~~~~~
/export/home/builder/brp/src/erp_extract.c:16:16: error: expected initializer before 'VPARAMS'
void non_fatal VPARAMS ((const char *format, ...)) {
^~~~~~~
I have tried numerous iterations to correct the issue by moving code blocks around, redefining them as a struct and overloading. I have even used gcc and the gcc/g++ preprocessor outputs to find the error to no avail.
gcc:
/export/home/builder/brp/src/erp_extract.c:16:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'VPARAMS'
NOTES:
The erp_extract.c file is the minimum source code to reproduce the error.
The #include is the default binutils sysdef.h
erp_extract.c
#include "sysdep.h"
static FILE *ostream; /* output stream */
void fatal(const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
void non_fatal(const char *, ...) ATTRIBUTE_PRINTF_1;
void report(const char *, va_list) ATTRIBUTE_PRINTF(1,0);
void fatal VPARAMS ((const char *format, ...)) {
VA_OPEN (args, format);
VA_FIXEDARG (args, const char *, format);
report(format, args);
VA_CLOSE (args);
}
void non_fatal VPARAMS ((const char *format, ...)) {
VA_OPEN (args, format);
VA_FIXEDARG (args, const char *, format);
report(format, args);
VA_CLOSE (args);
}
void report(const char * format, va_list args)
{
vfprintf(ostream, format, args);
putc ('\n', ostream);
}
Related
I wrote a very simple test code to test vsnprintf, but in xcode and visual studio environment, the results are very different. The test code is as follows:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include <cstdarg>
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
vsprintf(defaultBuf, fmt, args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
vsnprintf(defaultBuf, DefaultLength, fmt, args);
printf("%s\n", defaultBuf);
va_end(args);
}
int main(int argc, const char* argv[])
{
// if you uncomment this line(std::cout ...), it will crash at vsnprintf in xcode
std::cout << "Tests...!\n";
p("Create:%s(%d)", "I'm A String", 0x16);
return 0;
}
this is the output in visual studio :
Tests...!
Create:I'm A String(22)
Create:I'm A String(22)
This is normal and doesn't seem to be a problem. But the same code, I created a macos command line project, pasted this code in, something strange happened, when the code is executed to vsnprintf, it will start EXC_BAD_ACCESS directly.
What's more outrageous is that if I comment out the std::cout in the main function, it will not crash, but the output is wrong. So the question is, what is the reason for this difference, shouldn't these functions all be functions of the C standard library, and their behavior should be constrained by the standard library? Or is my usage wrong?
the output when i delete std::cout:
Create:I'm A String(22)
Create:\310\366\357\277\367(3112398)
Program ended with exit code: 0
If only one is right, is xcode right or visual studio is right, in the end I used is the latest xcode 14, visual studio 2022。
You must reinitialize the va_list between calls to vsprintf. Failure to do so is undefined behavior.
See https://en.cppreference.com/w/c/variadic/va_list :
If a va_list instance is created, passed to another function, and used via va_arg in that function, then any subsequent use in the calling function should be preceded by a call to va_end.
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
vsprintf(defaultBuf, fmt, args);
va_end(args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
va_start(args, fmt);
vsnprintf(defaultBuf, DefaultLength, fmt, args);
va_end(args);
printf("%s\n", defaultBuf);
}
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
va_list args_r;
va_copy(args_r, args);
vsprintf(defaultBuf, fmt, args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
vsnprintf(defaultBuf, DefaultLength, fmt, args_r);
printf("%s\n", defaultBuf);
va_end(args_r);
va_end(args);
}
I have a printf-style function that takes a variable number of arguments. Here is my starting point:
#include <stdio.h>
#include <stdarg.h>
void MyPrint (const char* fmt,...)
{
va_list arglist ;
va_start (arglist, fmt) ;
vprintf (fmt, arglist) ;
va_end (arglist) ;
}
int main()
{
MyPrint ("Hello, %s\n", "world") ;
}
This prints Hello, world as expected.
Now I want to make two changes. First, I want to check the format string using the format attribute of g++. So I declare the MyPrint function first (I have to declare it first, because for some reason g++ doesn't let you assign attributes to a function definition):
void MyPrint (const char* fmt,...) __attribute__ ((format (printf, 1, 2))) ;
Now if I try e.g. MyPrint ("Hello, %d\n", "world") ; I get a nice error message.
The second change I want to make is to use a variadic template parameter. Like this:
#include <utility> // for std::forward
template<typename...Params>
void MyPrint (Params&&... fmt)
{
printf (std::forward<Params> (fmt)...) ;
}
This works too. So I combine the two, by adding the format-checking attribute to the variadic function template with this forward declaration:
template<typename...Params>
void MyPrint (Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;
But now I get this error message (gcc 10.2):
<source>: In substitution of 'template<class ... Params> void MyPrint(Params&& ...) [with Params = {const char (&)[11], const char (&)[6]}]':
<source>:15:38: required from here
<source>:8:6: error:
'format' attribute argument 2 value '1' refers to parameter type
'const char (&)[11]'
This has got me completely baffled. Can anybody tell me what I'm doing wrong?
Here is the complete program:
#include <stdio.h>
#include <utility> // for std::forward
template<typename...Params>
void MyPrint (Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;
template<typename...Params>
void MyPrint (Params&&... fmt) // <-- Line 8
{
printf (std::forward<Params> (fmt)...) ;
}
int main()
{
MyPrint ("Hello, %s\n", "world") ; // <-- Line 15
}
You can make the first error go away by adding a fixed const char * argument as the format string and pointing the attribute to that.
template<typename...Params>
void MyPrint (const char * format, Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;
template<typename...Params>
void MyPrint (const char * format, Params&&... fmt) // <-- Line 9
{
printf (format, std::forward<Params> (fmt)...) ;
}
Which reveals another error:
test.cc:8:6: error: ‘format’ attribute argument 3 value ‘2’ does not refer to a variable argument list
8 | void MyPrint (const char * format, Params&&... fmt) // <-- Line 9
| ^~~~~~~
It seems that the attribute for checking the printf archetype relies on one const char * argument and a variable argument list and is not willing to work without them. So you have to give up either the C++ template magic or the compile-time format string checking.
The following code produces warning about wrong format specifier in all major compilers
std::wstring ws = L"some example string";
char buff[100];
sprintf(buff, "%s", ws.c_str());
The warning disappears if we use it in 'variadic' context (variadic template or va_list).
std::wstring ws = L"some example string";
void foo_va_list(const char* fmt, ...)
{
va_list argv;
va_start( argv, fmt );
char buff[1000];
vsprintf(buff, fmt, argv);
va_end(argv);
}
template<typename ... T>
void foo_variadic_template(const char* fmt, T && ... args)
{
char buff[100];
sprintf(buff, fmt, args...);
}
int main()
{
//this two should produce a warning but don't
foo_va_list("foo_va_list %s", ws.c_str());
foo_variadic_template("foo_variadic_template %s", ws.c_str());
char buff[100];
//this one produces warning as expected
sprintf(buff, "sprintf %s", ws.c_str());
}
The question is how to enable this warning in this context?
some compilers have an extension for the [s]printf functions and can "understand" the given format string and check the used format specifier against the used arguments.
Obviously these checks can not work if you hide this relation in your own implementation.
I have the following defined:
void LogMessage(PCTSTR text);
void LogMessage(PCTSTR format, ...);
If I just want to call the function with one parameter, I get the following error message:
Source.cpp(10): error C2668: 'Log' : ambiguous call to overloaded function
could be 'void Log(PCTSTR,...)' or 'void Log(PCTSTR)'
while trying to match the argument list '(const wchar_t [42])'
Is it possible to do a static_cast to explizite use the first version? Or haw can this be solved, except by renaming the first or second function?
How about the following? I haven't tested on VC++ (which seems to be your platform of choice) but hopefully the version you are using implements enough C++11 for this to work.
#include <iostream>
#include <cstdio>
#include <cstdarg>
void LogMessageWorker(char const* format, ...)
{
// 1k should be enough for anyone... ;)
char buf[1024] = { 0 };
// The version of vsnprint called should always null terminate correctly and doesn't
// strictly need the -1 but I believe that the implementation that is included with
// VC++ leaves a lot to be desired so you may need to slightly tweak this.
va_list args;
va_start (args, format);
vsnprintf (buf, sizeof (buf) - 1, format, args);
va_end (args);
std::cout << "LogMessage: " << buf << std::endl;
}
template <class... Arguments>
void LogMessage(char const* format, Arguments... arguments)
{
LogMessageWorker (format, std::forward<Arguments>(arguments)...);
}
void LogMessage(char const* text)
{
LogMessageWorker ("%s", text);
}
int main(int argc, char **argv)
{
LogMessage ("The test is starting...");
for (int i = 0; i < 3; i++)
LogMessage ("This is test #%d", i);
LogMessage ("This contains the % character and still it works (%d-%d-%d-%d)");
return 0;
}
I'm trying to suppress -Wformat-nonliteral warnings. I have used attribute((format(printf with success elsewhere but the following example eludes me.
exceptions.hpp
class Exceptions {
...
static void fthrow(Thread* thread, const char* file, int line, Symbol* name,
const char* format, ...);
};
exceptions.cpp
__attribute__((format(printf, 5, 6)))
void Exceptions::fthrow(Thread* thread, const char* file, int line, Symbol* h_name, const char* format, ...) {
const int max_msg_size = 1024;
va_list ap;
va_start(ap, format);
char msg[max_msg_size];
vsnprintf(msg, max_msg_size, format, ap);
msg[max_msg_size-1] = '\0';
va_end(ap);
_throw_msg(thread, file, line, h_name, msg);
}
result
exceptions.cpp:229:16: error: format argument not a string type
__attribute__((format(printf, 5, 6)))
^ ~
exceptions.cpp:235:32: error: format string is not a string literal [-Werror,-Wformat-nonliteral]
vsnprintf(msg, max_msg_size, format, ap);
^~~~~~
Since it is a static, the exact index should be used, but I've tried 4, 5 and 6, 7 (if out by one) with similar fail.
The attribute should be set on the declaration of the function, not the definition.
class Exceptions {
...
static void fthrow(Thread* thread, const char* file, int line, Symbol* name,
const char* format, ...) __attribute__((format(printf, 5, 6)));
};