rugged 0.23.3 → 0.24.0b0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/ext/rugged/rugged.c +24 -0
  4. data/ext/rugged/rugged_config.c +65 -0
  5. data/ext/rugged/rugged_remote.c +22 -2
  6. data/ext/rugged/rugged_repo.c +10 -5
  7. data/ext/rugged/rugged_tree.c +4 -1
  8. data/lib/rugged/version.rb +1 -1
  9. data/vendor/libgit2/CMakeLists.txt +47 -2
  10. data/vendor/libgit2/include/git2/config.h +18 -0
  11. data/vendor/libgit2/include/git2/diff.h +25 -2
  12. data/vendor/libgit2/include/git2/errors.h +0 -12
  13. data/vendor/libgit2/include/git2/index.h +11 -0
  14. data/vendor/libgit2/include/git2/remote.h +12 -1
  15. data/vendor/libgit2/include/git2/sys/config.h +14 -0
  16. data/vendor/libgit2/include/git2/sys/filter.h +4 -1
  17. data/vendor/libgit2/include/git2/sys/odb_backend.h +4 -0
  18. data/vendor/libgit2/include/git2/sys/refdb_backend.h +5 -4
  19. data/vendor/libgit2/include/git2/sys/transport.h +27 -0
  20. data/vendor/libgit2/include/git2/transport.h +25 -21
  21. data/vendor/libgit2/include/git2/version.h +2 -2
  22. data/vendor/libgit2/libgit2.pc.in +3 -2
  23. data/vendor/libgit2/src/branch.c +1 -12
  24. data/vendor/libgit2/src/checkout.c +29 -20
  25. data/vendor/libgit2/src/clone.c +2 -2
  26. data/vendor/libgit2/src/common.h +13 -4
  27. data/vendor/libgit2/src/config.c +36 -0
  28. data/vendor/libgit2/src/config.h +15 -0
  29. data/vendor/libgit2/src/config_file.c +124 -20
  30. data/vendor/libgit2/src/config_file.h +10 -0
  31. data/vendor/libgit2/src/curl_stream.c +7 -7
  32. data/vendor/libgit2/src/diff.c +89 -27
  33. data/vendor/libgit2/src/diff_print.c +1 -1
  34. data/vendor/libgit2/src/errors.c +75 -40
  35. data/vendor/libgit2/src/filebuf.c +81 -3
  36. data/vendor/libgit2/src/fileops.c +176 -75
  37. data/vendor/libgit2/src/fileops.h +7 -10
  38. data/vendor/libgit2/src/filter.c +5 -2
  39. data/vendor/libgit2/src/global.c +25 -9
  40. data/vendor/libgit2/src/global.h +1 -0
  41. data/vendor/libgit2/src/idxmap.h +92 -0
  42. data/vendor/libgit2/src/ignore.c +9 -7
  43. data/vendor/libgit2/src/index.c +246 -46
  44. data/vendor/libgit2/src/index.h +2 -0
  45. data/vendor/libgit2/src/iterator.c +377 -118
  46. data/vendor/libgit2/src/iterator.h +28 -20
  47. data/vendor/libgit2/src/merge.c +26 -13
  48. data/vendor/libgit2/src/notes.c +1 -1
  49. data/vendor/libgit2/src/odb.c +1 -2
  50. data/vendor/libgit2/src/odb_loose.c +2 -2
  51. data/vendor/libgit2/src/odb_mempack.c +6 -2
  52. data/vendor/libgit2/src/oidmap.h +2 -0
  53. data/vendor/libgit2/src/openssl_stream.c +9 -3
  54. data/vendor/libgit2/src/path.c +37 -2
  55. data/vendor/libgit2/src/path.h +12 -1
  56. data/vendor/libgit2/src/pathspec.c +12 -12
  57. data/vendor/libgit2/src/push.c +2 -1
  58. data/vendor/libgit2/src/push.h +1 -0
  59. data/vendor/libgit2/src/refdb.c +2 -6
  60. data/vendor/libgit2/src/refdb_fs.c +13 -3
  61. data/vendor/libgit2/src/remote.c +44 -15
  62. data/vendor/libgit2/src/repository.c +28 -12
  63. data/vendor/libgit2/src/stash.c +17 -12
  64. data/vendor/libgit2/src/stransport_stream.c +1 -1
  65. data/vendor/libgit2/src/submodule.c +234 -152
  66. data/vendor/libgit2/src/sysdir.c +22 -8
  67. data/vendor/libgit2/src/transaction.c +41 -0
  68. data/vendor/libgit2/src/transaction.h +14 -0
  69. data/vendor/libgit2/src/transports/cred.c +8 -0
  70. data/vendor/libgit2/src/transports/http.c +6 -0
  71. data/vendor/libgit2/src/transports/smart.c +95 -0
  72. data/vendor/libgit2/src/transports/smart.h +1 -0
  73. data/vendor/libgit2/src/transports/smart_pkt.c +9 -2
  74. data/vendor/libgit2/src/transports/ssh.c +5 -3
  75. data/vendor/libgit2/src/transports/winhttp.c +19 -1
  76. data/vendor/libgit2/src/unix/posix.h +14 -1
  77. data/vendor/libgit2/src/util.c +56 -13
  78. data/vendor/libgit2/src/util.h +13 -5
  79. data/vendor/libgit2/src/win32/path_w32.c +15 -8
  80. data/vendor/libgit2/src/win32/posix_w32.c +11 -2
  81. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +343 -0
  82. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +93 -0
  83. data/vendor/libgit2/src/win32/w32_stack.c +192 -0
  84. data/vendor/libgit2/src/win32/w32_stack.h +138 -0
  85. data/vendor/libgit2/src/win32/w32_util.c +29 -5
  86. data/vendor/libgit2/src/win32/w32_util.h +13 -3
  87. metadata +11 -5
