tools_common.h: add AOM_TOOLS_FORMAT_PRINTF

and use it to set the format attribute for printf like functions. this
allows the examples to be built with -Wformat-nonliteral without
producing warnings.

this is the same change that was applied in libvpx:
dd10ac8f6 tools_common.h: add VPX_TOOLS_FORMAT_PRINTF

Bug: webm:1744
Change-Id: I26b4c41c9a42790053b1ae0e4a678af8f2cd1d82
diff --git a/apps/aomenc.c b/apps/aomenc.c
index ad938d6..65a2684 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -64,8 +64,8 @@
 
 static const char *exec_name;
 
-static void warn_or_exit_on_errorv(aom_codec_ctx_t *ctx, int fatal,
-                                   const char *s, va_list ap) {
+static AOM_TOOLS_FORMAT_PRINTF(3, 0) void warn_or_exit_on_errorv(
+    aom_codec_ctx_t *ctx, int fatal, const char *s, va_list ap) {
   if (ctx->err) {
     const char *detail = aom_codec_error_detail(ctx);
 
@@ -78,7 +78,9 @@
   }
 }
 
-static void ctx_exit_on_error(aom_codec_ctx_t *ctx, const char *s, ...) {
+static AOM_TOOLS_FORMAT_PRINTF(2,
+                               3) void ctx_exit_on_error(aom_codec_ctx_t *ctx,
+                                                         const char *s, ...) {
   va_list ap;
 
   va_start(ap, s);
@@ -86,8 +88,8 @@
   va_end(ap);
 }
 
-static void warn_or_exit_on_error(aom_codec_ctx_t *ctx, int fatal,
-                                  const char *s, ...) {
+static AOM_TOOLS_FORMAT_PRINTF(3, 4) void warn_or_exit_on_error(
+    aom_codec_ctx_t *ctx, int fatal, const char *s, ...) {
   va_list ap;
 
   va_start(ap, s);
diff --git a/build/cmake/aom_configure.cmake b/build/cmake/aom_configure.cmake
index 43d60ae..d79cb90 100644
--- a/build/cmake/aom_configure.cmake
+++ b/build/cmake/aom_configure.cmake
@@ -275,6 +275,7 @@
   add_compiler_flag_if_supported("-Wdisabled-optimization")
   add_compiler_flag_if_supported("-Wextra")
   add_compiler_flag_if_supported("-Wfloat-conversion")
+  add_compiler_flag_if_supported("-Wformat=2")
   add_c_flag_if_supported("-Wimplicit-function-declaration")
   add_compiler_flag_if_supported("-Wlogical-op")
   add_compiler_flag_if_supported("-Wpointer-arith")
diff --git a/common/args.c b/common/args.c
index ed62294..e5b20e7 100644
--- a/common/args.c
+++ b/common/args.c
@@ -133,7 +133,7 @@
   char err_msg[ARG_ERR_MSG_MAX_LEN];
   int ret = arg_match_helper(arg_, def, argv, err_msg);
   if (err_msg[0] != '\0') {
-    die(err_msg);
+    die("%s", err_msg);
   }
   return ret;
 }
@@ -194,7 +194,7 @@
   char err_msg[ARG_ERR_MSG_MAX_LEN];
   unsigned int ret = arg_parse_uint_helper(arg, err_msg);
   if (err_msg[0] != '\0') {
-    die(err_msg);
+    die("%s", err_msg);
   }
   return ret;
 }
@@ -203,7 +203,7 @@
   char err_msg[ARG_ERR_MSG_MAX_LEN];
   int ret = arg_parse_int_helper(arg, err_msg);
   if (err_msg[0] != '\0') {
-    die(err_msg);
+    die("%s", err_msg);
   }
   return ret;
 }
@@ -212,7 +212,7 @@
   char err_msg[ARG_ERR_MSG_MAX_LEN];
   struct aom_rational ret = arg_parse_rational_helper(arg, err_msg);
   if (err_msg[0] != '\0') {
-    die(err_msg);
+    die("%s", err_msg);
   }
   return ret;
 }
