zookeeper 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/common.h ADDED
@@ -0,0 +1,7 @@
1
+ #ifndef ZKRB_COMMON_H
2
+ #define ZKRB_COMMON_H
3
+
4
+ //#define THREADED
5
+ #undef THREADED // we are linking against the zookeeper_st lib, this is crucial
6
+
7
+ #endif /* ZKRB_COMMON_H */
data/ext/depend CHANGED
@@ -1,5 +1,5 @@
1
- zookeeper_lib.c: zookeeper_lib.h
1
+ event_lib.c: event_lib.h common.h
2
2
  zkrb_wrapper_compat.c: zkrb_wrapper_compat.h
3
3
  zkrb_wrapper.c: zkrb_wrapper_compat.c zkrb_wrapper.h
4
- zookeeper_c.c: zookeeper_lib.c zookeeper_lib.h zkrb_wrapper.c zkrb_wrapper.h dbg.h
4
+ zkrb.c: event_lib.c event_lib.h zkrb_wrapper.c zkrb_wrapper.h dbg.h common.h
5
5
 
@@ -7,20 +7,21 @@ This file contains three sets of helpers:
7
7
 
8
8
  wickman@twitter.com
9
9
 
10
- *********************************************************************************
11
- *
12
- * NOTE: be *very careful* in these functions, calling *ANY* ruby interpreter
13
- * function when you're not in an interpreter thread can hork ruby, trigger a
14
- * [BUG], corrupt the stack, kill your dog, knock up your daughter, etc. etc.
15
- *
16
- *********************************************************************************
10
+
11
+ NOTE: be *very careful* in these functions, calling *ANY* ruby interpreter
12
+ function when you're not in an interpreter thread can hork ruby, trigger a
13
+ [BUG], corrupt the stack, kill your dog, knock up your daughter, etc. etc.
14
+
15
+ NOTE: the above is only true when you're running in THREADED mode, in
16
+ single-threaded, everything is called on an interpreter thread.
17
+
17
18
 
18
19
  slyphon@gmail.com
19
20
 
20
21
  */
21
22
 
22
23
  #include "ruby.h"
23
- #include "zookeeper_lib.h"
24
+ #include "event_lib.h"
24
25
  #include "c-client-src/zookeeper.h"
25
26
  #include <errno.h>
26
27
  #include <stdio.h>
@@ -28,13 +29,15 @@ slyphon@gmail.com
28
29
  #include <pthread.h>
29
30
  #include <unistd.h>
30
31
  #include <inttypes.h>
32
+ #include "common.h"
31
33
  #include "dbg.h"
32
34
 
33
35
  #define GET_SYM(str) ID2SYM(rb_intern(str))
34
36
 
35
37
  int ZKRBDebugging;
36
38
 
37
- // XXX(slyphon): need to check these for error, but what to do if they fail?
39
+ #ifdef THREADED
40
+
38
41
  pthread_mutex_t zkrb_q_mutex = PTHREAD_MUTEX_INITIALIZER;
39
42
 
