Merge branch 'rs/no-null-ptr-arith-in-fast-export'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:06 +0000 (14:04 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:06 +0000 (14:04 +0900)
Code clean-up to avoid non-standard-conformant pointer arithmetic.

* rs/no-null-ptr-arith-in-fast-export:
fast-export: avoid NULL pointer arithmetic

1  2 
builtin/fast-export.c
diff --combined builtin/fast-export.c
index 68a762fbeaa1363d6b0d709f1500b1925796a711,9aa4f7fce8f148e1d4cd2ebdd598c4dbad6cfcc6..07d20f446fa7c4a7c62be5e6ef44a7bd06e5d5a9
@@@ -5,7 -5,6 +5,7 @@@
   */
  #include "builtin.h"
  #include "cache.h"
 +#include "config.h"
  #include "refs.h"
  #include "commit.h"
  #include "object.h"
@@@ -93,9 -92,8 +93,9 @@@ struct anonymized_entry 
        size_t anon_len;
  };
  
 -static int anonymized_entry_cmp(const void *va, const void *vb,
 -                              const void *data)
 +static int anonymized_entry_cmp(const void *unused_cmp_data,
 +                              const void *va, const void *vb,
 +                              const void *unused_keydata)
  {
        const struct anonymized_entry *a = va, *b = vb;
        return a->orig_len != b->orig_len ||
@@@ -114,7 -112,7 +114,7 @@@ static const void *anonymize_mem(struc
        struct anonymized_entry key, *ret;
  
        if (!map->cmpfn)
 -              hashmap_init(map, anonymized_entry_cmp, 0);
 +              hashmap_init(map, anonymized_entry_cmp, NULL, 0);
  
        hashmap_entry_init(&key, memhash(orig, *len));
        key.orig = orig;
@@@ -156,15 -154,14 +156,14 @@@ static void anonymize_path(struct strbu
        }
  }
  
- /* Since intptr_t is C99, we do not use it here */
- static inline uint32_t *mark_to_ptr(uint32_t mark)
+ static inline void *mark_to_ptr(uint32_t mark)
  {
-       return ((uint32_t *)NULL) + mark;
+       return (void *)(uintptr_t)mark;
  }
  
  static inline uint32_t ptr_to_mark(void * mark)
  {
-       return (uint32_t *)mark - (uint32_t *)NULL;
+       return (uint32_t)(uintptr_t)mark;
  }
  
  static inline void mark_object(struct object *object, uint32_t mark)
@@@ -214,7 -211,7 +213,7 @@@ static char *anonymize_blob(unsigned lo
        return strbuf_detach(&out, NULL);
  }
  
 -static void export_blob(const unsigned char *sha1)
 +static void export_blob(const struct object_id *oid)
  {
        unsigned long size;
        enum object_type type;
        if (no_data)
                return;
  
 -      if (is_null_sha1(sha1))
 +      if (is_null_oid(oid))
                return;
  
 -      object = lookup_object(sha1);
 +      object = lookup_object(oid->hash);
        if (object && object->flags & SHOWN)
                return;
  
        if (anonymize) {
                buf = anonymize_blob(&size);
 -              object = (struct object *)lookup_blob(sha1);
 +              object = (struct object *)lookup_blob(oid);
                eaten = 0;
        } else {
 -              buf = read_sha1_file(sha1, &type, &size);
 +              buf = read_object_file(oid, &type, &size);
                if (!buf)
 -                      die ("Could not read blob %s", sha1_to_hex(sha1));
 -              if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
 -                      die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
 -              object = parse_object_buffer(sha1, type, size, buf, &eaten);
 +                      die ("Could not read blob %s", oid_to_hex(oid));
 +              if (check_object_signature(oid, buf, size, type_name(type)) < 0)
 +                      die("sha1 mismatch in blob %s", oid_to_hex(oid));
 +              object = parse_object_buffer(oid, type, size, buf, &eaten);
        }
  
        if (!object)
 -              die("Could not read blob %s", sha1_to_hex(sha1));
 +              die("Could not read blob %s", oid_to_hex(oid));
  
        mark_next_object(object);
  
        printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
        if (size && fwrite(buf, size, 1, stdout) != 1)
 -              die_errno ("Could not write blob '%s'", sha1_to_hex(sha1));
 +              die_errno ("Could not write blob '%s'", oid_to_hex(oid));
        printf("\n");
  
        show_progress();
@@@ -325,32 -322,31 +324,32 @@@ static void print_path(const char *path
        }
  }
  
 -static void *generate_fake_sha1(const void *old, size_t *len)
 +static void *generate_fake_oid(const void *old, size_t *len)
  {
        static uint32_t counter = 1; /* avoid null sha1 */
 -      unsigned char *out = xcalloc(20, 1);
 -      put_be32(out + 16, counter++);
 +      unsigned char *out = xcalloc(GIT_SHA1_RAWSZ, 1);
 +      put_be32(out + GIT_SHA1_RAWSZ - 4, counter++);
        return out;
  }
  
 -static const unsigned char *anonymize_sha1(const unsigned char *sha1)
 +static const unsigned char *anonymize_sha1(const struct object_id *oid)
  {
        static struct hashmap sha1s;
 -      size_t len = 20;
 -      return anonymize_mem(&sha1s, generate_fake_sha1, sha1, &len);
 +      size_t len = GIT_SHA1_RAWSZ;
 +      return anonymize_mem(&sha1s, generate_fake_oid, oid, &len);
  }
  
  static void show_filemodify(struct diff_queue_struct *q,
                            struct diff_options *options, void *data)
  {
        int i;
 +      struct string_list *changed = data;
  
        /*
         * Handle files below a directory first, in case they are all deleted
         * and the directory changes to a file or symlink.
         */
 -      qsort(q->queue, q->nr, sizeof(q->queue[0]), depth_first);
 +      QSORT(q->queue, q->nr, depth_first);
  
        for (i = 0; i < q->nr; i++) {
                struct diff_filespec *ospec = q->queue[i]->one;
                case DIFF_STATUS_DELETED:
                        printf("D ");
                        print_path(spec->path);
 +                      string_list_insert(changed, spec->path);
                        putchar('\n');
                        break;
  
                case DIFF_STATUS_COPIED:
                case DIFF_STATUS_RENAMED:
 -                      printf("%c ", q->queue[i]->status);
 -                      print_path(ospec->path);
 -                      putchar(' ');
 -                      print_path(spec->path);
 -                      putchar('\n');
 -
 -                      if (!oidcmp(&ospec->oid, &spec->oid) &&
 -                          ospec->mode == spec->mode)
 -                              break;
 +                      /*
 +                       * If a change in the file corresponding to ospec->path
 +                       * has been observed, we cannot trust its contents
 +                       * because the diff is calculated based on the prior
 +                       * contents, not the current contents.  So, declare a
 +                       * copy or rename only if there was no change observed.
 +                       */
 +                      if (!string_list_has_string(changed, ospec->path)) {
 +                              printf("%c ", q->queue[i]->status);
 +                              print_path(ospec->path);
 +                              putchar(' ');
 +                              print_path(spec->path);
 +                              string_list_insert(changed, spec->path);
 +                              putchar('\n');
 +
 +                              if (!oidcmp(&ospec->oid, &spec->oid) &&
 +                                  ospec->mode == spec->mode)
 +                                      break;
 +                      }
                        /* fallthrough */
  
                case DIFF_STATUS_TYPE_CHANGED:
                        if (no_data || S_ISGITLINK(spec->mode))
                                printf("M %06o %s ", spec->mode,
                                       sha1_to_hex(anonymize ?
 -                                                 anonymize_sha1(spec->oid.hash) :
 +                                                 anonymize_sha1(&spec->oid) :
                                                   spec->oid.hash));
                        else {
                                struct object *object = lookup_object(spec->oid.hash);
                                       get_object_mark(object));
                        }
                        print_path(spec->path);
 +                      string_list_insert(changed, spec->path);
                        putchar('\n');
                        break;
  
@@@ -541,8 -525,7 +540,8 @@@ static void anonymize_ident_line(const 
        *end = out->buf + out->len;
  }
  
 -static void handle_commit(struct commit *commit, struct rev_info *rev)
 +static void handle_commit(struct commit *commit, struct rev_info *rev,
 +                        struct string_list *paths_of_changed_objects)
  {
        int saved_output_format = rev->diffopt.output_format;
        const char *commit_buffer;
            get_object_mark(&commit->parents->item->object) != 0 &&
            !full_tree) {
                parse_commit_or_die(commit->parents->item);
 -              diff_tree_sha1(commit->parents->item->tree->object.oid.hash,
 -                             commit->tree->object.oid.hash, "", &rev->diffopt);
 +              diff_tree_oid(get_commit_tree_oid(commit->parents->item),
 +                            get_commit_tree_oid(commit), "", &rev->diffopt);
        }
        else
 -              diff_root_tree_sha1(commit->tree->object.oid.hash,
 -                                  "", &rev->diffopt);
 +              diff_root_tree_oid(get_commit_tree_oid(commit),
 +                                 "", &rev->diffopt);
  
        /* Export the referenced blobs, and remember the marks. */
        for (i = 0; i < diff_queued_diff.nr; i++)
                if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
 -                      export_blob(diff_queued_diff.queue[i]->two->oid.hash);
 +                      export_blob(&diff_queued_diff.queue[i]->two->oid);
  
        refname = commit->util;
        if (anonymize) {
        if (full_tree)
                printf("deleteall\n");
        log_tree_diff_flush(rev);
 +      string_list_clear(paths_of_changed_objects, 0);
        rev->diffopt.output_format = saved_output_format;
  
        printf("\n");
@@@ -645,18 -627,15 +644,18 @@@ static void *anonymize_tag(const void *
        return strbuf_detach(&out, len);
  }
  
 -static void handle_tail(struct object_array *commits, struct rev_info *revs)
 +static void handle_tail(struct object_array *commits, struct rev_info *revs,
 +                      struct string_list *paths_of_changed_objects)
  {
        struct commit *commit;
        while (commits->nr) {
 -              commit = (struct commit *)commits->objects[commits->nr - 1].item;
 -              if (has_unshown_parent(commit))
 +              commit = (struct commit *)object_array_pop(commits);
 +              if (has_unshown_parent(commit)) {
 +                      /* Queue again, to be handled later */
 +                      add_object_array(&commit->object, NULL, commits);
                        return;
 -              handle_commit(commit, revs);
 -              commits->nr--;
 +              }
 +              handle_commit(commit, revs, paths_of_changed_objects);
        }
  }
  
@@@ -685,7 -664,7 +684,7 @@@ static void handle_tag(const char *name
                return;
        }
  
 -      buf = read_sha1_file(tag->object.oid.hash, &type, &size);
 +      buf = read_object_file(&tag->object.oid, &type, &size);
        if (!buf)
                die ("Could not read tag %s", oid_to_hex(&tag->object.oid));
        message = memmem(buf, size, "\n\n", 2);
                             oid_to_hex(&tag->object.oid));
                case DROP:
                        /* Ignore this tag altogether */
 +                      free(buf);
                        return;
                case REWRITE:
                        if (tagged->type != OBJ_COMMIT) {
                                die ("Tag %s tags unexported %s!",
                                     oid_to_hex(&tag->object.oid),
 -                                   typename(tagged->type));
 +                                   type_name(tagged->type));
                        }
                        p = (struct commit *)tagged;
                        for (;;) {
               (int)(tagger_end - tagger), tagger,
               tagger == tagger_end ? "" : "\n",
               (int)message_size, (int)message_size, message ? message : "");
 +      free(buf);
  }
  
  static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
  
                /* handle nested tags */
                while (tag && tag->object.type == OBJ_TAG) {
 -                      parse_object(tag->object.oid.hash);
 +                      parse_object(&tag->object.oid);
                        string_list_append(&extra_refs, full_name)->util = tag;
                        tag = (struct tag *)tag->tagged;
                }
