Use C99 variadic macros when not on GCC.

1) We already require C99.

2) This allows us to support MSVC again (thanks to Gisle Vanem for
   this part)

3) This change allows us to dump some rotten old compatibility code
   from log.c
This commit is contained in:
Nick Mathewson 2015-07-15 14:43:35 -04:00
parent 7bd5212ddc
commit 8cb5070376
4 changed files with 42 additions and 120 deletions

4
changes/variadic_macros Normal file
View file

@ -0,0 +1,4 @@
o Minor features (portability):
- Use C99 variadic macros when the compiler is not GCC. This avoids
failing compilations on MSVC, and fixes a log-file-based race
condition in our old workarounds. Original patch from Gisle Vanem.

View file

@ -674,9 +674,7 @@ tor_log_get_logfile_names(smartlist_t *out)
UNLOCK_LOGS(); UNLOCK_LOGS();
} }
/** Output a message to the log, prefixed with a function name <b>fn</b>. */ /** Implementation of the log_fn backend, used when we have
#ifdef __GNUC__
/** GCC-based implementation of the log_fn backend, used when we have
* variadic macros. All arguments are as for log_fn, except for * variadic macros. All arguments are as for log_fn, except for
* <b>fn</b>, which is the name of the calling functions. */ * <b>fn</b>, which is the name of the calling functions. */
void void
@ -706,98 +704,6 @@ log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
va_end(ap); va_end(ap);
tor_free(m); tor_free(m);
} }
#else
/** @{ */
/** Variant implementation of log_fn, log_debug, log_info,... for C compilers
* without variadic macros. In this case, the calling function sets
* log_fn_function_name_ to the name of the function, then invokes the
* appropriate log_fn_, log_debug_, etc. */
const char *log_fn_function_name_=NULL;
void
log_fn_(int severity, log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
if (severity > log_global_min_severity_)
return;
va_start(ap,format);
logv(severity, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
log_fn_function_name_ = NULL;
}
void
log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain,
const char *format, ...)
{
va_list ap;
char *m;
if (severity > log_global_min_severity_)
return;
m = rate_limit_log(ratelim, approx_time());
if (m == NULL)
return;
va_start(ap, format);
logv(severity, domain, log_fn_function_name_, m, format, ap);
va_end(ap);
tor_free(m);
}
void
log_debug_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
/* For GCC we do this check in the macro. */
if (PREDICT_LIKELY(LOG_DEBUG > log_global_min_severity_))
return;
va_start(ap,format);
logv(LOG_DEBUG, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
log_fn_function_name_ = NULL;
}
void
log_info_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
if (LOG_INFO > log_global_min_severity_)
return;
va_start(ap,format);
logv(LOG_INFO, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
log_fn_function_name_ = NULL;
}
void
log_notice_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
if (LOG_NOTICE > log_global_min_severity_)
return;
va_start(ap,format);
logv(LOG_NOTICE, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
log_fn_function_name_ = NULL;
}
void
log_warn_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
if (LOG_WARN > log_global_min_severity_)
return;
va_start(ap,format);
logv(LOG_WARN, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
log_fn_function_name_ = NULL;
}
void
log_err_(log_domain_mask_t domain, const char *format, ...)
{
va_list ap;
if (LOG_ERR > log_global_min_severity_)
return;
va_start(ap,format);
logv(LOG_ERR, domain, log_fn_function_name_, NULL, format, ap);
va_end(ap);
log_fn_function_name_ = NULL;
}
/** @} */
#endif
/** Free all storage held by <b>victim</b>. */ /** Free all storage held by <b>victim</b>. */
static void static void

View file

