From f374bbf018dfadb26a07afe5d0334a7ef831feed Mon Sep 17 00:00:00 2001 From: kalibera Date: Fri, 24 Nov 2023 10:06:19 +0000 Subject: [PATCH] Annotate functions accepting formatted strings so that GCC and clang can check whether arguments match the format. git-svn-id: https://svn.r-project.org/R/trunk@85619 00db46b3-68df-0310-9c12-caf00c1e9a41 --- src/include/Defn.h | 43 +++++++++++++++++++++++++++++++------ src/include/R_ext/Error.h | 14 ++++++++++-- src/include/R_ext/Print.h | 31 +++++++++++++++++++++----- src/include/Rconnections.h | 8 +++++-- src/include/Rinternals.h | 20 ++++++++++++++--- src/library/tools/R/check.R | 8 +++++++ 6 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/include/Defn.h b/src/include/Defn.h index 55b6370b3be..45da8fb283b 100644 --- a/src/include/Defn.h +++ b/src/include/Defn.h @@ -2129,7 +2129,12 @@ NORET void R_jumpctxt(RCNTXT *, int, SEXP); SEXP ItemName(SEXP, R_xlen_t); /* ../main/errors.c : */ -NORET void errorcall_cpy(SEXP, const char *, ...); +NORET void errorcall_cpy(SEXP, const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; + NORET void ErrorMessage(SEXP, int, ...); void WarningMessage(SEXP, R_WARNING, ...); SEXP R_GetTraceback(int); // including deparse()ing @@ -2138,10 +2143,20 @@ NORET void R_signalErrorCondition(SEXP cond, SEXP call); NORET void R_signalErrorConditionEx(SEXP cond, SEXP call, int exitOnly); SEXP R_vmakeErrorCondition(SEXP call, const char *classname, const char *subclassname, - int nextra, const char *format, va_list ap); + int nextra, const char *format, va_list ap) +#ifdef __GNUC__ +__attribute__ ((format (printf, 5, 0))) +#endif +; + SEXP R_makeErrorCondition(SEXP call, const char *classname, const char *subclassname, - int nextra, const char *format, ...); + int nextra, const char *format, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 5, 6))) +#endif +; + void R_setConditionField(SEXP cond, R_xlen_t idx, const char *name, SEXP val); SEXP R_makeNotSubsettableError(SEXP x, SEXP call); SEXP R_makeMissingSubscriptError(SEXP x, SEXP call); @@ -2236,9 +2251,23 @@ char *mbcsTruncateToValid(char *s); Rboolean utf8Valid(const char *str); char *Rf_strchr(const char *s, int c); char *Rf_strrchr(const char *s, int c); -int Rvsnprintf_mbcs(char *buf, size_t size, const char *format, va_list ap); -int Rsnprintf_mbcs(char *str, size_t size, const char *format, ...); -int Rasprintf_malloc(char **str, const char *fmt, ...); +int Rvsnprintf_mbcs(char *buf, size_t size, const char *format, va_list ap) +#ifdef __GNUC__ +__attribute__ ((format (printf, 3, 0))) +#endif +; + +int Rsnprintf_mbcs(char *str, size_t size, const char *format, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 3, 4))) +#endif +; + +int Rasprintf_malloc(char **str, const char *fmt, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; SEXP fixup_NaRm(SEXP args); /* summary.c */ void invalidate_cached_recodings(void); /* from sysutils.c */ @@ -2297,7 +2326,7 @@ extern const char *locale2charset(const char *); # endif # define gettext_noop(String) String # define N_(String) gettext_noop (String) -# else /* not NLS */ +# else /* not NLS */ # define _(String) (String) # define N_(String) String # define ngettext(String, StringP, N) (N > 1 ? StringP: String) diff --git a/src/include/R_ext/Error.h b/src/include/R_ext/Error.h index 77a863131a4..f34a62ddf5d 100644 --- a/src/include/R_ext/Error.h +++ b/src/include/R_ext/Error.h @@ -48,11 +48,21 @@ extern "C" { # define NORET #endif -NORET void Rf_error(const char *, ...); +NORET void Rf_error(const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +; + NORET void UNIMPLEMENTED(const char *); NORET void WrongArgCount(const char *); -void Rf_warning(const char *, ...); +void Rf_warning(const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +; + void R_ShowMessage(const char *s); diff --git a/src/include/R_ext/Print.h b/src/include/R_ext/Print.h index 2e4cdd31ce7..8037f2e1992 100644 --- a/src/include/R_ext/Print.h +++ b/src/include/R_ext/Print.h @@ -1,6 +1,6 @@ /* * R : A Computer Language for Statistical Data Analysis - * Copyright (C) 1998-2019 The R Core Team + * Copyright (C) 1998-2023 The R Core Team * * This header file is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -42,11 +42,32 @@ extern "C" { # define R_VA_LIST va_list #endif -void Rprintf(const char *, ...); -void REprintf(const char *, ...); +void Rprintf(const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +; + +void REprintf(const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +; + #if !defined(__cplusplus) || defined R_USE_C99_IN_CXX -void Rvprintf(const char *, R_VA_LIST); -void REvprintf(const char *, R_VA_LIST); + +void Rvprintf(const char *, R_VA_LIST) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 0))) +#endif +; + +void REvprintf(const char *, R_VA_LIST) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 0))) +#endif +; + #endif #ifdef __cplusplus diff --git a/src/include/Rconnections.h b/src/include/Rconnections.h index 10175bd8fea..6f75e1b9bbe 100644 --- a/src/include/Rconnections.h +++ b/src/include/Rconnections.h @@ -1,6 +1,6 @@ /* * R : A Computer Language for Statistical Data Analysis - * Copyright (C) 2000-2020 The R Core Team. + * Copyright (C) 2000-2023 The R Core Team. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,7 +72,11 @@ typedef struct clpconn { int Rconn_fgetc(Rconnection con); int Rconn_ungetc(int c, Rconnection con); size_t Rconn_getline(Rconnection con, char *buf, size_t bufsize); -int Rconn_printf(Rconnection con, const char *format, ...); +int Rconn_printf(Rconnection con, const char *format, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; Rconnection getConnection(int n); Rconnection getConnection_no_err(int n); Rboolean switch_stdout(int icon, int closeOnExit); diff --git a/src/include/Rinternals.h b/src/include/Rinternals.h index 48c59694856..36770b07366 100644 --- a/src/include/Rinternals.h +++ b/src/include/Rinternals.h @@ -683,9 +683,23 @@ Rboolean R_HasFancyBindings(SEXP rho); /* ../main/errors.c : */ /* needed for R_load/savehistory handling in front ends */ -NORET void Rf_errorcall(SEXP, const char *, ...); -void Rf_warningcall(SEXP, const char *, ...); -void Rf_warningcall_immediate(SEXP, const char *, ...); +NORET void Rf_errorcall(SEXP, const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; + +void Rf_warningcall(SEXP, const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; + +void Rf_warningcall_immediate(SEXP, const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; /* Save/Load Interface */ #define R_XDR_DOUBLE_SIZE 8 diff --git a/src/library/tools/R/check.R b/src/library/tools/R/check.R index 737a10a99f5..807b8f80484 100644 --- a/src/library/tools/R/check.R +++ b/src/library/tools/R/check.R @@ -5730,6 +5730,14 @@ add_dummies <- function(dir, Log) ex_re <- "(RcppEigen/include/Eigen)/.*\\[-Wtautological-compare\\]" lines <- filtergrep(ex_re, lines, useBytes = TRUE) + ## 2023-11: filter out format warnings (to be fixed upstream) + ex_re <- "(Rcpp/include/Rcpp)/.*\\[-Wformat" + lines <- filtergrep(ex_re, lines, useBytes = TRUE) + + ## 2023-11: filter out format warnings (to be fixed upstream) + ex_re <- "(rstan/io)/.*\\[-Wformat" + lines <- filtergrep(ex_re, lines, useBytes = TRUE) + ## Filter out StanHeader warnings ex_re <- "StanHeaders/.*\\[-Wunneeded-internal-declaration\\]" lines <- filtergrep(ex_re, lines, useBytes = TRUE)