@@@ -819,14 -796,14 +818,14 @@@ static void get_tags_and_duplicates(str
  
        for (i = 0; i < info->nr; i++) {
                struct rev_cmdline_entry *e = info->rev + i;
 -              unsigned char sha1[20];
 +              struct object_id oid;
                struct commit *commit;
                char *full_name;
  
                if (e->flags & UNINTERESTING)
                        continue;
  
 -              if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
 +              if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
                        continue;
  
                if (refspecs) {
                if (!commit) {
                        warning("%s: Unexpected object of type %s, skipping.",
                                e->name,
 -                              typename(e->item->type));
 +                              type_name(e->item->type));
                        continue;
                }
  
                case OBJ_COMMIT:
                        break;
                case OBJ_BLOB:
 -                      export_blob(commit->object.oid.hash);
 +                      export_blob(&commit->object.oid);
                        continue;
                default: /* OBJ_TAG (nested tags) is already handled */
                        warning("Tag points to object of unexpected type %s, skipping.",
 -                              typename(commit->object.type));
 +                              type_name(commit->object.type));
                        continue;
                }
  
@@@ -898,7 -875,7 +897,7 @@@ static void export_marks(char *file
  {
        unsigned int i;
        uint32_t mark;
 -      struct object_decoration *deco = idnums.hash;
 +      struct decoration_entry *deco = idnums.entries;
        FILE *f;
        int e = 0;
  
  static void import_marks(char *input_file)
  {
        char line[512];
 -      FILE *f = fopen(input_file, "r");
 -      if (!f)
 -              die_errno("cannot read '%s'", input_file);
 +      FILE *f = xfopen(input_file, "r");
  
        while (fgets(line, sizeof(line), f)) {
                uint32_t mark;
                char *line_end, *mark_end;
 -              unsigned char sha1[20];
 +              struct object_id oid;
                struct object *object;
                struct commit *commit;
                enum object_type type;
  
                mark = strtoumax(line + 1, &mark_end, 10);
                if (!mark || mark_end == line + 1
 -                      || *mark_end != ' ' || get_sha1_hex(mark_end + 1, sha1))
 +                      || *mark_end != ' ' || get_oid_hex(mark_end + 1, &oid))
                        die("corrupt mark line: %s", line);
  
                if (last_idnum < mark)
                        last_idnum = mark;
  
 -              type = sha1_object_info(sha1, NULL);
 +              type = oid_object_info(the_repository, &oid, NULL);
                if (type < 0)
 -                      die("object not found: %s", sha1_to_hex(sha1));
 +                      die("object not found: %s", oid_to_hex(&oid));
  
                if (type != OBJ_COMMIT)
                        /* only commits */
                        continue;
  
 -              commit = lookup_commit(sha1);
 +              commit = lookup_commit(&oid);
                if (!commit)
 -                      die("not a commit? can't happen: %s", sha1_to_hex(sha1));
 +                      die("not a commit? can't happen: %s", oid_to_hex(&oid));
  
                object = &commit->object;
  
                if (object->flags & SHOWN)
 -                      error("Object %s already has a mark", sha1_to_hex(sha1));
 +                      error("Object %s already has a mark", oid_to_hex(&oid));
  
                mark_object(object, mark);
  
@@@ -995,7 -974,6 +994,7 @@@ int cmd_fast_export(int argc, const cha
        char *export_filename = NULL, *import_filename = NULL;
        uint32_t lastimportid;
        struct string_list refspecs_list = STRING_LIST_INIT_NODUP;
 +      struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP;
        struct option options[] = {
                OPT_INTEGER(0, "progress", &progress,
                            N_("show progress after <n> objects")),
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
        revs.diffopt.format_callback = show_filemodify;
 -      DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
 +      revs.diffopt.format_callback_data = &paths_of_changed_objects;
 +      revs.diffopt.flags.recursive = 1;
        while ((commit = get_revision(&revs))) {
                if (has_unshown_parent(commit)) {
                        add_object_array(&commit->object, NULL, &commits);
                }
                else {
 -                      handle_commit(commit, &revs);
 -                      handle_tail(&commits, &revs);
 +                      handle_commit(commit, &revs, &paths_of_changed_objects);
 +                      handle_tail(&commits, &revs, &paths_of_changed_objects);
                }
        }