@ -166,7 +166,6 @@ void tor_log_get_logfile_names(struct smartlist_t *out);
extern int log_global_min_severity_; extern int log_global_min_severity_;
#if defined(__GNUC__) || defined(RUNNING_DOXYGEN)
void log_fn_(int severity, log_domain_mask_t domain, void log_fn_(int severity, log_domain_mask_t domain,
const char *funcname, const char *format, ...) const char *funcname, const char *format, ...)
CHECK_PRINTF(4,5); CHECK_PRINTF(4,5);
@ -175,6 +174,12 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
log_domain_mask_t domain, const char *funcname, log_domain_mask_t domain, const char *funcname,
const char *format, ...) const char *format, ...)
CHECK_PRINTF(5,6); CHECK_PRINTF(5,6);
#if defined(__GNUC__)
/* These are the GCC varidaic macros, so that older versions of GCC don't
* break. */
/** Log a message at level <b>severity</b>, using a pretty-printed version /** Log a message at level <b>severity</b>, using a pretty-printed version
* of the current function name. */ * of the current function name. */
#define log_fn(severity, domain, args...) \ #define log_fn(severity, domain, args...) \
@ -200,31 +205,32 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
#else /* ! defined(__GNUC__) */ #else /* ! defined(__GNUC__) */
void log_fn_(int severity, log_domain_mask_t domain, const char *format, ...); /* Here are the c99 variadic macros, to work with non-GCC compilers */
struct ratelim_t;
void log_fn_ratelim_(struct ratelim_t *ratelim, int severity,
log_domain_mask_t domain, const char *format, ...);
void log_debug_(log_domain_mask_t domain, const char *format, ...);
void log_info_(log_domain_mask_t domain, const char *format, ...);
void log_notice_(log_domain_mask_t domain, const char *format, ...);
void log_warn_(log_domain_mask_t domain, const char *format, ...);
void log_err_(log_domain_mask_t domain, const char *format, ...);
/* We don't have GCC's varargs macros, so use a global variable to pass the #define log_debug(domain, args, ...) \
* function name to log_fn */ STMT_BEGIN \
extern const char *log_fn_function_name_; if (PREDICT_UNLIKELY(log_global_min_severity_ == LOG_DEBUG)) \
/* We abuse the comma operator here, since we can't use the standard log_fn_(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args, ##__VA_ARGS__); \
* do {...} while (0) trick to wrap this macro, since the macro can't take STMT_END
* arguments. */ #define log_info(domain, args,...) \
#define log_fn (log_fn_function_name_=__func__),log_fn_ log_fn_(LOG_INFO, domain, __PRETTY_FUNCTION__, args, ##__VA_ARGS__)
#define log_fn_ratelim (log_fn_function_name_=__func__),log_fn_ratelim_ #define log_notice(domain, args,...) \
#define log_debug (log_fn_function_name_=__func__),log_debug_ log_fn_(LOG_NOTICE, domain, __PRETTY_FUNCTION__, args, ##__VA_ARGS__)
#define log_info (log_fn_function_name_=__func__),log_info_ #define log_warn(domain, args,...) \
#define log_notice (log_fn_function_name_=__func__),log_notice_ log_fn_(LOG_WARN, domain, __PRETTY_FUNCTION__, args, ##__VA_ARGS__)
#define log_warn (log_fn_function_name_=__func__),log_warn_ #define log_err(domain, args,...) \
#define log_err (log_fn_function_name_=__func__),log_err_ log_fn_(LOG_ERR, domain, __PRETTY_FUNCTION__, args, ##__VA_ARGS__)
/** Log a message at level <b>severity</b>, using a pretty-printed version
#endif /* !GNUC */ * of the current function name. */
#define log_fn(severity, domain, args,...) \
log_fn_(severity, domain, __PRETTY_FUNCTION__, args, ##__VA_ARGS__)
/** As log_fn, but use <b>ratelim</b> (an instance of ratelim_t) to control
* the frequency at which messages can appear.
*/
#define log_fn_ratelim(ratelim, severity, domain, args,...) \
log_fn_ratelim_(ratelim, severity, domain, __PRETTY_FUNCTION__, \
args, ##__VA_ARGS__)
#endif
#ifdef LOG_PRIVATE #ifdef LOG_PRIVATE
MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain, MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain,

View file

@ -2583,8 +2583,14 @@ options_validate_cb(void *old_options, void *options, void *default_options,
#define REJECT(arg) \ #define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
#ifdef __GNUC__
#define COMPLAIN(args...) \ #define COMPLAIN(args...) \
STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END
#else
#define COMPLAIN(args, ...) \
STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END
#endif
/** Log a warning message iff <b>filepath</b> is not absolute. /** Log a warning message iff <b>filepath</b> is not absolute.
* Warning message must contain option name <b>option</b> and * Warning message must contain option name <b>option</b> and