@@ -221,7 +221,7 @@
   char err_msg[ARG_ERR_MSG_MAX_LEN];
   int ret = arg_parse_enum_helper(arg, err_msg);
   if (err_msg[0] != '\0') {
-    die(err_msg);
+    die("%s", err_msg);
   }
   return ret;
 }
@@ -230,7 +230,7 @@
   char err_msg[ARG_ERR_MSG_MAX_LEN];
   int ret = arg_parse_enum_or_int_helper(arg, err_msg);
   if (err_msg[0] != '\0') {
-    die(err_msg);
+    die("%s", err_msg);
   }
   return ret;
 }
@@ -241,7 +241,7 @@
   char err_msg[ARG_ERR_MSG_MAX_LEN];
   int ret = arg_parse_list_helper(arg, list, n, err_msg);
   if (err_msg[0] != '\0') {
-    die(err_msg);
+    die("%s", err_msg);
   }
   return ret;
 }
diff --git a/common/tools_common.h b/common/tools_common.h
index f5b5b19..79348c2 100644
--- a/common/tools_common.h
+++ b/common/tools_common.h
@@ -131,12 +131,24 @@
 #define AOM_NO_RETURN
 #endif
 
+// Tells the compiler to perform `printf` format string checking if the
+// compiler supports it; see the 'format' attribute in
+// <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html>.
+#define AOM_TOOLS_FORMAT_PRINTF(string_index, first_to_check)
+#if defined(__has_attribute)
+#if __has_attribute(format)
+#undef AOM_TOOLS_FORMAT_PRINTF
+#define AOM_TOOLS_FORMAT_PRINTF(string_index, first_to_check) \
+  __attribute__((__format__(__printf__, string_index, first_to_check)))
+#endif
+#endif
+
 /* Sets a stdio stream into binary mode */
 FILE *set_binary_mode(FILE *stream);
 
-AOM_NO_RETURN void die(const char *fmt, ...);
-AOM_NO_RETURN void fatal(const char *fmt, ...);
-void aom_tools_warn(const char *fmt, ...);
+AOM_NO_RETURN void die(const char *fmt, ...) AOM_TOOLS_FORMAT_PRINTF(1, 2);
+AOM_NO_RETURN void fatal(const char *fmt, ...) AOM_TOOLS_FORMAT_PRINTF(1, 2);
+void aom_tools_warn(const char *fmt, ...) AOM_TOOLS_FORMAT_PRINTF(1, 2);
 
 AOM_NO_RETURN void die_codec(aom_codec_ctx_t *ctx, const char *s);
 
diff --git a/common/warnings.c b/common/warnings.c
index 308cecd..a20531c 100644
--- a/common/warnings.c
+++ b/common/warnings.c
@@ -86,7 +86,7 @@
   /* Count and print warnings. */
   for (warning = warning_list.warning_node; warning != NULL;
        warning = warning->next_warning, ++num_warnings) {
-    aom_tools_warn(warning->warning_string);
+    aom_tools_warn("%s", warning->warning_string);
   }
 
   free_warning_list(&warning_list);
diff --git a/examples/noise_model.c b/examples/noise_model.c
index 2a40c12..27db41b 100644
--- a/examples/noise_model.c
+++ b/examples/noise_model.c
@@ -316,7 +316,7 @@
   }
   infile = fopen(args.input, "rb");
   if (!infile) {
-    die("Failed to open input file:", args.input);
+    die("Failed to open input file: %s", args.input);
   }
   fprintf(stderr, "Bit depth: %d  stride:%d\n", args.bit_depth, raw.stride[0]);
 
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index eb8dda4..fdf8c52 100644
--- a/examples/svc_encoder_rtc.c
+++ b/examples/svc_encoder_rtc.c
@@ -1160,7 +1160,7 @@
   // Y4M reader has its own allocation.
   if (app_input.input_ctx.file_type != FILE_TYPE_Y4M) {
     if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, width, height, 32)) {
-      die("Failed to allocate image", width, height);
+      die("Failed to allocate image (%dx%d)", width, height);
     }
   }
 
