Merge branch 'jk/leak-checkers'
authorJunio C Hamano <gitster@pobox.com>
Tue, 19 Sep 2017 01:47:55 +0000 (10:47 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 19 Sep 2017 01:47:55 +0000 (10:47 +0900)
Many of our programs consider that it is OK to release dynamic
storage that is used throughout the life of the program by simply
exiting, but this makes it harder to leak detection tools to avoid
reporting false positives. Plug many existing leaks and introduce
a mechanism for developers to mark that the region of memory
pointed by a pointer is not lost/leaking to help these tools.

* jk/leak-checkers:
add UNLEAK annotation for reducing leak false positives
set_git_dir: handle feeding gitdir to itself
repository: free fields before overwriting them
reset: free allocated tree buffers
reset: make tree counting less confusing
config: plug user_config leak
update-index: fix cache entry leak in add_one_file()
add: free leaked pathspec after add_files_to_cache()
test-lib: set LSAN_OPTIONS to abort by default
test-lib: --valgrind should not override --verbose-log

1  2 
Makefile
builtin/reset.c
builtin/update-index.c
diff --combined Makefile
index 68948dfbf3f29531d41be591daa9a8ba8df72708,c052f09bbae7936b9c9378f9e314e6916a257998..ed5960e6b378a982fb770f428324ba8fec0ba8c6
+++ b/Makefile
@@@ -162,11 -162,6 +162,11 @@@ all:
  # algorithm. This is slower, but may detect attempted collision attacks.
  # Takes priority over other *_SHA1 knobs.
  #
 +# Define DC_SHA1_EXTERNAL in addition to DC_SHA1 if you want to build / link
 +# git with the external SHA1 collision-detect library.
 +# Without this option, i.e. the default behavior is to build git with its
 +# own built-in code (or submodule).
 +#
  # Define DC_SHA1_SUBMODULE in addition to DC_SHA1 to use the
  # sha1collisiondetection shipped as a submodule instead of the
  # non-submodule copy in sha1dc/. This is an experimental option used
@@@ -1041,6 -1036,9 +1041,9 @@@ BASIC_CFLAGS += -fno-omit-frame-pointe
  ifneq ($(filter undefined,$(SANITIZERS)),)
  BASIC_CFLAGS += -DNO_UNALIGNED_LOADS
  endif
+ ifneq ($(filter leak,$(SANITIZERS)),)
+ BASIC_CFLAGS += -DSUPPRESS_ANNOTATED_LEAKS
+ endif
  endif
  
  ifndef sysconfdir
@@@ -1480,15 -1478,6 +1483,15 @@@ ifdef APPLE_COMMON_CRYPT
        BASIC_CFLAGS += -DSHA1_APPLE
  else
        DC_SHA1 := YesPlease
 +      BASIC_CFLAGS += -DSHA1_DC
 +      LIB_OBJS += sha1dc_git.o
 +ifdef DC_SHA1_EXTERNAL
 +      ifdef DC_SHA1_SUBMODULE
 +$(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both)
 +      endif
 +      BASIC_CFLAGS += -DDC_SHA1_EXTERNAL
 +      EXTLIBS += -lsha1detectcoll
 +else
  ifdef DC_SHA1_SUBMODULE
        LIB_OBJS += sha1collisiondetection/lib/sha1.o
        LIB_OBJS += sha1collisiondetection/lib/ubc_check.o
        LIB_OBJS += sha1dc/ubc_check.o
  endif
        BASIC_CFLAGS += \
 -              -DSHA1_DC \
                -DSHA1DC_NO_STANDARD_INCLUDES \
                -DSHA1DC_INIT_SAFE_HASH_DEFAULT=0 \
                -DSHA1DC_CUSTOM_INCLUDE_SHA1_C="\"cache.h\"" \
 -              -DSHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C="\"sha1dc_git.c\"" \
 -              -DSHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H="\"sha1dc_git.h\"" \
                -DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="\"git-compat-util.h\""
  endif
  endif
  endif
  endif
 +endif
  
  ifdef SHA1_MAX_BLOCK_SIZE
        LIB_OBJS += compat/sha1-chunked.o
diff --combined builtin/reset.c
index f1af9345e4c72fc6af411037ede717399ea3a4e1,0295c961a308189a5c50ac637b5f8f432d69077a..9cd89b23059f768c4651725f2c26c5b08c35f650
@@@ -44,10 -44,11 +44,11 @@@ static inline int is_merge(void
  
  static int reset_index(const struct object_id *oid, int reset_type, int quiet)
  {
-       int nr = 1;
+       int i, nr = 0;
        struct tree_desc desc[2];
        struct tree *tree;
        struct unpack_trees_options opts;
+       int ret = -1;
  
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = 1;
                struct object_id head_oid;
                if (get_oid("HEAD", &head_oid))
                        return error(_("You do not have a valid HEAD."));
-               if (!fill_tree_descriptor(desc, &head_oid))
+               if (!fill_tree_descriptor(desc + nr, &head_oid))
                        return error(_("Failed to find tree of HEAD."));
                nr++;
                opts.fn = twoway_merge;
        }
  
-       if (!fill_tree_descriptor(desc + nr - 1, oid))
-               return error(_("Failed to find tree of %s."), oid_to_hex(oid));
+       if (!fill_tree_descriptor(desc + nr, oid)) {
+               error(_("Failed to find tree of %s."), oid_to_hex(oid));
+               goto out;
+       }
+       nr++;
        if (unpack_trees(nr, desc, &opts))
-               return -1;
+               goto out;
  
        if (reset_type == MIXED || reset_type == HARD) {
                tree = parse_tree_indirect(oid);
                prime_cache_tree(&the_index, tree);
        }
  
-       return 0;
+       ret = 0;
+ out:
+       for (i = 0; i < nr; i++)
+               free((void *)desc[i].buffer);
+       return ret;
  }
  
  static void print_new_head_line(struct commit *commit)
@@@ -367,8 -377,8 +377,8 @@@ int cmd_reset(int argc, const char **ar
                die_if_unmerged_cache(reset_type);
  
        if (reset_type != SOFT) {
 -              struct lock_file *lock = xcalloc(1, sizeof(*lock));
 -              hold_locked_index(lock, LOCK_DIE_ON_ERROR);
 +              struct lock_file lock = LOCK_INIT;
 +              hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
                if (reset_type == MIXED) {
                        int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
                        if (read_from_tree(&pathspec, &oid, intent_to_add))
                                die(_("Could not reset index file to revision '%s'."), rev);
                }
  
 -              if (write_locked_index(&the_index, lock, COMMIT_LOCK))
 +              if (write_locked_index(&the_index, &lock, COMMIT_LOCK))
                        die(_("Could not write new index file."));
        }
  
diff --combined builtin/update-index.c
index 655e6d60d3f7e0525d5b88c66803e7b993168443,d955cd56b323387e2eb663225062d8f5bb439ee2..bf7420b808fd1e0314d981bf65073df62f7578a4
@@@ -287,8 -287,10 +287,10 @@@ static int add_one_path(const struct ca
        }
        option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
        option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
-       if (add_cache_entry(ce, option))
+       if (add_cache_entry(ce, option)) {
+               free(ce);
                return error("%s: cannot add to the index - missing --add option?", path);
+       }
        return 0;
  }
  
@@@ -915,7 -917,7 +917,7 @@@ int cmd_update_index(int argc, const ch
        struct refresh_params refresh_args = {0, &has_errors};
        int lock_error = 0;
        int split_index = -1;
 -      struct lock_file *lock_file;
 +      struct lock_file lock_file = LOCK_INIT;
        struct parse_opt_ctx_t ctx;
        strbuf_getline_fn getline_fn;
        int parseopt_state = PARSE_OPT_UNKNOWN;
  
        git_config(git_default_config, NULL);
  
 -      /* We can't free this memory, it becomes part of a linked list parsed atexit() */
 -      lock_file = xcalloc(1, sizeof(struct lock_file));
 -
        /* we will diagnose later if it turns out that we need to update it */
 -      newfd = hold_locked_index(lock_file, 0);
 +      newfd = hold_locked_index(&lock_file, 0);
        if (newfd < 0)
                lock_error = errno;
  
                                exit(128);
                        unable_to_lock_die(get_index_file(), lock_error);
                }
 -              if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +              if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                        die("Unable to write new index file");
        }
  
 -      rollback_lock_file(lock_file);
 +      rollback_lock_file(&lock_file);
  
        return has_errors ? 1 : 0;
  }