Here is a description of the problem we have been having, and I hope this
helps also someone else having the same problem:
We are using GitLab 7.4.3 353a987 on CentOS release 6.4 (Final).
When creating merge requests, most of the time, the MR shows all historical
commits (tens of thousands of commits) from the repository instead of the
ones in the feature branch.
The problem occurs when the master branch has new commits since the feature
branch was started.
We investigated the cause of the problem:
GitLab code calls:
Gitlab::Git::Compare.new(
target_project.repository.raw_repository,
target_branch,
source_branch,
)
And that calls:
compare.rb: @commits = Gitlab::Git::Commit.between(repository, @base.id,
@head.id)
And that calls:
commit.rb: repo.commits_between(base, head)
And that has been implemented like:
def commits_between(from, to)
walker = Rugged::Walker.new(rugged)
walker.push(to)
walker.hide(from)
commits = walker.to_a
walker.reset
The problem is that walker.hide('master') does NOT hide all historical
commits as it should.
And the root cause is in libgit2's (rugged-0.21.0) function
mark_uninteresting() in revwalk.c,
and more precisely in:
git_commit_list_node **node = git_array_alloc(pending);
That macro is defined in array.h:
#define git_array_alloc(a) \
(((a).size >= (a).asize) ? \
git_array_grow(&(a), sizeof(*(a).ptr)) : \
((a).ptr ? &(a).ptr[(a).size++] : NULL))
The problem is that git_array_grow() has code fragment:
a->ptr = new_array; a->asize = new_size; a->size++;
return a->ptr + (a->size - 1) * item_size;
which is incorrectly optimized by GCC (4.4.7 20120313 (Red Hat 4.4.7-11))
so that the return value is not
the address of the last item in array, but the second last, and that
results in early termination of mark_uninteresting()
because there is a NULL value in the pending array.
We recompiled the Rugged gem and its libgit2 without "-O2" compiler flag,
and everything started to work correctly.
Many other GCC versions do not have the problem (3.4, 4.1). Attached is C
code to reproduce the compiler problem.
Antsu Haapa
--
You received this message because you are subscribed to the Google Groups
"GitLab" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/gitlabhq/d4ef27e8-d867-465d-a005-59311ff657e3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
/* Compile with "cc -O2 koe.c" optimization -> returns offset 1 which is incorrect, should be 2.
* Occurs at least with gcc-4.4.7-11.el6.x86_64
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define git_array_t(type) struct { type *ptr; uint32_t size, asize; }
typedef git_array_t(char) git_array_generic_t;
typedef git_array_t(long) git_array_long_t;
# define GIT_INLINE(type) static inline type
GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
{
git_array_generic_t *a = _a;
uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2;
char *new_array = realloc(a->ptr, new_size * item_size);
if (!new_array) {
return NULL;
} else {
a->ptr = new_array; a->asize = new_size; a->size++;
return a->ptr + (a->size - 1) * item_size;
}
}
#define git_array_alloc(a) \
(((a).size >= (a).asize) ? \
git_array_grow(&(a), sizeof(*(a).ptr)) : \
((a).ptr ? &(a).ptr[(a).size++] : NULL))
main()
{
git_array_long_t myArray;
myArray.ptr=(long*)malloc(16);
myArray.size=2;
/* Should allocate third item and return its address */
long* node = git_array_alloc(myArray);
printf("Offset of new item: %d\n", node-myArray.ptr);
}