Variable length arguments in log4cxx LOG4CXX_ macros - thread-safety

I am using log4cxx in a big C++ project but I really don't like how log4cxx handles multiple variables when logging:
LOG4CXX_DEBUG(logger, "test " << var1 << " and " << var3 " and .....)
I prefer using printf like variable length arguments:
LOG4CXX_DEBUG(logger, "test %d and %d", var1, var3)
So I implemented this small wrapper on top of log4cxx
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <log4cxx/logger.h>
#include "log4cxx/basicconfigurator.h"
const char * log_format(const char *fmt, ...);
#define MYLOG_TRACE(logger, fmt, ...) LOG4CXX_TRACE(logger, log_format(fmt, ## __VA_ARGS__))
#define MYLOG_DEBUG(logger, fmt, ...) LOG4CXX_DEBUG(logger, log_format(fmt, ## __VA_ARGS__))
#define MYLOG_INFO(logger, fmt, ...) LOG4CXX_INFO(logger, log_format(fmt, ## __VA_ARGS__))
#define MYLOG_WARN(logger, fmt, ...) LOG4CXX_WARN(logger, log_format(fmt, ## __VA_ARGS__))
#define MYLOG_ERROR(logger, fmt, ...) LOG4CXX_ERROR(logger, log_format(fmt, ## __VA_ARGS__))
#define MYLOG_FATAL(logger, fmt, ...) LOG4CXX_FATAL(logger, log_format(fmt, ## __VA_ARGS__))
static log4cxx::LoggerPtr logger(log4cxx::Logger::getRootLogger());
int main(int argc, char **argv)
{
log4cxx::BasicConfigurator::configure();
MYLOG_INFO(logger, "Start ");
MYLOG_WARN(logger, "In running this in %d threads safe?", 1000);
MYLOG_INFO(logger, "End ");
return 0;
}
const char *log_format(const char *fmt, ...)
{
va_list va;
static char formatted[1024];
va_start(va, fmt);
vsnprintf(formatted, 1024, fmt, va);
va_end(va);
return formatted;
}
And this works perfectly but I know using that static variable (formatted) can become problematic if I start using threads and each thread logging to the same place.
I am no expert in log4cxx so I was wondering if the LOG4CXX macros are handling concurrent thread access automatically? or do I have to implement some sort of locking around the log_format method? something that I wan't to avoid due to performance implications.
To compile and test this program (in Ubuntu) use :
g++ -o loggertest loggertest.cpp -llog4cxx

Those convenience macros are standard C macros.
I can see nothing in there that would make them protect a function you define from clobbering its own static data.
The macros do use C++ so you should be able to return a std::string from your log_format function and thus avoid the problem.

This thread states that log4cxx is indeed thread safe.
http://old.nabble.com/thread-safe-log4cxx-td17721835.html
May want to test just to make sure though...

Related

How to use __VA_ARGS__ variadic in 8051

I'm trying to build a project 8051 in Keil IDE.
I have a definition to print information for purposes debug program as following:
#define LOGI(fmt, ...) printf("[I] %s:%u: "fmt, __FILE__, __LINE__, ##__VA_ARGS__)
But there are errors:
log.h(18): error C301: identifier expected
log.h(18): error C301: identifier expected
log.h(18): error C304: bad macro parameter list
Please help me fix this code, thank you.
According to the documentation, Keil C51 is based on C90. So it does not support __VA_ARGS__ that is a C99 addition.
However, you can work around this for example by this trick. Use a parenthesized argument.
#define LOGI(args) \
do { \
printf("[I] %s:%u: ", __FILE__, __LINE__); \
printf args; \
} while (0)
void f(void) {
LOGI(("address of f() = %p\n", f));
}
Another possible solution is to provide an own function with a variable number of arguments, see the example in the documentation. This is a cleaner way because you can use this function without a "hick-up" when reading the source code because of the double parentheses. But be aware that these arguments are not placed in registers, and more memory on stack and in code is used.
#include <stdio.h>
#include <stdarg.h>
void logi(const char* filename, int line, char *fmt, ...) {
va_list arg_ptr;
va_start(arg_ptr, fmt);
printf("[I] %s:%u: ", filename, line);
vprintf(fmt, arg_ptr);
va_end(arg_ptr);
}
void f(void) {
logi(__FILE__, __LINE__, "Hello %u %u", 1 , 2);
}
Note: You might want to switch to another compiler, which supports some newer standard than a 30 years old one.

linux hw_breakpoint does not work while accessing memory from userspace

I am debugging a ARMv7 board and I want to know whether a kernel symbol is accessed. So I have to use hw_breakpoint in kernel.
For simplicity, I use kernel sample code:data_breakpoint to test, which locates in samples/hw_breakpoint/data_breakpoint.c.
Then I did the following operation:
insmod data_breakpoint.ko ksym=max
cat /proc/kallsyms | grep max
./read_kmem c06fa128
But this did not trigger the callback function.
If I print the value in that address in any kernel module, callback function will be triggered.
I read the cpu manual and it says that the breakpoint register in my cpu support virtual address matching. But I don't know why it doesn't work while accessing memory from userspace. I think that program does read the right value of kernel symbol.
read_kmem.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#define DEVKMEM "/dev/kmem"
#define PAGE_SIZE 0x1000
#define PAGE_MASK (~(PAGE_SIZE-1))
int main(int argc, char* argv[])
{
int fd;
char *mbase;
char read_buf[10];
unsigned int varAddr;
varAddr = strtoul(argv[1], 0, 16);
unsigned int ptr = varAddr & ~(PAGE_MASK);
fd = open(DEVKMEM, O_RDONLY);
if (fd == -1) {
perror("open");
exit(-1);
}
mbase = mmap(0,PAGE_SIZE,PROT_READ,MAP_SHARED,fd, (varAddr & PAGE_MASK));
if (mbase == MAP_FAILED) {
printf("map failed %s\n",strerror(errno));
}
printf("varAddr = 0x%X \n", varAddr);
printf("mapbase = 0x%X \n", (unsigned int)mbase);
printf("value = 0x%X \n",*(unsigned int*)(mbase+ptr));
close(fd);
munmap(mbase,PAGE_SIZE);
return 0;
}
Your userspace does not access address c06fa128, it accesses a different address - one that that mmap() returned (plus offset). Thus no breakpoint hit.
The fact that virtual address being accessed resolves to same physical address as some other virtual address that has a breapoint, does not matter. CPU executing your userspace code has no idea that different mapping exists.

"struct has no member named" error with gcc on dev machine

#include <stdio.h>
#include <stdlib.h>
#include "ReadMethods.h"
int main(int argc,char * argv[])
{
DPDA WordChecker;
DPDA * WordCheckerPointer=&WordChecker;
WordChecker.DPDAFilename=(char*)malloc(25*sizeof(char));
WordChecker.DPDAInputFilename=(char*)malloc(25*sizeof(char));
WordChecker.DPDAOutputFilename=(char*)malloc(25*sizeof(char));
strcpy( WordChecker.DPDAFilename,argv[1]);
strcpy( WordChecker.DPDAInputFilename,argv[2]);
strcpy( WordChecker.DPDAOutputFilename,argv[3]);
readDPDA(argv[1],WordCheckerPointer);
readInputLines(argv[2],WordCheckerPointer,argv[3]);
return 0;
}
This is my code that gives error from mallocs until last strcpy() ,total 6 lines.The error is "DPDA has no member named DPDAFilename" and same for other fields for every malloc and strcpy linesthat i work on.Here is the part of header file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tagRule{
char *startingState;
char symbolToPop;
char expectedInput;
char *endingState;
char symbolToPush;
}Rule;
typedef struct tagStackDPDA{
char * arrayOfSymbols;
int stackElementCount;
char * currentState;
}stackDPDA;
typedef struct tagDPDA{
char * alphabet;
char * stackSymbols;
char ** states;
char *startingState;
char **finalStates;
int finalStatesAmount;
Rule * ruleList;
stackDPDA stackOfDPDA;
int sizeArray[4];//This array holds amount values of states,alphabet symbols,stack symbols and transition rules
char *DPDAFilename;
char *DPDAInputFilename;
char *DPDAOutputFilename;
}DPDA;
The code works fine in codeblocks environment but in gcc (-Wall -ansi).Those filenames come from input text files yet i am not sure it can cause this error.
Edit:By the way I am using this command line to compile;
gcc -Wall -ansi main.c ReadMethods.h -o WordChecker
May be if you compile in C mode, you have to use C-style comments in header?
/**/ instead of //

chdir not declared, compilation error g++

I am trying to compile a relatively simple application that I obtained from the web..
When running make I get the following error:
In file included from main.cpp:2:0:
os.h: In function ‘void myOpenDir(const char*)’:
os.h:13:16: error: ‘chdir’ was not declared in this scope
The file os.h looks like this:
#ifndef OS_H
#define OS_H
#if defined(__GNUG__)
#define INT64 long long
#define UINT64 unsigned long long
#include <dirent.h>
#define SPRTR '/'
void myOpenDir(const char* dirpath)
{
chdir(dirpath);
}
#elif defined(_MSC_VER)
#define INT64 __int64
#define UINT64 unsigned __int64
#include <direct.h>
#define SPRTR '\\'
void myOpenDir(const char* dirpath)
{
_chdir(dirpath);
}
#else
#error "Platform not supported. Need to update source code"
#endif
#endif
Someone got an idea why it wont compile?
I also used a g++ compiler via g++-4.7.real -c main.cpp but so far no luck.
Add #include <unistd.h>, as per the chdir manual.

intercepting the openat() system call for GNU tar

I'm trying to intercept the openat() system call on Linux using a custom shared library that I can load via LD_PRELOAD. An example intercept-openat.c has this content:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <dlfcn.h>
int (*_original_openat)(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void) __attribute__((constructor));
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void)
{
_original_openat = (int (*)(int, const char *, int, mode_t))
dlsym(RTLD_NEXT, "openat");
}
int openat(int dirfd, const char *pathname, int flags, mode_t mode)
{
fprintf(stderr, "intercepting openat()...\n");
return _original_openat(dirfd, pathname, flags, mode);
}
I compile it via gcc -fPIC -Wall -shared -o intercept-openat.so intercept-openat.c -ldl. Then, when I run this small example program:
int main(int argc, char *argv[])
{
int fd;
fd = openat(AT_FDCWD, "/home/feh/.vimrc", O_RDONLY);
if(fd == -1)
return -1;
close(fd);
return 0;
}
The openat() call is re-written via the library:
$ LD_PRELOAD=./intercept-openat.so ./openat
intercepting openat()...
However, the same does not happen with GNU tar, even though it uses the same system call:
$ strace -e openat tar cf /tmp/t.tgz .vimrc
openat(AT_FDCWD, ".vimrc", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC) = 4
$ LD_PRELOAD=./intercept-openat.so tar cf /tmp/t.tgz .vimrc
So the custom openat() from intercept-openat.so is not being called. Why is that?
It uses the same system call, but apparently it does not call that via the same C function. Alternatively, it could be that it does, but it's statically linked.
Either way, I think you've proved that it never dynamically links a function names "openat". If you still want to pursue this option, you might like to see if it links against a specific version of that function, but that's a long shot.
You can still intercept the system call by writing your program to use ptrace. This is the same interface used by strace and gdb. It will have a higher performance penalty though.
http://linux.die.net/man/2/ptrace

Resources