Merge branch 'jk/gcc-function-attributes'
authorJunio C Hamano <gitster@pobox.com>
Mon, 22 Jul 2013 18:23:59 +0000 (11:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Jul 2013 18:23:59 +0000 (11:23 -0700)
Use the function attributes extension to catch mistakes in use of
our own variadic functions that use NULL sentinel at the end
(i.e. like execl(3)) and format strings (i.e. like printf(3)).

* jk/gcc-function-attributes:
  Add the LAST_ARG_MUST_BE_NULL macro
  wt-status: use "format" function attribute for status_printf
  use "sentinel" function attribute for variadic lists
  add missing "format" function attributes

1  2 
advice.h
git-compat-util.h
transport-helper.c

diff --combined advice.h
+++ b/advice.h
@@@ -17,10 -17,9 +17,11 @@@ extern int advice_resolve_conflict
  extern int advice_implicit_identity;
  extern int advice_detached_head;
  extern int advice_set_upstream_failure;
 +extern int advice_object_name_warning;
 +extern int advice_rm_hints;
  
  int git_default_advice_config(const char *var, const char *value);
+ __attribute__((format (printf, 1, 2)))
  void advise(const char *advice, ...);
  int error_resolve_conflict(const char *me);
  extern void NORETURN die_resolve_conflict(const char *me);
diff --combined git-compat-util.h
  #define _NETBSD_SOURCE 1
  #define _SGI_SOURCE 1
  
 -#ifdef WIN32 /* Both MinGW and MSVC */
 +#if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
  # if defined (_MSC_VER)
  #  define _WIN32_WINNT 0x0502
  # endif
  #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
  #include <winsock2.h>
  #include <windows.h>
 +#define GIT_WINDOWS_NATIVE
  #endif
  
  #include <unistd.h>
  #else
  #include <poll.h>
  #endif
 +
 +extern int get_st_mode_bits(const char *path, int *mode);
 +
  #if defined(__MINGW32__)
  /* pull in Windows compatibility stuff */
  #include "compat/mingw.h"
  typedef long intptr_t;
  typedef unsigned long uintptr_t;
  #endif
 -int get_st_mode_bits(const char *path, int *mode);
  #if defined(__CYGWIN__)
  #undef _XOPEN_SOURCE
  #include <grp.h>
  #define probe_utf8_pathname_composition(a,b)
  #endif
  
 +#ifdef NEEDS_CLIPPED_WRITE
 +ssize_t clipped_write(int fildes, const void *buf, size_t nbyte);
 +#define write(x,y,z) clipped_write((x),(y),(z))
 +#endif
 +
  #ifdef MKDIR_WO_TRAILING_SLASH
  #define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b))
  extern int compat_mkdir_wo_trailing_slash(const char*, mode_t);
@@@ -303,6 -295,13 +303,13 @@@ extern char *gitbasename(char *)
  #endif
  #endif
  
+ /* The sentinel attribute is valid from gcc version 4.0 */
+ #if defined(__GNUC__) && (__GNUC__ >= 4)
+ #define LAST_ARG_MUST_BE_NULL __attribute__((sentinel))
+ #else
+ #define LAST_ARG_MUST_BE_NULL
+ #endif
  #include "compat/bswap.h"
  
  #ifdef USE_WILDMATCH
@@@ -700,9 -699,8 +707,9 @@@ int remove_or_warn(unsigned int mode, c
   * Call access(2), but warn for any error except "missing file"
   * (ENOENT or ENOTDIR).
   */
 -int access_or_warn(const char *path, int mode);
 -int access_or_die(const char *path, int mode);
 +#define ACCESS_EACCES_OK (1U << 0)
 +int access_or_warn(const char *path, int mode, unsigned flag);
 +int access_or_die(const char *path, int mode, unsigned flag);
  
  /* Warn on an inaccessible file that ought to be accessible */
  void warn_on_inaccessible(const char *path);
diff --combined transport-helper.c
@@@ -11,7 -11,6 +11,7 @@@
  #include "thread-utils.h"
  #include "sigchain.h"
  #include "argv-array.h"
 +#include "refs.h"
  
  static int debug;
  
@@@ -48,7 -47,7 +48,7 @@@ static void sendline(struct helper_dat
                die_errno("Full write to remote helper failed");
  }
  
 -static int recvline_fh(FILE *helper, struct strbuf *buffer)
 +static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)
  {
        strbuf_reset(buffer);
        if (debug)
@@@ -66,7 -65,7 +66,7 @@@
  
  static int recvline(struct helper_data *helper, struct strbuf *buffer)
  {
 -      return recvline_fh(helper->out, buffer);
 +      return recvline_fh(helper->out, buffer, helper->name);
  }
  
  static void xchgline(struct helper_data *helper, struct strbuf *buffer)
@@@ -218,8 -217,6 +218,8 @@@ static struct child_process *get_helper
                for (i = 0; i < refspec_nr; i++)
                        free((char *)refspecs[i]);
                free(refspecs);
 +      } else if (data->import || data->bidi_import || data->export) {
 +              warning("This remote helper should implement refspec capability.");
        }
        strbuf_release(&buf);
        if (debug)
@@@ -476,7 -473,7 +476,7 @@@ static int fetch_with_import(struct tra
         * were fetching.
         *
         * (If no "refspec" capability was specified, for historical
 -       * reasons we default to *:*.)
 +       * reasons we default to the equivalent of *:*.)
         *
         * Store the result in to_fetch[i].old_sha1.  Callers such
         * as "git fetch" can use the value to write feedback to the
@@@ -543,7 -540,7 +543,7 @@@ static int process_connect_service(stru
                goto exit;
  
        sendline(data, &cmdbuf);
 -      recvline_fh(input, &cmdbuf);
 +      recvline_fh(input, &cmdbuf, name);
        if (!strcmp(cmdbuf.buf, "")) {
                data->no_disconnect_req = 1;
                if (debug)
@@@ -625,7 -622,7 +625,7 @@@ static int fetch(struct transport *tran
        return -1;
  }
  
 -static void push_update_ref_status(struct strbuf *buf,
 +static int push_update_ref_status(struct strbuf *buf,
                                   struct ref **ref,
                                   struct ref *remote_refs)
  {
                *ref = find_ref_by_name(remote_refs, refname);
        if (!*ref) {
                warning("helper reported unexpected status of %s", refname);
 -              return;
 +              return 1;
        }
  
        if ((*ref)->status != REF_STATUS_NONE) {
                 * status reported by the remote helper if the latter is 'no match'.
                 */
                if (status == REF_STATUS_NONE)
 -                      return;
 +                      return 1;
        }
  
        (*ref)->status = status;
        (*ref)->remote_status = msg;
 +      return !(status == REF_STATUS_OK);
  }
  
  static void push_update_refs_status(struct helper_data *data,
        struct strbuf buf = STRBUF_INIT;
        struct ref *ref = remote_refs;
        for (;;) {
 +              char *private;
 +
                recvline(data, &buf);
                if (!buf.len)
                        break;
  
 -              push_update_ref_status(&buf, &ref, remote_refs);
 +              if (push_update_ref_status(&buf, &ref, remote_refs))
 +                      continue;
 +
 +              if (!data->refspecs)
 +                      continue;
 +
 +              /* propagate back the update to the remote namespace */
 +              private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
 +              if (!private)
 +                      continue;
 +              update_ref("update by helper", private, ref->new_sha1, NULL, 0, 0);
 +              free(private);
        }
        strbuf_release(&buf);
  }
@@@ -806,14 -789,6 +806,14 @@@ static int push_refs_with_export(struc
        struct string_list revlist_args = STRING_LIST_INIT_NODUP;
        struct strbuf buf = STRBUF_INIT;
  
 +      if (!data->refspecs)
 +              die("remote-helper doesn't support push; refspec needed");
 +
 +      if (flags & TRANSPORT_PUSH_DRY_RUN) {
 +              if (set_helper_option(transport, "dry-run", "true") != 0)
 +                      die("helper %s does not support dry-run", data->name);
 +      }
 +
        helper = get_helper(transport);
  
        write_constant(helper->in, "export\n");
                char *private;
                unsigned char sha1[20];
  
 -              if (!data->refspecs)
 -                      continue;
 +              if (ref->deletion)
 +                      die("remote-helpers do not support ref deletion");
 +
                private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
                if (private && !get_sha1(private, sha1)) {
                        strbuf_addf(&buf, "^%s", private);
                }
                free(private);
  
 -              if (ref->deletion) {
 +              if (ref->deletion)
                        die("remote-helpers do not support ref deletion");
 -              }
  
 -              if (ref->peer_ref)
 +              if (ref->peer_ref) {
 +                      if (strcmp(ref->peer_ref->name, ref->name))
 +                              die("remote-helpers do not support old:new syntax");
                        string_list_append(&revlist_args, ref->peer_ref->name);
 -
 +              }
        }
  
        if (get_exporter(transport, &exporter, &revlist_args))
@@@ -982,6 -955,7 +982,7 @@@ int transport_helper_init(struct transp
  #define PBUFFERSIZE 8192
  
  /* Print bidirectional transfer loop debug message. */
+ __attribute__((format (printf, 1, 2)))
  static void transfer_debug(const char *fmt, ...)
  {
        va_list args;
@@@ -1067,7 -1041,7 +1068,7 @@@ static int udt_do_read(struct unidirect
                return -1;
        } else if (bytes == 0) {
                transfer_debug("%s EOF (with %i bytes in buffer)",
-                       t->src_name, t->bufuse);
+                       t->src_name, (int)t->bufuse);
                t->state = SSTATE_FLUSHING;
        } else if (bytes > 0) {
                t->bufuse += bytes;