diff --git a/examples/twopass_encoder.c b/examples/twopass_encoder.c
index 075eeae..b62e7a7 100644
--- a/examples/twopass_encoder.c
+++ b/examples/twopass_encoder.c
@@ -218,7 +218,7 @@
     die("Invalid frame size: %dx%d", w, h);
 
   if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, w, h, 1))
-    die("Failed to allocate image", w, h);
+    die("Failed to allocate image (%dx%d)", w, h);
 
   printf("Using %s\n", aom_codec_iface_name(encoder));
 
diff --git a/stats/aomstats.c b/stats/aomstats.c
index 8d59377..a006ec0 100644
--- a/stats/aomstats.c
+++ b/stats/aomstats.c
@@ -44,7 +44,7 @@
     stats->buf.buf = malloc(stats->buf_alloc_sz);
 
     if (!stats->buf.buf)
-      fatal("Failed to allocate first-pass stats buffer (%lu bytes)",
+      fatal("Failed to allocate first-pass stats buffer (%u bytes)",
             (unsigned int)stats->buf_alloc_sz);
 
     nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file);
diff --git a/stats/rate_hist.c b/stats/rate_hist.c
index 71eb78b..d820d51 100644
--- a/stats/rate_hist.c
+++ b/stats/rate_hist.c
@@ -179,38 +179,38 @@
 
 static void show_histogram(const struct hist_bucket *bucket, int buckets,
                            int total, int scale) {
-  const char *pat1, *pat2;
+  int width1, width2;
   int i;
 
   switch ((int)(log(bucket[buckets - 1].high) / log(10)) + 1) {
     case 1:
     case 2:
-      pat1 = "%4d %2s: ";
-      pat2 = "%4d-%2d: ";
+      width1 = 4;
+      width2 = 2;
       break;
     case 3:
-      pat1 = "%5d %3s: ";
-      pat2 = "%5d-%3d: ";
+      width1 = 5;
+      width2 = 3;
       break;
     case 4:
-      pat1 = "%6d %4s: ";
-      pat2 = "%6d-%4d: ";
+      width1 = 6;
+      width2 = 4;
       break;
     case 5:
-      pat1 = "%7d %5s: ";
-      pat2 = "%7d-%5d: ";
+      width1 = 7;
+      width2 = 5;
       break;
     case 6:
-      pat1 = "%8d %6s: ";
-      pat2 = "%8d-%6d: ";
+      width1 = 8;
+      width2 = 6;
       break;
     case 7:
-      pat1 = "%9d %7s: ";
-      pat2 = "%9d-%7d: ";
+      width1 = 9;
+      width2 = 7;
       break;
     default:
-      pat1 = "%12d %10s: ";
-      pat2 = "%12d-%10d: ";
+      width1 = 12;
+      width2 = 10;
       break;
   }
 
@@ -225,9 +225,10 @@
     assert(len <= HIST_BAR_MAX);
 
     if (bucket[i].low == bucket[i].high)
-      fprintf(stderr, pat1, bucket[i].low, "");
+      fprintf(stderr, "%*d %*s: ", width1, bucket[i].low, width2, "");
     else
-      fprintf(stderr, pat2, bucket[i].low, bucket[i].high);
+      fprintf(stderr, "%*d-%*d: ", width1, bucket[i].low, width2,
+              bucket[i].high);
 
     for (j = 0; j < HIST_BAR_MAX; j++) fprintf(stderr, j < len ? "=" : " ");
     fprintf(stderr, "\t%5d (%6.2f%%)\n", bucket[i].count, pct);