Following program crashes in 64 bit system. This code is working fine in 32 bit system
I am using centOS 32 bit and centOS 64 bit sytems..
what will be the reason for this ?
#if 1
if (1)
{
memset(message1, '\0', sizeof(message1));
vsprintf(message1, format, vAList);
}
#endif
if (1)
{
//PROGRAM CRASHES in the following line IF AM PUTTING #if 1 in the above code as i did
val = vfprintf(logFile, format,vAList);
}
when program reaches val = vfprintf(logFile,format,vAList);
here it crashes in 64 bit system..
You can't use a variadic argument list twice. vfprintf "uses up" the arguments and the next call probably tries to access memory after the list. In the words of the man page:
These functions [v*printf] do not call the va_end macro. Consequently, the value of ap is undefined after the call. The application should call va_end(ap) itself afterwards.
If your format requires dereferencing, like the %s format, chances are that your program crashes.
You can solve that in two ways: Either wrap all calls to vfprintf in their own va_start and va_end:
int f(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
return 0;
}
Or make a copy of the variadic list:
int f(const char *fmt, ...)
{
va_list va, vb;
va_start(va, fmt);
va_copy(vb, va);
vprintf(fmt, va);
vprintf(fmt, vb);
va_end(va);
va_end(vb);
return 0;
}
(You must make the copy before the list you copy from has been used.)
Edit: Forgot to clean up the copied va lis, vb in the second example. Fixed now.
Related
I am trying to write a macro which gets the information and sends that information to another function by splitting the orginal va_list into string and another va_list spawned from the original one.
Below is my code.
Call to macro
/* Usage */
PRINT_LOG("Format log = %d, %f, %s", 1, 2.7, "Test");
My code below
/* my includes here */
#include <stdarg.h>
void printInfo(int level, const char *debugInfo, ...); /* defined in 3rd party API */
void formatLogs(int level, ...);
#define PRINT_LOG(...) formatLogs(0, __VA_ARGS__)
void formatLogs(int level, ...)
{
va_list args;
va_start(args, level);
/* get the first argument from va_list */
const char *debugString = va_arg(args, const char*);
/* here I want to get the rest of the variable args received from PRINT_LOG*/
va_list restOfArgs = ???????; /* restOfArgs should be 1, 2.7, "Test" */
/* Below I want to send the rest of the arguments */
printInfo(level, debugString, args);
va_end(args);
}
Is it possible to send some part of va_list as va_list to another function?? If so, how can i do it?
Thank you very much in advance.
The simplest thing to do, based on the code in your question, is to redefine the macro like so:
#define PRINT_LOG(s, ...) printInfo(0, s, __VA_ARGS__)
and just skip the intermediate function altogether. Because what you're trying to do can't be done like that.
The , ...) variable argument ellipsis is not a va_list. The variable arguments passed to a function aren't realized as a va_list until va_start is invoked. To pass a va_list as a function argument, the function has to have a va_list in its signature, like this:
int vprintf(const char *format, va_list argList);
I have to change this code fragment from varargs.h to stdarg.h, but I do not know exactly how to:
#ifndef lint
int ll_log (va_alist)
va_dcl
{
int event, result;
LLog *lp;
va_list ap;
va_start (ap);
lp = va_arg (ap, LLog *);
event = va_arg (ap, int);
result = _ll_log (lp, event, ap);
va_end (ap);
return result;
}
When I try build this, compiler says:
error "GCC no longer implements <varargs.h>."
error "Revise your code to use <stdarg.h>."
The program, which I need to compile and run, has a few similar fragments and I need to know how to change them. If you can write some example, I'll be content.
<varargs.h> is a pre-standard C header; use <stdarg.h> instead. The differences:
The function must take at least one named argument.
The function must be prototyped (using the ellipsis terminator).
The va_start macro works differently: it takes two arguments, the first being the va_list to be initialized and the second the name of the last named argument.
Example:
int ll_log (LLog *llog, ...) {
int event, result;
LLog *lp;
va_list ap;
va_start (ap, llog);
lp = llog;
event = va_arg (ap, int);
result = _ll_log (lp, event, ap);
va_end (ap);
return result;
}
Regarding va_start: gcc ignores the second argument, but not giving the correct one is not portable.
You have to include
#include <stdarg.h>
va_ Macro syntax stays the same.
I want to have something like a cross platform snprintf function, so I'm trying to use this (perhaps there are other solutions, but I'm wondering exactly that):
void string_print(char *str, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
#ifdef _WIN32
sprintf_s(str, size, format, args);
#else
snprintf(str, size, format, args);
#endif
va_end(args);
}
Example of usage:
// timeStepNumber == 1
char fileName[40];
string_print(fileName, 40, "Flow%d.dat", timeStepNumber);
But in this case I have fileName == "Flow-14843.dat", although va_arg(args, int) == 1. Can anybody explain, what maybe wrong in the string_print function?
You need to use vsnprintf/vsnprintf_s functions with vararg lists.
vsnprintf(str, size, format, args);
As indicated by imbtfab, use vsnprintf() in place of snprintf() and _vsnprintf() in place of sprintf_s.
i have this chunk of code
static void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{
int errno_save;
unsigned long n;
char buf[MAXLINE];
errno_save = errno;
#ifdef HAVE_VSNPRINTF
vsnprintf(buf, sizeof(buf), fmt, ap); /* this is safe */
#else
vsprintf(buf ,fmt, ap); /* this is not safe */
#endif
n = strlen(buf);
if (errnoflag)
snprintf(buf + n, sizeof(buf) - n, ": %s", strerror(errno_save));
strcat(buf, "\n");
if (daemon_proc) {
syslog(level,"%s", buf);
} else {
fflush(stdout);
fputs(buf, stderr);
fflush(stderr);
}
return;
}
when i compile it (Clang 5.0.0 with -Weverything) i obtain those warnings:
Building C object lib/netutils/CMakeFiles/netutils.dir/error.c.o
/Users/User/Desktop/project.cmake/lib/netutils/error.c:98:16: warning: format string is not a string literal [-Wformat-nonliteral]
vsprintf(buf ,fmt, ap); /* this is not safe */
^~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/secure/_stdio.h:66:57: note: expanded from
macro 'vsprintf'__builtin___vsprintf_chk (str, 0, __darwin_obsz(str), format, ap)
^
the same thing happens with this other function vsnprintf(buf, sizeof(buf), fmt, ap);
how can i fix this warning?
Thanks
Apparently the solution is to tell Clang that your vsnprintf is called within a function that implements the behaviour of the printf family of functions by, well, calling vsnprintf. You do this with an attribute, as described here:
__attribute__((__format__ (__printf__, 3, 0)))
static void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{
...
}
This checks whether the format string is a literal on the calling function. As err_doit takes already a va_list, you should specify the format on the functions that call it, too. The second number, which is 0 here, should then be the argument index of the variadic argument, .... See also this discussion.
Function attributes are a non-standard extension of gcc, which is also implemented for Clang. If you want to keep the code compiler independent, you should wrap the attributes in a macro that hides it for compilers that don't know attributes.
(Disclaimer: I couldn't check this with Clang, but it works for gcc. Edit: fixed wrong argument index in example)
This question already has answers here:
Passing an ellipsis to another variadic function [duplicate]
(4 answers)
Closed 8 years ago.
Old client code:
printf("foo: %d, bar: %s.\n", f, b);
What I'd like to replace that printf (& 100's others like it) with:
my_printf(ctrl1, ctrl2, "foo: %d, bar: %s.\n", f, b);
Implementation of my_printf
void my_printf(CtrlT1 c1, Ctrl c2, char* fmt, ...) {
/* Do stuff with c1 & c2 */
fprintf(log, fmt, **WHAT_GOES_HERE**);
}
What I've tried so far
It seems like there ought to be a simple, direct way to pass the list of arguments associated with ... through to fprintf. I tried fprintf(log, fmt, ...); but the compiler complains, "syntax error before '...' token".
I also tried:
va_list ap;
va_start(ap, fmt);
fprintf(log, fmt, ap);
The call with the va_list compiles and even runs without coring, but what's being passed to printf is plainly not the same thing as what was passed into my function as ..., as may be judged by the output (representation of non-printing char).
If push comes to shove, I could probably walk through the contents of the va_list by brute-force but that seems stupid. Is there no simple token or syntax to pass that ... through?
This isn't a general solution, but for the stdio functions, look at the ones that start with the letter v, such as vfprintf. They take a va_list as their last parameter, instead of the ....
void my_printf(CtrlT1 c1, Ctrl c2, char* fmt, ...) {
/* Do stuff with c1 & c2 */
va_list ap;
va_start (ap, fmt);
vfprintf (log, fmt, ap);
va_end (ap);
}