@@ -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__ */
@@ -198,13 +198,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
198
198
  /* See if this is an absolute path (beginning with a drive letter) */
199
199
  if (path__is_absolute(src)) {
200
200
  if (git__utf8_to_16(dest, MAX_PATH, src) < 0)
201
- return -1;
201
+ goto on_error;
202
202
  }
203
203
  /* File-prefixed NT-style paths beginning with \\?\ */
204
204
  else if (path__is_nt_namespace(src)) {
205
205
  /* Skip the NT prefix, the destination already contains it */
206
206
  if (git__utf8_to_16(dest, MAX_PATH, src + PATH__NT_NAMESPACE_LEN) < 0)
207
- return -1;
207
+ goto on_error;
208
208
  }
209
209
  /* UNC paths */
210
210
  else if (path__is_unc(src)) {
@@ -213,36 +213,43 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
213
213
 
214
214
  /* Skip the leading "\\" */
215
215
  if (git__utf8_to_16(dest, MAX_PATH - 2, src + 2) < 0)
216
- return -1;
216
+ goto on_error;
217
217
  }
218
218
  /* Absolute paths omitting the drive letter */
219
219
  else if (src[0] == '\\' || src[0] == '/') {
220
220
  if (path__cwd(dest, MAX_PATH) < 0)
221
- return -1;
221
+ goto on_error;
222
222
 
223
223
  if (!path__is_absolute(dest)) {
224
224
  errno = ENOENT;
225
- return -1;
225
+ goto on_error;
226
226
  }
227
227
 
228
228
  /* Skip the drive letter specification ("C:") */
229
229
  if (git__utf8_to_16(dest + 2, MAX_PATH - 2, src) < 0)
230
- return -1;
230
+ goto on_error;
231
231
  }
232
232
  /* Relative paths */
233
233
  else {
234
234
  int cwd_len;
235
235
 
236
236
  if ((cwd_len = git_win32_path__cwd(dest, MAX_PATH)) < 0)
237
- return -1;
237
+ goto on_error;
238
238
 
239
239
  dest[cwd_len++] = L'\\';
240
240
 
241
241
  if (git__utf8_to_16(dest + cwd_len, MAX_PATH - cwd_len, src) < 0)
242
- return -1;
242
+ goto on_error;
243
243
  }
244
244
 
245
245
  return git_win32_path_canonicalize(out);
246
+
247
+ on_error:
248
+ /* set windows error code so we can use its error message */
249
+ if (errno == ENAMETOOLONG)
250
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
251
+
252
+ return -1;
246
253
  }
247
254
 
248
255
  int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src)
@@ -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>
@@ -146,12 +148,19 @@ static int lstat_w(
146
148
  return git_win32__file_attribute_to_stat(buf, &fdata, path);
147
149
  }
148
150
 
149
- errno = ENOENT;
151
+ switch (GetLastError()) {
152
+ case ERROR_ACCESS_DENIED:
153
+ errno = EACCES;
154
+ break;
155
+ default:
156
+ errno = ENOENT;
157
+ break;
158
+ }
150
159
 
151
160
  /* To match POSIX behavior, set ENOTDIR when any of the folders in the
152
161
  * file path is a regular file, otherwise set ENOENT.
153
162
  */
154
- if (posix_enotdir) {
163
+ if (errno == ENOENT && posix_enotdir) {
155
164
  size_t path_len = wcslen(path);
156
165
 
157
166
  /* scan up path until we find an existing item */
@@ -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