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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_remote.c +1 -8
  3. data/ext/rugged/rugged_submodule_collection.c +3 -3
  4. data/lib/rugged/version.rb +1 -1
  5. data/vendor/libgit2/CMakeLists.txt +3 -1
  6. data/vendor/libgit2/include/git2/diff.h +19 -0
  7. data/vendor/libgit2/include/git2/errors.h +1 -12
  8. data/vendor/libgit2/include/git2/remote.h +9 -1
  9. data/vendor/libgit2/include/git2/repository.h +1 -1
  10. data/vendor/libgit2/include/git2/sys/config.h +1 -1
  11. data/vendor/libgit2/include/git2/sys/diff.h +4 -4
  12. data/vendor/libgit2/include/git2/sys/filter.h +4 -1
  13. data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
  14. data/vendor/libgit2/include/git2/sys/refdb_backend.h +4 -3
  15. data/vendor/libgit2/include/git2/transport.h +14 -21
  16. data/vendor/libgit2/src/blame_git.c +10 -15
  17. data/vendor/libgit2/src/blob.c +6 -0
  18. data/vendor/libgit2/src/branch.c +1 -12
  19. data/vendor/libgit2/src/cache.c +4 -4
  20. data/vendor/libgit2/src/checkout.c +2 -2
  21. data/vendor/libgit2/src/clone.c +2 -2
  22. data/vendor/libgit2/src/common.h +13 -4
  23. data/vendor/libgit2/src/curl_stream.c +7 -7
  24. data/vendor/libgit2/src/describe.c +1 -1
  25. data/vendor/libgit2/src/diff.c +25 -0
  26. data/vendor/libgit2/src/errors.c +75 -40
  27. data/vendor/libgit2/src/filebuf.c +6 -1
  28. data/vendor/libgit2/src/filebuf.h +2 -0
  29. data/vendor/libgit2/src/filter.c +14 -9
  30. data/vendor/libgit2/src/global.c +25 -9
  31. data/vendor/libgit2/src/global.h +1 -0
  32. data/vendor/libgit2/src/index.c +75 -2
  33. data/vendor/libgit2/src/indexer.c +1 -1
  34. data/vendor/libgit2/src/iterator.c +6 -3
  35. data/vendor/libgit2/src/khash.h +1 -1
  36. data/vendor/libgit2/src/merge.c +3 -3
  37. data/vendor/libgit2/src/openssl_stream.c +5 -2
  38. data/vendor/libgit2/src/pack-objects.c +1 -1
  39. data/vendor/libgit2/src/pack.c +2 -2
  40. data/vendor/libgit2/src/path.c +25 -4
  41. data/vendor/libgit2/src/path.h +6 -1
  42. data/vendor/libgit2/src/push.h +3 -1
  43. data/vendor/libgit2/src/rebase.c +2 -2
  44. data/vendor/libgit2/src/refdb_fs.c +7 -0
  45. data/vendor/libgit2/src/remote.c +18 -9
  46. data/vendor/libgit2/src/revwalk.c +1 -1
  47. data/vendor/libgit2/src/stash.c +1 -1
  48. data/vendor/libgit2/src/stransport_stream.c +1 -1
  49. data/vendor/libgit2/src/submodule.c +12 -1
  50. data/vendor/libgit2/src/sysdir.c +22 -8
  51. data/vendor/libgit2/src/thread-utils.c +2 -0
  52. data/vendor/libgit2/src/transports/git.c +2 -0
  53. data/vendor/libgit2/src/transports/http.c +2 -2
  54. data/vendor/libgit2/src/transports/smart_pkt.c +1 -1
  55. data/vendor/libgit2/src/transports/ssh.c +4 -2
  56. data/vendor/libgit2/src/transports/winhttp.c +1 -1
  57. data/vendor/libgit2/src/util.c +48 -0
  58. data/vendor/libgit2/src/util.h +13 -5
  59. data/vendor/libgit2/src/win32/posix_w32.c +2 -0
  60. data/vendor/libgit2/src/win32/{buffer.c → w32_buffer.c} +1 -2
  61. data/vendor/libgit2/src/win32/{buffer.h → w32_buffer.h} +0 -0
  62. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +343 -0
  63. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +93 -0
  64. data/vendor/libgit2/src/win32/w32_stack.c +192 -0
  65. data/vendor/libgit2/src/win32/w32_stack.h +138 -0
  66. data/vendor/libgit2/src/xdiff/xdiff.h +10 -6
  67. data/vendor/libgit2/src/xdiff/xdiffi.c +46 -4
  68. data/vendor/libgit2/src/xdiff/xdiffi.h +1 -0
  69. data/vendor/libgit2/src/xdiff/xemit.c +43 -6
  70. data/vendor/libgit2/src/xdiff/xemit.h +1 -1
  71. data/vendor/libgit2/src/xdiff/xhistogram.c +1 -1
  72. data/vendor/libgit2/src/xdiff/xmerge.c +2 -2
  73. data/vendor/libgit2/src/xdiff/xpatience.c +1 -1
  74. data/vendor/libgit2/src/xdiff/xprepare.c +10 -11
  75. data/vendor/libgit2/src/xdiff/xutils.c +13 -29
  76. data/vendor/libgit2/src/xdiff/xutils.h +1 -0
  77. 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 {
@@ -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
- return git_buf_sets(out, getenv("HOME"));
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
- const char *env = NULL;
48
+ git_buf env = GIT_BUF_INIT;
49
+ int error;
42
50
 
43
- if ((env = getenv("XDG_CONFIG_HOME")) != NULL)
44
- return git_buf_joinpath(out, env, "git");
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
- git_buf_clear(out);
49
- return 0;
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
 
@@ -8,7 +8,9 @@
8
8
  #include "thread-utils.h"
9
9
 
10
10
  #ifdef _WIN32
11
+ #ifndef WIN32_LEAN_AND_MEAN
11
12
  # define WIN32_LEAN_AND_MEAN
13
+ #endif
12
14
  # include <windows.h>
13
15
  #elif defined(hpux) || defined(__hpux) || defined(_hpux)
14
16
  # include <sys/pstat.h>
@@ -50,6 +50,8 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
50
50
  }
51
51
 
52
52
  repo = delim;
53
+ if (repo[1] == '~')
54
+ ++repo;
53
55
 
54
56
  delim = strchr(url, ':');
55
57
  if (delim == NULL)
@@ -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 (!strcmp("WWW-Authenticate", git_buf_cstr(name))) {
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, "%X\r\n", (unsigned)len);
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 %d", len);
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);
@@ -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
@@ -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__ */
@@ -11,6 +11,8 @@
11
11
  #include "utf-conv.h"
12
12
  #include "repository.h"
13
13
  #include "reparse.h"
14
+ #include "global.h"
15
+ #include "buffer.h"
14
16
  #include <errno.h>
15
17
  #include <io.h>
16
18
  #include <fcntl.h>
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  #include "common.h"
9
- #include "buffer.h"
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