rugged 0.23.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/rugged/rugged_remote.c +1 -8
- data/ext/rugged/rugged_submodule_collection.c +3 -3
- data/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/CMakeLists.txt +3 -1
- data/vendor/libgit2/include/git2/diff.h +19 -0
- data/vendor/libgit2/include/git2/errors.h +1 -12
- data/vendor/libgit2/include/git2/remote.h +9 -1
- data/vendor/libgit2/include/git2/repository.h +1 -1
- data/vendor/libgit2/include/git2/sys/config.h +1 -1
- data/vendor/libgit2/include/git2/sys/diff.h +4 -4
- data/vendor/libgit2/include/git2/sys/filter.h +4 -1
- data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
- data/vendor/libgit2/include/git2/sys/refdb_backend.h +4 -3
- data/vendor/libgit2/include/git2/transport.h +14 -21
- data/vendor/libgit2/src/blame_git.c +10 -15
- data/vendor/libgit2/src/blob.c +6 -0
- data/vendor/libgit2/src/branch.c +1 -12
- data/vendor/libgit2/src/cache.c +4 -4
- data/vendor/libgit2/src/checkout.c +2 -2
- data/vendor/libgit2/src/clone.c +2 -2
- data/vendor/libgit2/src/common.h +13 -4
- data/vendor/libgit2/src/curl_stream.c +7 -7
- data/vendor/libgit2/src/describe.c +1 -1
- data/vendor/libgit2/src/diff.c +25 -0
- data/vendor/libgit2/src/errors.c +75 -40
- data/vendor/libgit2/src/filebuf.c +6 -1
- data/vendor/libgit2/src/filebuf.h +2 -0
- data/vendor/libgit2/src/filter.c +14 -9
- data/vendor/libgit2/src/global.c +25 -9
- data/vendor/libgit2/src/global.h +1 -0
- data/vendor/libgit2/src/index.c +75 -2
- data/vendor/libgit2/src/indexer.c +1 -1
- data/vendor/libgit2/src/iterator.c +6 -3
- data/vendor/libgit2/src/khash.h +1 -1
- data/vendor/libgit2/src/merge.c +3 -3
- data/vendor/libgit2/src/openssl_stream.c +5 -2
- data/vendor/libgit2/src/pack-objects.c +1 -1
- data/vendor/libgit2/src/pack.c +2 -2
- data/vendor/libgit2/src/path.c +25 -4
- data/vendor/libgit2/src/path.h +6 -1
- data/vendor/libgit2/src/push.h +3 -1
- data/vendor/libgit2/src/rebase.c +2 -2
- data/vendor/libgit2/src/refdb_fs.c +7 -0
- data/vendor/libgit2/src/remote.c +18 -9
- data/vendor/libgit2/src/revwalk.c +1 -1
- data/vendor/libgit2/src/stash.c +1 -1
- data/vendor/libgit2/src/stransport_stream.c +1 -1
- data/vendor/libgit2/src/submodule.c +12 -1
- data/vendor/libgit2/src/sysdir.c +22 -8
- data/vendor/libgit2/src/thread-utils.c +2 -0
- data/vendor/libgit2/src/transports/git.c +2 -0
- data/vendor/libgit2/src/transports/http.c +2 -2
- data/vendor/libgit2/src/transports/smart_pkt.c +1 -1
- data/vendor/libgit2/src/transports/ssh.c +4 -2
- data/vendor/libgit2/src/transports/winhttp.c +1 -1
- data/vendor/libgit2/src/util.c +48 -0
- data/vendor/libgit2/src/util.h +13 -5
- data/vendor/libgit2/src/win32/posix_w32.c +2 -0
- data/vendor/libgit2/src/win32/{buffer.c → w32_buffer.c} +1 -2
- data/vendor/libgit2/src/win32/{buffer.h → w32_buffer.h} +0 -0
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +343 -0
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +93 -0
- data/vendor/libgit2/src/win32/w32_stack.c +192 -0
- data/vendor/libgit2/src/win32/w32_stack.h +138 -0
- data/vendor/libgit2/src/xdiff/xdiff.h +10 -6
- data/vendor/libgit2/src/xdiff/xdiffi.c +46 -4
- data/vendor/libgit2/src/xdiff/xdiffi.h +1 -0
- data/vendor/libgit2/src/xdiff/xemit.c +43 -6
- data/vendor/libgit2/src/xdiff/xemit.h +1 -1
- data/vendor/libgit2/src/xdiff/xhistogram.c +1 -1
- data/vendor/libgit2/src/xdiff/xmerge.c +2 -2
- data/vendor/libgit2/src/xdiff/xpatience.c +1 -1
- data/vendor/libgit2/src/xdiff/xprepare.c +10 -11
- data/vendor/libgit2/src/xdiff/xutils.c +13 -29
- data/vendor/libgit2/src/xdiff/xutils.h +1 -0
- metadata +84 -80
|
@@ -108,7 +108,7 @@ int stransport_certificate(git_cert **out, git_stream *stream)
|
|
|
108
108
|
return -1;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
st->cert_info.cert_type = GIT_CERT_X509;
|
|
111
|
+
st->cert_info.parent.cert_type = GIT_CERT_X509;
|
|
112
112
|
st->cert_info.data = (void *) CFDataGetBytePtr(st->der_data);
|
|
113
113
|
st->cert_info.len = CFDataGetLength(st->der_data);
|
|
114
114
|
|
|
@@ -781,11 +781,21 @@ const char *git_submodule_url(git_submodule *submodule)
|
|
|
781
781
|
int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
|
|
782
782
|
{
|
|
783
783
|
int error = 0;
|
|
784
|
+
git_buf normalized = GIT_BUF_INIT;
|
|
784
785
|
|
|
785
786
|
assert(out && repo && url);
|
|
786
787
|
|
|
787
788
|
git_buf_sanitize(out);
|
|
788
789
|
|
|
790
|
+
/* We do this in all platforms in case someone on Windows created the .gitmodules */
|
|
791
|
+
if (strchr(url, '\\')) {
|
|
792
|
+
if ((error = git_path_normalize_slashes(&normalized, url)) < 0)
|
|
793
|
+
return error;
|
|
794
|
+
|
|
795
|
+
url = normalized.ptr;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
|
|
789
799
|
if (git_path_is_relative(url)) {
|
|
790
800
|
if (!(error = get_url_base(out, repo)))
|
|
791
801
|
error = git_path_apply_relative(out, url);
|
|
@@ -796,6 +806,7 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur
|
|
|
796
806
|
error = -1;
|
|
797
807
|
}
|
|
798
808
|
|
|
809
|
+
git_buf_free(&normalized);
|
|
799
810
|
return error;
|
|
800
811
|
}
|
|
801
812
|
|
|
@@ -1647,7 +1658,7 @@ static int submodule_load_from_config(
|
|
|
1647
1658
|
} else {
|
|
1648
1659
|
khiter_t pos;
|
|
1649
1660
|
git_strmap *map = data->map;
|
|
1650
|
-
pos = git_strmap_lookup_index(map, name.ptr);
|
|
1661
|
+
pos = git_strmap_lookup_index(map, path ? path : name.ptr);
|
|
1651
1662
|
if (git_strmap_valid_index(map, pos)) {
|
|
1652
1663
|
sm = git_strmap_value_at(map, pos);
|
|
1653
1664
|
} else {
|
data/vendor/libgit2/src/sysdir.c
CHANGED
|
@@ -29,7 +29,14 @@ static int git_sysdir_guess_global_dirs(git_buf *out)
|
|
|
29
29
|
#ifdef GIT_WIN32
|
|
30
30
|
return git_win32__find_global_dirs(out);
|
|
31
31
|
#else
|
|
32
|
-
|
|
32
|
+
int error = git__getenv(out, "HOME");
|
|
33
|
+
|
|
34
|
+
if (error == GIT_ENOTFOUND) {
|
|
35
|
+
giterr_clear();
|
|
36
|
+
error = 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return error;
|
|
33
40
|
#endif
|
|
34
41
|
}
|
|
35
42
|
|
|
@@ -38,15 +45,22 @@ static int git_sysdir_guess_xdg_dirs(git_buf *out)
|
|
|
38
45
|
#ifdef GIT_WIN32
|
|
39
46
|
return git_win32__find_xdg_dirs(out);
|
|
40
47
|
#else
|
|
41
|
-
|
|
48
|
+
git_buf env = GIT_BUF_INIT;
|
|
49
|
+
int error;
|
|
42
50
|
|
|
43
|
-
if ((
|
|
44
|
-
|
|
45
|
-
else if ((env = getenv("HOME")) != NULL)
|
|
46
|
-
return git_buf_joinpath(out, env, ".config/git");
|
|
51
|
+
if ((error = git__getenv(&env, "XDG_CONFIG_HOME")) == 0)
|
|
52
|
+
error = git_buf_joinpath(out, env.ptr, "git");
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
if (error == GIT_ENOTFOUND && (error = git__getenv(&env, "HOME")) == 0)
|
|
55
|
+
error = git_buf_joinpath(out, env.ptr, ".config/git");
|
|
56
|
+
|
|
57
|
+
if (error == GIT_ENOTFOUND) {
|
|
58
|
+
giterr_clear();
|
|
59
|
+
error = 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
git_buf_free(&env);
|
|
63
|
+
return error;
|
|
50
64
|
#endif
|
|
51
65
|
}
|
|
52
66
|
|
|
@@ -255,7 +255,7 @@ static int on_header_ready(http_subtransport *t)
|
|
|
255
255
|
GITERR_CHECK_ALLOC(t->content_type);
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
-
else if (!
|
|
258
|
+
else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) {
|
|
259
259
|
char *dup = git__strdup(git_buf_cstr(value));
|
|
260
260
|
GITERR_CHECK_ALLOC(dup);
|
|
261
261
|
|
|
@@ -511,7 +511,7 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len)
|
|
|
511
511
|
git_buf buf = GIT_BUF_INIT;
|
|
512
512
|
|
|
513
513
|
/* Chunk header */
|
|
514
|
-
git_buf_printf(&buf, "%
|
|
514
|
+
git_buf_printf(&buf, "%" PRIxZ "\r\n", len);
|
|
515
515
|
|
|
516
516
|
if (git_buf_oom(&buf))
|
|
517
517
|
return -1;
|
|
@@ -523,7 +523,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
|
|
|
523
523
|
|
|
524
524
|
if (len > 0xffff) {
|
|
525
525
|
giterr_set(GITERR_NET,
|
|
526
|
-
"Tried to produce packet with invalid length %
|
|
526
|
+
"Tried to produce packet with invalid length %" PRIuZ, len);
|
|
527
527
|
return -1;
|
|
528
528
|
}
|
|
529
529
|
|
|
@@ -66,6 +66,8 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
|
|
|
66
66
|
if (!git__prefixcmp(url, prefix_ssh)) {
|
|
67
67
|
url = url + strlen(prefix_ssh);
|
|
68
68
|
repo = strchr(url, '/');
|
|
69
|
+
if (repo && repo[1] == '~')
|
|
70
|
+
++repo;
|
|
69
71
|
} else {
|
|
70
72
|
repo = strchr(url, ':');
|
|
71
73
|
if (repo) repo++;
|
|
@@ -525,10 +527,10 @@ static int _git_ssh_setup_conn(
|
|
|
525
527
|
goto done;
|
|
526
528
|
|
|
527
529
|
if (t->owner->certificate_check_cb != NULL) {
|
|
528
|
-
git_cert_hostkey cert = { 0 }, *cert_ptr;
|
|
530
|
+
git_cert_hostkey cert = {{ 0 }}, *cert_ptr;
|
|
529
531
|
const char *key;
|
|
530
532
|
|
|
531
|
-
cert.cert_type = GIT_CERT_HOSTKEY_LIBSSH2;
|
|
533
|
+
cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2;
|
|
532
534
|
|
|
533
535
|
key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
|
534
536
|
if (key != NULL) {
|
|
@@ -228,7 +228,7 @@ static int certificate_check(winhttp_stream *s, int valid)
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
giterr_clear();
|
|
231
|
-
cert.cert_type = GIT_CERT_X509;
|
|
231
|
+
cert.parent.cert_type = GIT_CERT_X509;
|
|
232
232
|
cert.data = cert_ctx->pbCertEncoded;
|
|
233
233
|
cert.len = cert_ctx->cbCertEncoded;
|
|
234
234
|
error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->connection_data.host, t->owner->cred_acquire_payload);
|
data/vendor/libgit2/src/util.c
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
#include <ctype.h>
|
|
11
11
|
#include "posix.h"
|
|
12
12
|
|
|
13
|
+
#ifdef GIT_WIN32
|
|
14
|
+
# include "win32/w32_buffer.h"
|
|
15
|
+
#endif
|
|
16
|
+
|
|
13
17
|
#ifdef _MSC_VER
|
|
14
18
|
# include <Shlwapi.h>
|
|
15
19
|
#endif
|
|
@@ -765,3 +769,47 @@ int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst)
|
|
|
765
769
|
*dst = uc;
|
|
766
770
|
return length;
|
|
767
771
|
}
|
|
772
|
+
|
|
773
|
+
#ifdef GIT_WIN32
|
|
774
|
+
int git__getenv(git_buf *out, const char *name)
|
|
775
|
+
{
|
|
776
|
+
wchar_t *wide_name = NULL, *wide_value = NULL;
|
|
777
|
+
DWORD value_len;
|
|
778
|
+
int error = -1;
|
|
779
|
+
|
|
780
|
+
git_buf_clear(out);
|
|
781
|
+
|
|
782
|
+
if (git__utf8_to_16_alloc(&wide_name, name) < 0)
|
|
783
|
+
return -1;
|
|
784
|
+
|
|
785
|
+
if ((value_len = GetEnvironmentVariableW(wide_name, NULL, 0)) > 0) {
|
|
786
|
+
wide_value = git__malloc(value_len * sizeof(wchar_t));
|
|
787
|
+
GITERR_CHECK_ALLOC(wide_value);
|
|
788
|
+
|
|
789
|
+
value_len = GetEnvironmentVariableW(wide_name, wide_value, value_len);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
if (value_len)
|
|
793
|
+
error = git_buf_put_w(out, wide_value, value_len);
|
|
794
|
+
else if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
|
|
795
|
+
error = GIT_ENOTFOUND;
|
|
796
|
+
else
|
|
797
|
+
giterr_set(GITERR_OS, "could not read environment variable '%s'", name);
|
|
798
|
+
|
|
799
|
+
git__free(wide_name);
|
|
800
|
+
git__free(wide_value);
|
|
801
|
+
return error;
|
|
802
|
+
}
|
|
803
|
+
#else
|
|
804
|
+
int git__getenv(git_buf *out, const char *name)
|
|
805
|
+
{
|
|
806
|
+
const char *val = getenv(name);
|
|
807
|
+
|
|
808
|
+
git_buf_clear(out);
|
|
809
|
+
|
|
810
|
+
if (!val)
|
|
811
|
+
return GIT_ENOTFOUND;
|
|
812
|
+
|
|
813
|
+
return git_buf_puts(out, val);
|
|
814
|
+
}
|
|
815
|
+
#endif
|
data/vendor/libgit2/src/util.h
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
#ifndef INCLUDE_util_h__
|
|
8
8
|
#define INCLUDE_util_h__
|
|
9
9
|
|
|
10
|
+
#include "git2/buffer.h"
|
|
11
|
+
#include "buffer.h"
|
|
12
|
+
|
|
10
13
|
#if defined(GIT_MSVC_CRTDBG)
|
|
11
14
|
/* Enable MSVC CRTDBG memory leak reporting.
|
|
12
15
|
*
|
|
@@ -35,6 +38,7 @@
|
|
|
35
38
|
*/
|
|
36
39
|
#include <stdlib.h>
|
|
37
40
|
#include <crtdbg.h>
|
|
41
|
+
#include "win32/w32_crtdbg_stacktrace.h"
|
|
38
42
|
#endif
|
|
39
43
|
|
|
40
44
|
#include "common.h"
|
|
@@ -62,23 +66,24 @@
|
|
|
62
66
|
#define CONST_STRLEN(x) ((sizeof(x)/sizeof(x[0])) - 1)
|
|
63
67
|
|
|
64
68
|
#if defined(GIT_MSVC_CRTDBG)
|
|
69
|
+
|
|
65
70
|
GIT_INLINE(void *) git__crtdbg__malloc(size_t len, const char *file, int line)
|
|
66
71
|
{
|
|
67
|
-
void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, file, line);
|
|
72
|
+
void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
|
|
68
73
|
if (!ptr) giterr_set_oom();
|
|
69
74
|
return ptr;
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
GIT_INLINE(void *) git__crtdbg__calloc(size_t nelem, size_t elsize, const char *file, int line)
|
|
73
78
|
{
|
|
74
|
-
void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, file, line);
|
|
79
|
+
void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
|
|
75
80
|
if (!ptr) giterr_set_oom();
|
|
76
81
|
return ptr;
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
GIT_INLINE(char *) git__crtdbg__strdup(const char *str, const char *file, int line)
|
|
80
85
|
{
|
|
81
|
-
char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, file, line);
|
|
86
|
+
char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
|
|
82
87
|
if (!ptr) giterr_set_oom();
|
|
83
88
|
return ptr;
|
|
84
89
|
}
|
|
@@ -118,7 +123,7 @@ GIT_INLINE(char *) git__crtdbg__substrdup(const char *start, size_t n, const cha
|
|
|
118
123
|
|
|
119
124
|
GIT_INLINE(void *) git__crtdbg__realloc(void *ptr, size_t size, const char *file, int line)
|
|
120
125
|
{
|
|
121
|
-
void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, file, line);
|
|
126
|
+
void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
|
|
122
127
|
if (!new_ptr) giterr_set_oom();
|
|
123
128
|
return new_ptr;
|
|
124
129
|
}
|
|
@@ -126,8 +131,9 @@ GIT_INLINE(void *) git__crtdbg__realloc(void *ptr, size_t size, const char *file
|
|
|
126
131
|
GIT_INLINE(void *) git__crtdbg__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
|
|
127
132
|
{
|
|
128
133
|
size_t newsize;
|
|
134
|
+
|
|
129
135
|
return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ?
|
|
130
|
-
NULL : _realloc_dbg(ptr, newsize, _NORMAL_BLOCK, file, line);
|
|
136
|
+
NULL : _realloc_dbg(ptr, newsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
GIT_INLINE(void *) git__crtdbg__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
|
|
@@ -596,4 +602,6 @@ GIT_INLINE(double) git__timer(void)
|
|
|
596
602
|
|
|
597
603
|
#endif
|
|
598
604
|
|
|
605
|
+
extern int git__getenv(git_buf *out, const char *name);
|
|
606
|
+
|
|
599
607
|
#endif /* INCLUDE_util_h__ */
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
#include "common.h"
|
|
9
|
-
#include "
|
|
9
|
+
#include "w32_buffer.h"
|
|
10
10
|
#include "../buffer.h"
|
|
11
11
|
#include "utf-conv.h"
|
|
12
12
|
|
|
@@ -52,4 +52,3 @@ int git_buf_put_w(git_buf *buf, const wchar_t *string_w, size_t len_w)
|
|
|
52
52
|
buf->ptr[buf->size] = '\0';
|
|
53
53
|
return 0;
|
|
54
54
|
}
|
|
55
|
-
|
|
File without changes
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
5
|
+
* a Linking Exception. For full terms see the included COPYING file.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#if defined(GIT_MSVC_CRTDBG)
|
|
9
|
+
#include "w32_stack.h"
|
|
10
|
+
#include "w32_crtdbg_stacktrace.h"
|
|
11
|
+
|
|
12
|
+
#define CRTDBG_STACKTRACE__UID_LEN (15)
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The stacktrace of an allocation can be distilled
|
|
16
|
+
* to a unique id based upon the stackframe pointers
|
|
17
|
+
* and ignoring any size arguments. We will use these
|
|
18
|
+
* UIDs as the (char const*) __FILE__ argument we
|
|
19
|
+
* give to the CRT malloc routines.
|
|
20
|
+
*/
|
|
21
|
+
typedef struct {
|
|
22
|
+
char uid[CRTDBG_STACKTRACE__UID_LEN + 1];
|
|
23
|
+
} git_win32__crtdbg_stacktrace__uid;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* All mallocs with the same stacktrace will be de-duped
|
|
27
|
+
* and aggregated into this row.
|
|
28
|
+
*/
|
|
29
|
+
typedef struct {
|
|
30
|
+
git_win32__crtdbg_stacktrace__uid uid; /* must be first */
|
|
31
|
+
git_win32__stack__raw_data raw_data;
|
|
32
|
+
unsigned int count_allocs; /* times this alloc signature seen since init */
|
|
33
|
+
unsigned int count_allocs_at_last_checkpoint; /* times since last mark */
|
|
34
|
+
unsigned int transient_count_leaks; /* sum of leaks */
|
|
35
|
+
} git_win32__crtdbg_stacktrace__row;
|
|
36
|
+
|
|
37
|
+
static CRITICAL_SECTION g_crtdbg_stacktrace_cs;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* CRTDBG memory leak tracking takes a "char const * const file_name"
|
|
41
|
+
* and stores the pointer in the heap data (instead of allocing a copy
|
|
42
|
+
* for itself). Normally, this is not a problem, since we usually pass
|
|
43
|
+
* in __FILE__. But I'm going to lie to it and pass in the address of
|
|
44
|
+
* the UID in place of the file_name. Also, I do not want to alloc the
|
|
45
|
+
* stacktrace data (because we are called from inside our alloc routines).
|
|
46
|
+
* Therefore, I'm creating a very large static pool array to store row
|
|
47
|
+
* data. This also eliminates the temptation to realloc it (and move the
|
|
48
|
+
* UID pointers).
|
|
49
|
+
*
|
|
50
|
+
* And to efficiently look for duplicates we need an index on the rows
|
|
51
|
+
* so we can bsearch it. Again, without mallocing.
|
|
52
|
+
*
|
|
53
|
+
* If we observe more than MY_ROW_LIMIT unique malloc signatures, we
|
|
54
|
+
* fall through and use the traditional __FILE__ processing and don't
|
|
55
|
+
* try to de-dup them. If your testing hits this limit, just increase
|
|
56
|
+
* it and try again.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
#define MY_ROW_LIMIT (1024 * 1024)
|
|
60
|
+
static git_win32__crtdbg_stacktrace__row g_cs_rows[MY_ROW_LIMIT];
|
|
61
|
+
static git_win32__crtdbg_stacktrace__row *g_cs_index[MY_ROW_LIMIT];
|
|
62
|
+
|
|
63
|
+
static unsigned int g_cs_end = MY_ROW_LIMIT;
|
|
64
|
+
static unsigned int g_cs_ins = 0; /* insertion point == unique allocs seen */
|
|
65
|
+
static unsigned int g_count_total_allocs = 0; /* number of allocs seen */
|
|
66
|
+
static unsigned int g_transient_count_total_leaks = 0; /* number of total leaks */
|
|
67
|
+
static unsigned int g_transient_count_dedup_leaks = 0; /* number of unique leaks */
|
|
68
|
+
static bool g_limit_reached = false; /* had allocs after we filled row table */
|
|
69
|
+
|
|
70
|
+
static unsigned int g_checkpoint_id = 0; /* to better label leak checkpoints */
|
|
71
|
+
static bool g_transient_leaks_since_mark = false; /* payload for hook */
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Compare function for bsearch on g_cs_index table.
|
|
75
|
+
*/
|
|
76
|
+
static int row_cmp(const void *v1, const void *v2)
|
|
77
|
+
{
|
|
78
|
+
git_win32__stack__raw_data *d1 = (git_win32__stack__raw_data*)v1;
|
|
79
|
+
git_win32__crtdbg_stacktrace__row *r2 = (git_win32__crtdbg_stacktrace__row *)v2;
|
|
80
|
+
|
|
81
|
+
return (git_win32__stack_compare(d1, &r2->raw_data));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Unique insert the new data into the row and index tables.
|
|
86
|
+
* We have to sort by the stackframe data itself, not the uid.
|
|
87
|
+
*/
|
|
88
|
+
static git_win32__crtdbg_stacktrace__row * insert_unique(
|
|
89
|
+
const git_win32__stack__raw_data *pdata)
|
|
90
|
+
{
|
|
91
|
+
size_t pos;
|
|
92
|
+
if (git__bsearch(g_cs_index, g_cs_ins, pdata, row_cmp, &pos) < 0) {
|
|
93
|
+
/* Append new unique item to row table. */
|
|
94
|
+
memcpy(&g_cs_rows[g_cs_ins].raw_data, pdata, sizeof(*pdata));
|
|
95
|
+
sprintf(g_cs_rows[g_cs_ins].uid.uid, "##%08lx", g_cs_ins);
|
|
96
|
+
|
|
97
|
+
/* Insert pointer to it into the proper place in the index table. */
|
|
98
|
+
if (pos < g_cs_ins)
|
|
99
|
+
memmove(&g_cs_index[pos+1], &g_cs_index[pos], (g_cs_ins - pos)*sizeof(g_cs_index[0]));
|
|
100
|
+
g_cs_index[pos] = &g_cs_rows[g_cs_ins];
|
|
101
|
+
|
|
102
|
+
g_cs_ins++;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
g_cs_index[pos]->count_allocs++;
|
|
106
|
+
|
|
107
|
+
return g_cs_index[pos];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Hook function to receive leak data from the CRT. (This includes
|
|
112
|
+
* both "<file_name>:(<line_number>)" data, but also each of the
|
|
113
|
+
* various headers and fields.
|
|
114
|
+
*
|
|
115
|
+
* Scan this for the special "##<pos>" UID forms that we substituted
|
|
116
|
+
* for the "<file_name>". Map <pos> back to the row data and
|
|
117
|
+
* increment its leak count.
|
|
118
|
+
*
|
|
119
|
+
* See https://msdn.microsoft.com/en-us/library/74kabxyx.aspx
|
|
120
|
+
*
|
|
121
|
+
* We suppress the actual crtdbg output.
|
|
122
|
+
*/
|
|
123
|
+
static int __cdecl report_hook(int nRptType, char *szMsg, int *retVal)
|
|
124
|
+
{
|
|
125
|
+
static int hook_result = TRUE; /* FALSE to get stock dump; TRUE to suppress. */
|
|
126
|
+
unsigned int pos;
|
|
127
|
+
|
|
128
|
+
*retVal = 0; /* do not invoke debugger */
|
|
129
|
+
|
|
130
|
+
if ((szMsg[0] != '#') || (szMsg[1] != '#'))
|
|
131
|
+
return hook_result;
|
|
132
|
+
|
|
133
|
+
if (sscanf(&szMsg[2], "%08lx", &pos) < 1)
|
|
134
|
+
return hook_result;
|
|
135
|
+
if (pos >= g_cs_ins)
|
|
136
|
+
return hook_result;
|
|
137
|
+
|
|
138
|
+
if (g_transient_leaks_since_mark) {
|
|
139
|
+
if (g_cs_rows[pos].count_allocs == g_cs_rows[pos].count_allocs_at_last_checkpoint)
|
|
140
|
+
return hook_result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
g_cs_rows[pos].transient_count_leaks++;
|
|
144
|
+
|
|
145
|
+
if (g_cs_rows[pos].transient_count_leaks == 1)
|
|
146
|
+
g_transient_count_dedup_leaks++;
|
|
147
|
+
|
|
148
|
+
g_transient_count_total_leaks++;
|
|
149
|
+
|
|
150
|
+
return hook_result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Write leak data to all of the various places we need.
|
|
155
|
+
* We force the caller to sprintf() the message first
|
|
156
|
+
* because we want to avoid fprintf() because it allocs.
|
|
157
|
+
*/
|
|
158
|
+
static void my_output(const char *buf)
|
|
159
|
+
{
|
|
160
|
+
fwrite(buf, strlen(buf), 1, stderr);
|
|
161
|
+
OutputDebugString(buf);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* For each row with leaks, dump a stacktrace for it.
|
|
166
|
+
*/
|
|
167
|
+
static void dump_summary(const char *label)
|
|
168
|
+
{
|
|
169
|
+
unsigned int k;
|
|
170
|
+
char buf[10 * 1024];
|
|
171
|
+
|
|
172
|
+
if (g_transient_count_total_leaks == 0)
|
|
173
|
+
return;
|
|
174
|
+
|
|
175
|
+
fflush(stdout);
|
|
176
|
+
fflush(stderr);
|
|
177
|
+
my_output("\n");
|
|
178
|
+
|
|
179
|
+
if (g_limit_reached) {
|
|
180
|
+
sprintf(buf,
|
|
181
|
+
"LEAK SUMMARY: de-dup row table[%d] filled. Increase MY_ROW_LIMIT.\n",
|
|
182
|
+
MY_ROW_LIMIT);
|
|
183
|
+
my_output(buf);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!label)
|
|
187
|
+
label = "";
|
|
188
|
+
|
|
189
|
+
if (g_transient_leaks_since_mark) {
|
|
190
|
+
sprintf(buf, "LEAK CHECKPOINT %d: leaks %d unique %d: %s\n",
|
|
191
|
+
g_checkpoint_id, g_transient_count_total_leaks, g_transient_count_dedup_leaks, label);
|
|
192
|
+
my_output(buf);
|
|
193
|
+
} else {
|
|
194
|
+
sprintf(buf, "LEAK SUMMARY: TOTAL leaks %d de-duped %d: %s\n",
|
|
195
|
+
g_transient_count_total_leaks, g_transient_count_dedup_leaks, label);
|
|
196
|
+
my_output(buf);
|
|
197
|
+
}
|
|
198
|
+
my_output("\n");
|
|
199
|
+
|
|
200
|
+
for (k = 0; k < g_cs_ins; k++) {
|
|
201
|
+
if (g_cs_rows[k].transient_count_leaks > 0) {
|
|
202
|
+
sprintf(buf, "LEAK: %s leaked %d of %d times:\n",
|
|
203
|
+
g_cs_rows[k].uid.uid,
|
|
204
|
+
g_cs_rows[k].transient_count_leaks,
|
|
205
|
+
g_cs_rows[k].count_allocs);
|
|
206
|
+
my_output(buf);
|
|
207
|
+
|
|
208
|
+
if (git_win32__stack_format(
|
|
209
|
+
buf, sizeof(buf), &g_cs_rows[k].raw_data,
|
|
210
|
+
NULL, NULL) >= 0) {
|
|
211
|
+
my_output(buf);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
my_output("\n");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
fflush(stderr);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
void git_win32__crtdbg_stacktrace_init(void)
|
|
222
|
+
{
|
|
223
|
+
InitializeCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
224
|
+
|
|
225
|
+
EnterCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
226
|
+
|
|
227
|
+
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
|
228
|
+
|
|
229
|
+
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
|
230
|
+
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
|
231
|
+
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
|
232
|
+
|
|
233
|
+
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
|
234
|
+
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
|
|
235
|
+
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
|
236
|
+
|
|
237
|
+
LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
int git_win32__crtdbg_stacktrace__dump(
|
|
241
|
+
git_win32__crtdbg_stacktrace_options opt,
|
|
242
|
+
const char *label)
|
|
243
|
+
{
|
|
244
|
+
_CRT_REPORT_HOOK old;
|
|
245
|
+
unsigned int k;
|
|
246
|
+
int r = 0;
|
|
247
|
+
|
|
248
|
+
#define IS_BIT_SET(o,b) (((o) & (b)) != 0)
|
|
249
|
+
|
|
250
|
+
bool b_set_mark = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK);
|
|
251
|
+
bool b_leaks_since_mark = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK);
|
|
252
|
+
bool b_leaks_total = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL);
|
|
253
|
+
bool b_quiet = IS_BIT_SET(opt, GIT_WIN32__CRTDBG_STACKTRACE__QUIET);
|
|
254
|
+
|
|
255
|
+
if (b_leaks_since_mark && b_leaks_total) {
|
|
256
|
+
giterr_set(GITERR_INVALID, "Cannot combine LEAKS_SINCE_MARK and LEAKS_TOTAL.");
|
|
257
|
+
return GIT_ERROR;
|
|
258
|
+
}
|
|
259
|
+
if (!b_set_mark && !b_leaks_since_mark && !b_leaks_total) {
|
|
260
|
+
giterr_set(GITERR_INVALID, "Nothing to do.");
|
|
261
|
+
return GIT_ERROR;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
EnterCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
265
|
+
|
|
266
|
+
if (b_leaks_since_mark || b_leaks_total) {
|
|
267
|
+
/* All variables with "transient" in the name are per-dump counters
|
|
268
|
+
* and reset before each dump. This lets us handle checkpoints.
|
|
269
|
+
*/
|
|
270
|
+
g_transient_count_total_leaks = 0;
|
|
271
|
+
g_transient_count_dedup_leaks = 0;
|
|
272
|
+
for (k = 0; k < g_cs_ins; k++) {
|
|
273
|
+
g_cs_rows[k].transient_count_leaks = 0;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
g_transient_leaks_since_mark = b_leaks_since_mark;
|
|
278
|
+
|
|
279
|
+
old = _CrtSetReportHook(report_hook);
|
|
280
|
+
_CrtDumpMemoryLeaks();
|
|
281
|
+
_CrtSetReportHook(old);
|
|
282
|
+
|
|
283
|
+
if (b_leaks_since_mark || b_leaks_total) {
|
|
284
|
+
r = g_transient_count_dedup_leaks;
|
|
285
|
+
|
|
286
|
+
if (!b_quiet)
|
|
287
|
+
dump_summary(label);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (b_set_mark) {
|
|
291
|
+
for (k = 0; k < g_cs_ins; k++) {
|
|
292
|
+
g_cs_rows[k].count_allocs_at_last_checkpoint = g_cs_rows[k].count_allocs;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
g_checkpoint_id++;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
299
|
+
|
|
300
|
+
return r;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
void git_win32__crtdbg_stacktrace_cleanup(void)
|
|
304
|
+
{
|
|
305
|
+
/* At shutdown/cleanup, dump cummulative leak info
|
|
306
|
+
* with everything since startup. This might generate
|
|
307
|
+
* extra noise if the caller has been doing checkpoint
|
|
308
|
+
* dumps, but it might also eliminate some false
|
|
309
|
+
* positives for resources previously reported during
|
|
310
|
+
* checkpoints.
|
|
311
|
+
*/
|
|
312
|
+
git_win32__crtdbg_stacktrace__dump(
|
|
313
|
+
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL,
|
|
314
|
+
"CLEANUP");
|
|
315
|
+
|
|
316
|
+
DeleteCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const char *git_win32__crtdbg_stacktrace(int skip, const char *file)
|
|
320
|
+
{
|
|
321
|
+
git_win32__stack__raw_data new_data;
|
|
322
|
+
git_win32__crtdbg_stacktrace__row *row;
|
|
323
|
+
const char * result = file;
|
|
324
|
+
|
|
325
|
+
if (git_win32__stack_capture(&new_data, skip+1) < 0)
|
|
326
|
+
return result;
|
|
327
|
+
|
|
328
|
+
EnterCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
329
|
+
|
|
330
|
+
if (g_cs_ins < g_cs_end) {
|
|
331
|
+
row = insert_unique(&new_data);
|
|
332
|
+
result = row->uid.uid;
|
|
333
|
+
} else {
|
|
334
|
+
g_limit_reached = true;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
g_count_total_allocs++;
|
|
338
|
+
|
|
339
|
+
LeaveCriticalSection(&g_crtdbg_stacktrace_cs);
|
|
340
|
+
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
#endif
|