40
43
  inline static int global_mutex_lock() {
@@ -66,6 +69,42 @@ void atfork_child() {
66
69
  // and children
67
70
  /*pthread_atfork(atfork_prepare, atfork_parent, atfork_child);*/
68
71
 
72
+ // delegates to the system malloc (we can't use xmalloc in the threaded case,
73
+ // as we can't touch the interpreter)
74
+
75
+ inline static void* zk_malloc(size_t size) {
76
+ return malloc(size);
77
+ }
78
+
79
+ inline static void zk_free(void *ptr) {
80
+ free(ptr);
81
+ }
82
+
83
+ #else
84
+
85
+ inline static int global_mutex_lock() {
86
+ return 0;
87
+ }
88
+
89
+ inline static int global_mutex_unlock() {
90
+ return 0;
91
+ }
92
+
93
+ // we can use the ruby xmalloc/xfree that will raise errors
94
+ // in the case of a failure to allocate memory, and can cycle
95
+ // the garbage collector in some cases.
96
+
97
+ inline static void* zk_malloc(size_t size) {
98
+ return xmalloc(size);
99
+ }
100
+
101
+ inline static void zk_free(void *ptr) {
102
+ xfree(ptr);
103
+ }
104
+
105
+
106
+ #endif /* THREADED */
107
+
69
108
 
70
109
  void zkrb_enqueue(zkrb_queue_t *q, zkrb_event_t *elt) {
71
110
  if (q == NULL) {
@@ -81,7 +120,7 @@ void zkrb_enqueue(zkrb_queue_t *q, zkrb_event_t *elt) {
81
120
  global_mutex_lock();
82
121
 
83
122
  q->tail->event = elt;
84
- q->tail->next = (zkrb_event_ll_t *) malloc(sizeof(zkrb_event_ll_t));
123
+ q->tail->next = (zkrb_event_ll_t *)zk_malloc(sizeof(zkrb_event_ll_t));
85
124
  q->tail = q->tail->next;
86
125
  q->tail->event = NULL;
87
126
  q->tail->next = NULL;
@@ -134,7 +173,7 @@ zkrb_event_t* zkrb_dequeue(zkrb_queue_t *q, int need_lock) {
134
173
  if (need_lock)
135
174
  global_mutex_unlock();
136
175
 
137
- free(old_root);
176
+ zk_free(old_root);
138
177
  return rv;
139
178
  }
140
179
 
@@ -150,7 +189,7 @@ void zkrb_signal(zkrb_queue_t *q) {
150
189
  }
151
190
 
152
191
  zkrb_event_ll_t *zkrb_event_ll_t_alloc(void) {
153
- zkrb_event_ll_t *rv = malloc(sizeof(zkrb_event_ll_t));
192
+ zkrb_event_ll_t *rv = zk_malloc(sizeof(zkrb_event_ll_t));
154
193
 
155
194
  if (!rv) return NULL;
156
195
 
@@ -166,7 +205,7 @@ zkrb_queue_t *zkrb_queue_alloc(void) {
166
205
 
167
206
  check(pipe(pfd) == 0, "creating the signal pipe failed");
168
207
 
169
- rq = malloc(sizeof(zkrb_queue_t));
208
+ rq = zk_malloc(sizeof(zkrb_queue_t));
170
209
  check_mem(rq);
171
210
 
172
211
  rq->orig_pid = getpid();
@@ -181,7 +220,7 @@ zkrb_queue_t *zkrb_queue_alloc(void) {
181
220
  return rq;
182
221
 
183
222
  error:
184
- free(rq);
223
+ zk_free(rq);
185
224
  return NULL;
186
225
  }
187
226
 
@@ -193,15 +232,15 @@ void zkrb_queue_free(zkrb_queue_t *queue) {
193
232
  zkrb_event_free(elt);
194
233
  }
195
234
 
196
- free(queue->head);
235
+ zk_free(queue->head);
197
236
  close(queue->pipe_read);
198
237
  close(queue->pipe_write);
199
238
 
200
- free(queue);
239
+ zk_free(queue);
201
240
  }
202
241
 
203
242
  zkrb_event_t *zkrb_event_alloc(void) {
204
- zkrb_event_t *rv = malloc(sizeof(zkrb_event_t));
243
+ zkrb_event_t *rv = zk_malloc(sizeof(zkrb_event_t));
205
244
  return rv;
206
245
  }
207
246
 
@@ -209,58 +248,58 @@ void zkrb_event_free(zkrb_event_t *event) {
209
248
  switch (event->type) {
210
249
  case ZKRB_DATA: {
211
250
  struct zkrb_data_completion *data_ctx = event->completion.data_completion;
212
- free(data_ctx->data);
213
- free(data_ctx->stat);
214
- free(data_ctx);
251
+ zk_free(data_ctx->data);
252
+ zk_free(data_ctx->stat);
253
+ zk_free(data_ctx);
215
254
  break;
216
255
  }
217
256
  case ZKRB_STAT: {
218
257
  struct zkrb_stat_completion *stat_ctx = event->completion.stat_completion;
219
- free(stat_ctx->stat);
220
- free(stat_ctx);
258
+ zk_free(stat_ctx->stat);
259
+ zk_free(stat_ctx);
221
260
  break;
222
261
  }
223
262
  case ZKRB_STRING: {
224
263
  struct zkrb_string_completion *string_ctx = event->completion.string_completion;
225
- free(string_ctx->value);
226
- free(string_ctx);
264
+ zk_free(string_ctx->value);
265
+ zk_free(string_ctx);
227
266
  break;
228
267
  }
229
268
  case ZKRB_STRINGS: {
230
269
  struct zkrb_strings_completion *strings_ctx = event->completion.strings_completion;
231
270
  int k;
232
271
  if (strings_ctx->values)
233
- for (k = 0; k < strings_ctx->values->count; ++k) free(strings_ctx->values->data[k]);
234
- free(strings_ctx->values);
235
- free(strings_ctx);
272
+ for (k = 0; k < strings_ctx->values->count; ++k) zk_free(strings_ctx->values->data[k]);
273
+ zk_free(strings_ctx->values);
274
+ zk_free(strings_ctx);
236
275
  break;
237
276
  }
238
277
  case ZKRB_STRINGS_STAT: {
239
278
  struct zkrb_strings_stat_completion *strings_stat_ctx = event->completion.strings_stat_completion;
240
279
  int k;
241
280
  if (strings_stat_ctx->values)
242
- for (k = 0; k < strings_stat_ctx->values->count; ++k) free(strings_stat_ctx->values->data[k]);
243
- free(strings_stat_ctx->values);
281
+ for (k = 0; k < strings_stat_ctx->values->count; ++k) zk_free(strings_stat_ctx->values->data[k]);
282
+ zk_free(strings_stat_ctx->values);
244
283
 
245
284
  if (strings_stat_ctx->stat)
246
- free(strings_stat_ctx->stat);
247
- free(strings_stat_ctx);
285
+ zk_free(strings_stat_ctx->stat);
286
+ zk_free(strings_stat_ctx);
248
287
  break;
249
288
  }
250
289
  case ZKRB_ACL: {
251
290
  struct zkrb_acl_completion *acl_ctx = event->completion.acl_completion;
252
291
  if (acl_ctx->acl) {
253
292
  deallocate_ACL_vector(acl_ctx->acl);
254
- free(acl_ctx->acl);
293
+ zk_free(acl_ctx->acl);
255
294
  }
256
- free(acl_ctx->stat);
257
- free(acl_ctx);
295
+ zk_free(acl_ctx->stat);
296
+ zk_free(acl_ctx);
258
297
  break;
259
298
  }
260
299
  case ZKRB_WATCHER: {
261
300
  struct zkrb_watcher_completion *watcher_ctx = event->completion.watcher_completion;
262
- free(watcher_ctx->path);
263
- free(watcher_ctx);
301
+ zk_free(watcher_ctx->path);
302
+ zk_free(watcher_ctx);
264
303
  break;
265
304
  }
266
305
  case ZKRB_VOID: {
@@ -270,7 +309,7 @@ void zkrb_event_free(zkrb_event_t *event) {
270
309
  log_err("unrecognized event in event_free!");
271
310
  }
272
311
 
273
- free(event);
312
+ zk_free(event);
274
313
  }
275
314
 
276
315
  /* this is called only from a method_get_latest_event, so the hash is
@@ -289,6 +328,7 @@ VALUE zkrb_event_to_ruby(zkrb_event_t *event) {
289
328
 
290
329
  switch (event->type) {
291
330
  case ZKRB_DATA: {
331
+ zkrb_debug("zkrb_event_to_ruby ZKRB_DATA\n");
292
332
  struct zkrb_data_completion *data_ctx = event->completion.data_completion;
293
333
  if (ZKRBDebugging) zkrb_print_stat(data_ctx->stat);
294
334
  rb_hash_aset(hash, GET_SYM("data"), data_ctx->data ? rb_str_new(data_ctx->data, data_ctx->data_len) : Qnil);
@@ -329,7 +369,6 @@ VALUE zkrb_event_to_ruby(zkrb_event_t *event) {
329
369
  }
330
370
  case ZKRB_WATCHER: {
331
371
  zkrb_debug("zkrb_event_to_ruby ZKRB_WATCHER\n");
332
- struct zkrb_acl_completion *acl_ctx = event->completion.acl_completion;
333
372
  struct zkrb_watcher_completion *watcher_ctx = event->completion.watcher_completion;
334
373
  rb_hash_aset(hash, GET_SYM("type"), INT2FIX(watcher_ctx->type));
335
374
  rb_hash_aset(hash, GET_SYM("state"), INT2FIX(watcher_ctx->state));
@@ -365,7 +404,7 @@ void zkrb_print_stat(const struct Stat *s) {
365
404
  }
366
405
 
367
406
  zkrb_calling_context *zkrb_calling_context_alloc(int64_t req_id, zkrb_queue_t *queue) {
368
- zkrb_calling_context *ctx = malloc(sizeof(zkrb_calling_context));
407
+ zkrb_calling_context *ctx = zk_malloc(sizeof(zkrb_calling_context));
369
408
  if (!ctx) return NULL;
370
409
 
371
410
  ctx->req_id = req_id;
@@ -374,6 +413,10 @@ zkrb_calling_context *zkrb_calling_context_alloc(int64_t req_id, zkrb_queue_t *q
374
413
  return ctx;
375
414
  }
376
415
 
416
+ void zkrb_calling_context_free(zkrb_calling_context *ctx) {
417
+ zk_free(ctx);
418
+ }
419
+
377
420
  void zkrb_print_calling_context(zkrb_calling_context *ctx) {
378
421
  fprintf(stderr, "calling context (%p){\n", ctx);
379
422
  fprintf(stderr, "\treq_id = %"PRId64"\n", ctx->req_id);
@@ -394,7 +437,7 @@ void zkrb_print_calling_context(zkrb_calling_context *ctx) {
394
437
  zkrb_event_t *eptr = zkrb_event_alloc(); \
395
438
  eptr->req_id = ctx->req_id; \
396
439
  zkrb_queue_t *qptr = ctx->queue; \
397
- if (eptr->req_id != ZKRB_GLOBAL_REQ) free(ctx)
440
+ if (eptr->req_id != ZKRB_GLOBAL_REQ) zk_free(ctx)
398
441
 
399
442
  void zkrb_state_callback(
400
443
  zhandle_t *zh, int type, int state, const char *path, void *calling_ctx) {
@@ -404,7 +447,7 @@ void zkrb_state_callback(
404
447
  type, state, (void *) path, path ? path : "NULL");
405
448
 
406
449
  /* save callback context */
407
- struct zkrb_watcher_completion *wc = malloc(sizeof(struct zkrb_watcher_completion));
450
+ struct zkrb_watcher_completion *wc = zk_malloc(sizeof(struct zkrb_watcher_completion));
408
451
  wc->type = type;
409
452
  wc->state = state;
410
453
  wc->path = strdup(path);
@@ -416,7 +459,7 @@ void zkrb_state_callback(
416
459
  event->req_id = ctx->req_id;
417
460
  zkrb_queue_t *queue = ctx->queue;
418
461
  if (type != ZOO_SESSION_EVENT) {
419
- free(ctx);
462
+ zk_free(ctx);
420
463
  ctx = NULL;
421
464
  }
422
465
 
@@ -426,8 +469,6 @@ void zkrb_state_callback(
426
469
  zkrb_enqueue(queue, event);
427
470
  }
428
471
 
429
-
430
-
431
472
  void zkrb_data_callback(
432
473
  int rc, const char *value, int value_len, const struct Stat *stat, const void *calling_ctx) {
433
474
 
@@ -436,18 +477,18 @@ void zkrb_data_callback(
436
477
  rc, zerror(rc), value ? value : "NULL", value_len);
437
478
 
438
479
  /* copy data completion */
439
- struct zkrb_data_completion *dc = malloc(sizeof(struct zkrb_data_completion));
480
+ struct zkrb_data_completion *dc = zk_malloc(sizeof(struct zkrb_data_completion));
440
481
  dc->data = NULL;
441
482
  dc->stat = NULL;
442
483
  dc->data_len = 0;
443
484
 
444
485
  if (value != NULL) {
445
- dc->data = malloc(value_len);
486
+ dc->data = zk_malloc(value_len); // xmalloc may raise an exception, which means the above completion will leak
446
487
  dc->data_len = value_len;
447
488
  memcpy(dc->data, value, value_len);
448
489
  }
449
490
 
450
- if (stat != NULL) { dc->stat = malloc(sizeof(struct Stat)); memcpy(dc->stat, stat, sizeof(struct Stat)); }
491
+ if (stat != NULL) { dc->stat = zk_malloc(sizeof(struct Stat)); memcpy(dc->stat, stat, sizeof(struct Stat)); }
451
492
 
452
493
  ZKH_SETUP_EVENT(queue, event);
453
494
  event->rc = rc;
@@ -462,9 +503,9 @@ void zkrb_stat_callback(
462
503
  zkrb_debug("ZOOKEEPER_C_STAT WATCHER "
463
504
  "rc = %d (%s)\n", rc, zerror(rc));
464
505
 
465
- struct zkrb_stat_completion *sc = malloc(sizeof(struct zkrb_stat_completion));
506
+ struct zkrb_stat_completion *sc = zk_malloc(sizeof(struct zkrb_stat_completion));
466
507
  sc->stat = NULL;
467
- if (stat != NULL) { sc->stat = malloc(sizeof(struct Stat)); memcpy(sc->stat, stat, sizeof(struct Stat)); }
508
+ if (stat != NULL) { sc->stat = zk_malloc(sizeof(struct Stat)); memcpy(sc->stat, stat, sizeof(struct Stat)); }
468
509
 
469
510
  ZKH_SETUP_EVENT(queue, event);
470
511
  event->rc = rc;
@@ -480,7 +521,7 @@ void zkrb_string_callback(
480
521
  zkrb_debug("ZOOKEEPER_C_STRING WATCHER "
481
522
  "rc = %d (%s)\n", rc, zerror(rc));
482
523
 
483
- struct zkrb_string_completion *sc = malloc(sizeof(struct zkrb_string_completion));
524
+ struct zkrb_string_completion *sc = zk_malloc(sizeof(struct zkrb_string_completion));
484
525
  sc->value = NULL;
485
526
  if (string)
486
527
  sc->value = strdup(string);
@@ -499,7 +540,7 @@ void zkrb_strings_callback(
499
540
  "rc = %d (%s), calling_ctx = %p\n", rc, zerror(rc), calling_ctx);
500
541
 
501
542
  /* copy string vector */
502
- struct zkrb_strings_completion *sc = malloc(sizeof(struct zkrb_strings_completion));
543
+ struct zkrb_strings_completion *sc = zk_malloc(sizeof(struct zkrb_strings_completion));
503
544
  sc->values = (strings != NULL) ? zkrb_clone_string_vector(strings) : NULL;
504
545
 
505
546
  ZKH_SETUP_EVENT(queue, event);
@@ -515,9 +556,9 @@ void zkrb_strings_stat_callback(
515
556
  zkrb_debug("ZOOKEEPER_C_STRINGS_STAT WATCHER "
516
557
  "rc = %d (%s), calling_ctx = %p\n", rc, zerror(rc), calling_ctx);
517
558
 
518
- struct zkrb_strings_stat_completion *sc = malloc(sizeof(struct zkrb_strings_stat_completion));
559
+ struct zkrb_strings_stat_completion *sc = zk_malloc(sizeof(struct zkrb_strings_stat_completion));
519
560
  sc->stat = NULL;
520
- if (stat != NULL) { sc->stat = malloc(sizeof(struct Stat)); memcpy(sc->stat, stat, sizeof(struct Stat)); }
561
+ if (stat != NULL) { sc->stat = zk_malloc(sizeof(struct Stat)); memcpy(sc->stat, stat, sizeof(struct Stat)); }
521
562
 
522
563
  sc->values = (strings != NULL) ? zkrb_clone_string_vector(strings) : NULL;
523
564
 
@@ -545,11 +586,11 @@ void zkrb_acl_callback(
545
586
  int rc, struct ACL_vector *acls, struct Stat *stat, const void *calling_ctx) {
546
587
  zkrb_debug("ZOOKEEPER_C_ACL WATCHER rc = %d (%s)\n", rc, zerror(rc));
547
588
 
548
- struct zkrb_acl_completion *ac = malloc(sizeof(struct zkrb_acl_completion));
589
+ struct zkrb_acl_completion *ac = zk_malloc(sizeof(struct zkrb_acl_completion));
549
590
  ac->acl = NULL;
550
591
  ac->stat = NULL;
551
592
  if (acls != NULL) { ac->acl = zkrb_clone_acl_vector(acls); }
552
- if (stat != NULL) { ac->stat = malloc(sizeof(struct Stat)); memcpy(ac->stat, stat, sizeof(struct Stat)); }
593
+ if (stat != NULL) { ac->stat = zk_malloc(sizeof(struct Stat)); memcpy(ac->stat, stat, sizeof(struct Stat)); }
553
594
 
554
595
  ZKH_SETUP_EVENT(queue, event);
555
596
  event->rc = rc;
@@ -574,12 +615,12 @@ VALUE zkrb_acl_to_ruby(struct ACL *acl) {
574
615
  return hash;
575
616
  }
576
617
 
577
- #warning [wickman] TODO test zkrb_ruby_to_aclvector
578
- #warning [slyphon] TODO size checking on acl_ary (cast to int)
618
+ // [wickman] TODO test zkrb_ruby_to_aclvector
619
+ // [slyphon] TODO size checking on acl_ary (cast to int)
579
620
  struct ACL_vector * zkrb_ruby_to_aclvector(VALUE acl_ary) {
580
621
  Check_Type(acl_ary, T_ARRAY);
581
622
 
582
- struct ACL_vector *v = malloc(sizeof(struct ACL_vector));
623
+ struct ACL_vector *v = zk_malloc(sizeof(struct ACL_vector));
583
624
  allocate_ACL_vector(v, (int)RARRAY_LEN(acl_ary));
584
625
 
585
626
  int k;
@@ -591,7 +632,7 @@ struct ACL_vector * zkrb_ruby_to_aclvector(VALUE acl_ary) {
591
632
  return v;
592
633
  }
593
634
 
594
- #warning [wickman] TODO test zkrb_ruby_to_aclvector
635
+ // [wickman] TODO test zkrb_ruby_to_aclvector
595
636
  struct ACL zkrb_ruby_to_acl(VALUE rubyacl) {
596
637
  struct ACL acl;
597
638
 
@@ -603,7 +644,7 @@ struct ACL zkrb_ruby_to_acl(VALUE rubyacl) {
603
644
  return acl;
604
645
  }
605
646
 
606
- #warning [wickman] TODO zkrb_ruby_to_id error checking? test
647
+ // [wickman] TODO zkrb_ruby_to_id error checking? test
607
648
  struct Id zkrb_ruby_to_id(VALUE rubyid) {
608
649
  struct Id id;
609
650
 
@@ -611,7 +652,7 @@ struct Id zkrb_ruby_to_id(VALUE rubyid) {
611
652
  VALUE ident = rb_iv_get(rubyid, "@id");
612
653
 
613
654
  if (scheme != Qnil) {
614
- id.scheme = malloc(RSTRING_LEN(scheme) + 1);
655
+ id.scheme = zk_malloc(RSTRING_LEN(scheme) + 1);
615
656
  strncpy(id.scheme, RSTRING_PTR(scheme), RSTRING_LEN(scheme));
616
657
  id.scheme[RSTRING_LEN(scheme)] = '\0';
617
658
  } else {
@@ -619,7 +660,7 @@ struct Id zkrb_ruby_to_id(VALUE rubyid) {
619
660
  }
620
661
 
621
662
  if (ident != Qnil) {
622
- id.id = malloc(RSTRING_LEN(ident) + 1);
663
+ id.id = zk_malloc(RSTRING_LEN(ident) + 1);
623
664
  strncpy(id.id, RSTRING_PTR(ident), RSTRING_LEN(ident));
624
665
  id.id[RSTRING_LEN(ident)] = '\0';
625
666
  } else {
@@ -678,9 +719,9 @@ VALUE zkrb_stat_to_rhash(const struct Stat *stat) {
678
719
  return ary;
679
720
  }
680
721
 
681
- #warning [wickman] TODO test zkrb_clone_acl_vector
722
+ // [wickman] TODO test zkrb_clone_acl_vector
682
723
  struct ACL_vector * zkrb_clone_acl_vector(struct ACL_vector * src) {
683
- struct ACL_vector * dst = malloc(sizeof(struct ACL_vector));
724
+ struct ACL_vector * dst = zk_malloc(sizeof(struct ACL_vector));
684
725
  allocate_ACL_vector(dst, src->count);
685
726
  int k;
686
727
  for (k = 0; k < src->count; ++k) {
@@ -692,9 +733,9 @@ struct ACL_vector * zkrb_clone_acl_vector(struct ACL_vector * src) {
692
733
  return dst;
693
734
  }
694
735
 
695
- #warning [wickman] TODO test zkrb_clone_string_vector
736
+ // [wickman] TODO test zkrb_clone_string_vector
696
737
  struct String_vector * zkrb_clone_string_vector(const struct String_vector * src) {
697
- struct String_vector * dst = malloc(sizeof(struct String_vector));
738
+ struct String_vector * dst = zk_malloc(sizeof(struct String_vector));
698
739
  allocate_String_vector(dst, src->count);
699
740
  int k;
700
741
  for (k = 0; k < src->count; ++k) {