Merge pull request #1692 from arrbee/fix-1692 Segmentation fault on git_clone
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
diff --git a/src/buffer.c b/src/buffer.c
index 6e3ffe5..b5b2fd6 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -259,6 +259,15 @@ void git_buf_truncate(git_buf *buf, size_t len)
}
}
+void git_buf_shorten(git_buf *buf, size_t amount)
+{
+ if (amount > buf->size)
+ amount = buf->size;
+
+ buf->size = buf->size - amount;
+ buf->ptr[buf->size] = '\0';
+}
+
void git_buf_rtruncate_at_char(git_buf *buf, char separator)
{
ssize_t idx = git_buf_rfind_next(buf, separator);
diff --git a/src/buffer.h b/src/buffer.h
index 5402f38..f3e1d50 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -91,6 +91,7 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap);
void git_buf_clear(git_buf *buf);
void git_buf_consume(git_buf *buf, const char *end);
void git_buf_truncate(git_buf *buf, size_t len);
+void git_buf_shorten(git_buf *buf, size_t amount);
void git_buf_rtruncate_at_char(git_buf *path, char separator);
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
diff --git a/src/clone.c b/src/clone.c
index 5b6c6f7..5c11872 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -204,7 +204,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
/* Get the remote's HEAD. This is always the first ref in remote->refs. */
remote_head = NULL;
-
+
if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head))
return -1;
@@ -220,7 +220,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
memset(&dummy_spec, 0, sizeof(git_refspec));
head_info.refspec = &dummy_spec;
}
-
+
/* Determine the remote tracking reference name from the local master */
if (git_refspec_transform_r(
&remote_master_name,
diff --git a/src/config_file.c b/src/config_file.c
index dec9521..2b0732a 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -1395,7 +1395,7 @@ static int parse_multiline_variable(diskfile_backend *cfg, git_buf *value, int i
* standard, this character **has** to be last one in the buf, with
* no whitespace after it */
assert(is_multiline_var(value->ptr));
- git_buf_truncate(value, git_buf_len(value) - 1);
+ git_buf_shorten(value, 1);
proc_line = fixup_line(line, in_quotes);
if (proc_line == NULL) {
diff --git a/src/indexer.c b/src/indexer.c
index 1b5339f..1b638cd 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -602,7 +602,7 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_transfer_progress *
git_vector_sort(&idx->objects);
git_buf_sets(&filename, idx->pack->pack_name);
- git_buf_truncate(&filename, filename.size - strlen("pack"));
+ git_buf_shorten(&filename, strlen("pack"));
git_buf_puts(&filename, "idx");
if (git_buf_oom(&filename))
return -1;
diff --git a/src/refspec.c b/src/refspec.c
index a907df8..492c6ed 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -225,25 +225,31 @@ int git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, co
return refspec_transform_internal(out, outlen, spec->dst, spec->src, name);
}
-static int refspec_transform(git_buf *out, const char *from, const char *to, const char *name)
+static int refspec_transform(
+ git_buf *out, const char *from, const char *to, const char *name)
{
- if (git_buf_sets(out, to) < 0)
- return -1;
+ size_t to_len = to ? strlen(to) : 0;
+ size_t from_len = from ? strlen(from) : 0;
+ size_t name_len = name ? strlen(name) : 0;
- /*
- * No '*' at the end means that it's mapped to one specific
- * branch, so no actual transformation is needed.
- */
- if (git_buf_len(out) > 0 && out->ptr[git_buf_len(out) - 1] != '*')
- return 0;
+ if (git_buf_set(out, to, to_len) < 0)
+ return -1;
- git_buf_truncate(out, git_buf_len(out) - 1); /* remove trailing '*' */
- git_buf_puts(out, name + strlen(from) - 1);
+ if (to_len > 0) {
+ /* No '*' at the end of 'to' means that refspec is mapped to one
+ * specific branch, so no actual transformation is needed.
+ */
+ if (out->ptr[to_len - 1] != '*')
+ return 0;
+ git_buf_shorten(out, 1); /* remove trailing '*' copied from 'to' */
+ }
- if (git_buf_oom(out))
- return -1;
+ if (from_len > 0) /* ignore trailing '*' from 'from' */
+ from_len--;
+ if (from_len > name_len)
+ from_len = name_len;
- return 0;
+ return git_buf_put(out, name + from_len, name_len - from_len);
}
int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name)