* and will send small couples of slices to calc_changes, keeping the running
* time near-linear. This is explained in more detail in the gen_ed_diff
* comments.
+ *
+ * The allocation strategy tries to save time and memory by avoiding needless
+ * copies. Instead of actually splitting the inputs into separate strings, we
+ * allocate cdline_t objects, each of which represents a line in the original
+ * object or in the output. We use memarea_t allocators to manage the
+ * temporary memory we use when generating or applying diffs.
**/
#define CONSDIFF_PRIVATE
#include "or.h"
#include "consdiff.h"
+#include "memarea.h"
#include "routerparse.h"
static const char* ns_diff_version = "network-status-diff-version 1";
static char *consensus_join_lines(const smartlist_t *inp);
+/** Return true iff a and b have the same contents. */
+STATIC int
+lines_eq(const cdline_t *a, const cdline_t *b)
+{
+ return a->len == b->len && fast_memeq(a->s, b->s, a->len);
+}
+
+/** Return true iff a has the same contents as the nul-terminated string b. */
+STATIC int
+line_str_eq(const cdline_t *a, const char *b)
+{
+ const size_t len = strlen(b);
+ tor_assert(len <= UINT32_MAX);
+ cdline_t bline = { b, (uint32_t)len };
+ return lines_eq(a, &bline);
+}
+
+/** Add a cdline_t to <b>lst</b> holding as its contents the nul-terminated
+ * string s. Use the provided memory area for storage. */
+STATIC void
+smartlist_add_linecpy(smartlist_t *lst, memarea_t *area, const char *s)
+{
+ size_t len = strlen(s);
+ const char *ss = memarea_memdup(area, s, len);
+ cdline_t *line = memarea_alloc(area, sizeof(cdline_t));
+ line->s = ss;
+ line->len = (uint32_t)len;
+ smartlist_add(lst, line);
+}
+
/** Compute the digest of <b>cons</b>, and store the result in
* <b>digest_out</b>. Return 0 on success, -1 on failure. */
/* This is a separate, mockable function so that we can override it when
for (int i = 0; i < slice1->len; ++i, si+=direction) {
- const char *line1 = smartlist_get(slice1->list, si);
+ const cdline_t *line1 = smartlist_get(slice1->list, si);
/* Store the last results. */
memcpy(prev, result, a_size);
for (int j = 0; j < slice2->len; ++j, sj+=direction) {
- const char *line2 = smartlist_get(slice2->list, sj);
- if (!strcmp(line1, line2)) {
+ const cdline_t *line2 = smartlist_get(slice2->list, sj);
+ if (lines_eq(line1, line2)) {
/* If the lines are equal, the lcs is one line longer. */
result[j + 1] = prev[j] + 1;
} else {
trim_slices(smartlist_slice_t *slice1, smartlist_slice_t *slice2)
{
while (slice1->len>0 && slice2->len>0) {
- const char *line1 = smartlist_get(slice1->list, slice1->offset);
- const char *line2 = smartlist_get(slice2->list, slice2->offset);
- if (strcmp(line1, line2)) {
+ const cdline_t *line1 = smartlist_get(slice1->list, slice1->offset);
+ const cdline_t *line2 = smartlist_get(slice2->list, slice2->offset);
+ if (!lines_eq(line1, line2)) {
break;
}
slice1->offset++; slice1->len--;
int i2 = (slice2->offset+slice2->len)-1;
while (slice1->len>0 && slice2->len>0) {
- const char *line1 = smartlist_get(slice1->list, i1);
- const char *line2 = smartlist_get(slice2->list, i2);
- if (strcmp(line1, line2)) {
+ const cdline_t *line1 = smartlist_get(slice1->list, i1);
+ const cdline_t *line2 = smartlist_get(slice2->list, i2);
+ if (!lines_eq(line1, line2)) {
break;
}
i1--;
}
}
-/** Like smartlist_string_pos, but limited to the bounds of the slice.
+/** Like smartlist_string_pos, but uses a cdline_t, and is restricted to the
+ * bounds of the slice.
*/
STATIC int
-smartlist_slice_string_pos(const smartlist_slice_t *slice, const char *string)
+smartlist_slice_string_pos(const smartlist_slice_t *slice,
+ const cdline_t *string)
{
int end = slice->offset + slice->len;
for (int i = slice->offset; i < end; ++i) {
- const char *el = smartlist_get(slice->list, i);
- if (!strcmp(el, string)) {
+ const cdline_t *el = smartlist_get(slice->list, i);
+ if (lines_eq(el, string)) {
return i;
}
}
tor_assert(slice1->len == 0 || slice1->len == 1);
if (slice1->len == 1) {
- const char *line_common = smartlist_get(slice1->list, slice1->offset);
+ const cdline_t *line_common = smartlist_get(slice1->list, slice1->offset);
toskip = smartlist_slice_string_pos(slice2, line_common);
if (toskip == -1) {
bitarray_set(changed1, slice1->offset);
/** Helper: Get the identity hash from a router line, assuming that the line
* at least appears to be a router line and thus starts with "r ".
+ *
+ * If an identity hash is found, store it (without decoding it) in
+ * <b>hash_out</b>, and return 0. On failure, return -1.
*/
-STATIC const char *
-get_id_hash(const char *r_line)
+STATIC int
+get_id_hash(const cdline_t *line, cdline_t *hash_out)
{
- r_line += strlen("r ");
+ if (line->len < 2)
+ return -1;
/* Skip the router name. */
- const char *hash = strchr(r_line, ' ');
+ const char *hash = memchr(line->s + 2, ' ', line->len - 2);
if (!hash) {
- return NULL;
+ return -1;
}
hash++;
/* Stop when the first non-base64 character is found. Use unsigned chars to
* avoid negative indexes causing crashes.
*/
- while (base64_compare_table[*((unsigned char*)hash_end)] != X) {
+ while (base64_compare_table[*((unsigned char*)hash_end)] != X &&
+ hash_end < line->s + line->len) {
hash_end++;
}
/* Empty hash. */
if (hash_end == hash) {
- return NULL;
+ return -1;
}
- return hash;
+ hash_out->s = hash;
+ /* Always true because lines are limited to this length */
+ tor_assert(hash_end - hash <= UINT32_MAX);
+ hash_out->len = (uint32_t)(hash_end - hash);
+
+ return 0;
}
/** Helper: Check that a line is a valid router entry. We must at least be
* able to fetch a proper identity hash from it for it to be valid.
*/
STATIC int
-is_valid_router_entry(const char *line)
+is_valid_router_entry(const cdline_t *line)
{
- if (strcmpstart(line, "r ") != 0) {
+ if (line->len < 2 || fast_memneq(line->s, "r ", 2))
return 0;
- }
- return (get_id_hash(line) != NULL);
+ cdline_t tmp;
+ return (get_id_hash(line, &tmp) == 0);
}
/** Helper: Find the next router line starting at the current position.
return len;
}
- const char *line = smartlist_get(cons, cur);
+ const cdline_t *line = smartlist_get(cons, cur);
while (!is_valid_router_entry(line)) {
if (++cur >= len) {
return len;
return cur;
}
-/** Helper: compare two base64-encoded identity hashes which may be of
+/** Helper: compare two base64-encoded identity hashes, which may be of
* different lengths. Comparison ends when the first non-base64 char is found.
*/
STATIC int
-base64cmp(const char *hash1, const char *hash2)
+base64cmp(const cdline_t *hash1, const cdline_t *hash2)
{
/* NULL is always lower, useful for last_hash which starts at NULL. */
- if (!hash1 && !hash2) {
+ if (!hash1->s && !hash2->s) {
return 0;
}
- if (!hash1) {
+ if (!hash1->s) {
return -1;
}
- if (!hash2) {
+ if (!hash2->s) {
return 1;
}
/* Don't index with a char; char may be signed. */
- const unsigned char *a = (unsigned char*)hash1;
- const unsigned char *b = (unsigned char*)hash2;
+ const unsigned char *a = (unsigned char*)hash1->s;
+ const unsigned char *b = (unsigned char*)hash2->s;
+ const unsigned char *a_end = a + hash1->len;
+ const unsigned char *b_end = b + hash2->len;
while (1) {
uint8_t av = base64_compare_table[*a];
uint8_t bv = base64_compare_table[*b];
} else {
a++;
b++;
+ if (a == a_end) {
+ if (b == b_end) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else if (b == b_end) {
+ return 1;
+ }
}
}
}
* happen if any lines the script had to add matched "." or if the routers
* were not properly ordered.
*
+ * All cdline_t objects in the resulting object are either references to lines
+ * in one of the inputs, or are newly allocated lines in the provided memarea.
+ *
* This implementation is consensus-specific. To generate an ed diff for any
* given input in quadratic time, you can replace all the code until the
* navigation in reverse order with the following:
* calc_changes(cons1_sl, cons2_sl, changed1, changed2);
*/
STATIC smartlist_t *
-gen_ed_diff(const smartlist_t *cons1, const smartlist_t *cons2)
+gen_ed_diff(const smartlist_t *cons1, const smartlist_t *cons2,
+ memarea_t *area)
{
int len1 = smartlist_len(cons1);
int len2 = smartlist_len(cons2);
int i1=-1, i2=-1;
int start1=0, start2=0;
- const char *hash1 = NULL;
- const char *hash2 = NULL;
-
/* To check that hashes are ordered properly */
- const char *last_hash1 = NULL;
- const char *last_hash2 = NULL;
+ cdline_t hash1 = { NULL, 0 }, hash2 = { NULL, 0 };
+ cdline_t last_hash1 = { NULL, 0 }, last_hash2 = { NULL, 0 };
/* i1 and i2 are initialized at the first line of each consensus. They never
* reach past len1 and len2 respectively, since next_router doesn't let that
if (i1 < len1) {
i1 = next_router(cons1, i1);
if (i1 != len1) {
- last_hash1 = hash1;
- hash1 = get_id_hash(smartlist_get(cons1, i1));
- if (base64cmp(hash1, last_hash1) <= 0) {
+ memcpy(&last_hash1, &hash1, sizeof(cdline_t));
+ if (get_id_hash(smartlist_get(cons1, i1), &hash1) < 0 ||
+ base64cmp(&hash1, &last_hash1) <= 0) {
log_warn(LD_CONSDIFF, "Refusing to generate consensus diff because "
"the base consensus doesn't have its router entries "
"sorted properly.");
if (i2 < len2) {
i2 = next_router(cons2, i2);
if (i2 != len2) {
- last_hash2 = hash2;
- hash2 = get_id_hash(smartlist_get(cons2, i2));
- if (base64cmp(hash2, last_hash2) <= 0) {
+ memcpy(&last_hash2, &hash2, sizeof(cdline_t));
+ if (get_id_hash(smartlist_get(cons2, i2), &hash2) < 0 ||
+ base64cmp(&hash2, &last_hash2) <= 0) {
log_warn(LD_CONSDIFF, "Refusing to generate consensus diff because "
"the target consensus doesn't have its router entries "
"sorted properly.");
* consensus has already reached the end, both are extended to their
* respecting ends since we are done.
*/
- int cmp = base64cmp(hash1, hash2);
+ int cmp = base64cmp(&hash1, &hash2);
while (cmp != 0) {
if (i1 < len1 && cmp < 0) {
i1 = next_router(cons1, i1);
i2 = len2;
break;
}
- last_hash1 = hash1;
- hash1 = get_id_hash(smartlist_get(cons1, i1));
- if (base64cmp(hash1, last_hash1) <= 0) {
+ memcpy(&last_hash1, &hash1, sizeof(cdline_t));
+ if (get_id_hash(smartlist_get(cons1, i1), &hash1) < 0 ||
+ base64cmp(&hash1, &last_hash1) <= 0) {
log_warn(LD_CONSDIFF, "Refusing to generate consensus diff "
"because the base consensus doesn't have its router entries "
"sorted properly.");
i1 = len1;
break;
}
- last_hash2 = hash2;
- hash2 = get_id_hash(smartlist_get(cons2, i2));
- if (base64cmp(hash2, last_hash2) <= 0) {
+ memcpy(&last_hash2, &hash2, sizeof(cdline_t));
+ if (get_id_hash(smartlist_get(cons2, i2), &hash2) < 0 ||
+ base64cmp(&hash2, &last_hash2) <= 0) {
log_warn(LD_CONSDIFF, "Refusing to generate consensus diff "
"because the target consensus doesn't have its router entries "
"sorted properly.");
i2 = len2;
break;
}
- cmp = base64cmp(hash1, hash2);
+ cmp = base64cmp(&hash1, &hash2);
}
}
* each chunk of changes.
*/
i1=len1-1, i2=len2-1;
+ char buf[128];
while (i1 > 0 || i2 > 0) {
int start1x, start2x, end1, end2, added, deleted;
if (added == 0) {
if (deleted == 1) {
- smartlist_add_asprintf(result, "%id", start1x+1);
+ tor_snprintf(buf, sizeof(buf), "%id", start1x+1);
+ smartlist_add_linecpy(result, area, buf);
} else {
- smartlist_add_asprintf(result, "%i,%id", start1x+1, start1x+deleted);
+ tor_snprintf(buf, sizeof(buf), "%i,%id", start1x+1, start1x+deleted);
+ smartlist_add_linecpy(result, area, buf);
}
} else {
int i;
if (deleted == 0) {
- smartlist_add_asprintf(result, "%ia", start1x);
+ tor_snprintf(buf, sizeof(buf), "%ia", start1x);
+ smartlist_add_linecpy(result, area, buf);
} else if (deleted == 1) {
- smartlist_add_asprintf(result, "%ic", start1x+1);
+ tor_snprintf(buf, sizeof(buf), "%ic", start1x+1);
+ smartlist_add_linecpy(result, area, buf);
} else {
- smartlist_add_asprintf(result, "%i,%ic", start1x+1, start1x+deleted);
+ tor_snprintf(buf, sizeof(buf), "%i,%ic", start1x+1, start1x+deleted);
+ smartlist_add_linecpy(result, area, buf);
}
for (i = start2x; i <= end2; ++i) {
- const char *line = smartlist_get(cons2, i);
- if (!strcmp(line, ".")) {
+ cdline_t *line = smartlist_get(cons2, i);
+ if (line_str_eq(line, ".")) {
log_warn(LD_CONSDIFF, "Cannot generate consensus diff because "
"one of the lines to be added is \".\".");
goto error_cleanup;
}
- smartlist_add(result, tor_strdup(line));
+ smartlist_add(result, line);
}
- smartlist_add_asprintf(result, ".");
+ smartlist_add_linecpy(result, area, ".");
}
}
bitarray_free(changed1);
bitarray_free(changed2);
- SMARTLIST_FOREACH(result, char*, line, tor_free(line));
smartlist_free(result);
return NULL;
/** Apply the ed diff, starting at <b>diff_starting_line</b>, to the consensus
* and return a new consensus, also as a line-based smartlist. Will return
* NULL if the ed diff is not properly formatted.
+ *
+ * All cdline_t objects in the resulting object are references to lines
+ * in one of the inputs; nothing is copied.
*/
STATIC smartlist_t *
apply_ed_diff(const smartlist_t *cons1, const smartlist_t *diff,
smartlist_t *cons2 = smartlist_new();
for (int i=diff_starting_line; i<diff_len; ++i) {
- const char *diff_line = smartlist_get(diff, i);
+ const cdline_t *diff_cdline = smartlist_get(diff, i);
+ char diff_line[128];
char *endptr1, *endptr2;
+ if (diff_cdline->len > sizeof(diff_line) - 1) {
+ log_warn(LD_CONSDIFF, "Could not apply consensus diff because "
+ "an ed command was far too long");
+ goto error_cleanup;
+ }
+ memcpy(diff_line, diff_cdline->s, diff_cdline->len);
+ diff_line[diff_cdline->len] = 0;
int start = (int)strtol(diff_line, &endptr1, 10);
int end;
if (endptr1 == diff_line) {
/* Add unchanged lines. */
for (; j && j > end; --j) {
- const char *cons_line = smartlist_get(cons1, j-1);
- smartlist_add(cons2, tor_strdup(cons_line));
+ cdline_t *cons_line = smartlist_get(cons1, j-1);
+ smartlist_add(cons2, cons_line);
}
/* Ignore removed lines. */
i++; /* Skip the line with the range and command. */
while (i < diff_len) {
- if (!strcmp(smartlist_get(diff, i), ".")) {
+ if (line_str_eq(smartlist_get(diff, i), ".")) {
break;
}
if (++i == diff_len) {
}
while (added_i > added_end) {
- const char *added_line = smartlist_get(diff, added_i--);
- smartlist_add(cons2, tor_strdup(added_line));
+ cdline_t *added_line = smartlist_get(diff, added_i--);
+ smartlist_add(cons2, added_line);
}
}
}
/* Add remaining unchanged lines. */
for (; j > 0; --j) {
- const char *cons_line = smartlist_get(cons1, j-1);
- smartlist_add(cons2, tor_strdup(cons_line));
+ cdline_t *cons_line = smartlist_get(cons1, j-1);
+ smartlist_add(cons2, cons_line);
}
/* Reverse the whole thing since we did it from the end. */
error_cleanup:
- SMARTLIST_FOREACH(cons2, char*, line, tor_free(line));
smartlist_free(cons2);
return NULL;
* up to the caller to free their resources.
*/
smartlist_t *
-consdiff_gen_diff(const smartlist_t *cons1, const smartlist_t *cons2,
+consdiff_gen_diff(const smartlist_t *cons1,
+ const smartlist_t *cons2,
const consensus_digest_t *digests1,
- const consensus_digest_t *digests2)
+ const consensus_digest_t *digests2,
+ memarea_t *area)
{
- smartlist_t *ed_diff = gen_ed_diff(cons1, cons2);
+ smartlist_t *ed_diff = gen_ed_diff(cons1, cons2, area);
/* ed diff could not be generated - reason already logged by gen_ed_diff. */
if (!ed_diff) {
goto error_cleanup;
/* LCOV_EXCL_STOP */
}
- int cons2_eq = smartlist_strings_eq(cons2, ed_cons2);
- SMARTLIST_FOREACH(ed_cons2, char*, line, tor_free(line));
+ int cons2_eq = 1;
+ if (smartlist_len(cons2) == smartlist_len(ed_cons2)) {
+ SMARTLIST_FOREACH_BEGIN(cons2, const cdline_t *, line1) {
+ const cdline_t *line2 = smartlist_get(ed_cons2, line1_sl_idx);
+ if (! lines_eq(line1, line2) ) {
+ cons2_eq = 0;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(line1);
+ } else {
+ cons2_eq = 0;
+ }
smartlist_free(ed_cons2);
if (!cons2_eq) {
/* LCOV_EXCL_START -- impossible if diff generation is correct. */
(const char*)digests2->sha3_256, DIGEST256_LEN);
/* Create the resulting consensus diff. */
+ char buf[160];
smartlist_t *result = smartlist_new();
- smartlist_add_asprintf(result, "%s", ns_diff_version);
- smartlist_add_asprintf(result, "%s %s %s", hash_token,
+ tor_snprintf(buf, sizeof(buf), "%s", ns_diff_version);
+ smartlist_add_linecpy(result, area, buf);
+ tor_snprintf(buf, sizeof(buf), "%s %s %s", hash_token,
cons1_hash_hex, cons2_hash_hex);
+ smartlist_add_linecpy(result, area, buf);
smartlist_add_all(result, ed_diff);
smartlist_free(ed_diff);
return result;
if (ed_diff) {
/* LCOV_EXCL_START -- ed_diff is NULL except in unreachable cases above */
- SMARTLIST_FOREACH(ed_diff, char *, cp, tor_free(cp));
smartlist_free(ed_diff);
/* LCOV_EXCL_STOP */
}
char *digest2_out)
{
smartlist_t *hash_words = NULL;
- const char *format;
+ const cdline_t *format;
char cons1_hash[DIGEST256_LEN], cons2_hash[DIGEST256_LEN];
char *cons1_hash_hex, *cons2_hash_hex;
if (smartlist_len(diff) < 2) {
/* Check that it's the format and version we know. */
format = smartlist_get(diff, 0);
- if (strcmp(format, ns_diff_version)) {
+ if (!line_str_eq(format, ns_diff_version)) {
log_warn(LD_CONSDIFF, "The provided consensus diff format is not known.");
goto error_cleanup;
}
/* Grab the base16 digests. */
hash_words = smartlist_new();
- smartlist_split_string(hash_words, smartlist_get(diff, 1), " ", 0, 0);
+ {
+ const cdline_t *line2 = smartlist_get(diff, 1);
+ char *h = tor_memdup_nulterm(line2->s, line2->len);
+ smartlist_split_string(hash_words, h, " ", 0, 0);
+ tor_free(h);
+ }
/* There have to be three words, the first of which must be hash_token. */
if (smartlist_len(hash_words) != 3 ||
done:
if (cons2) {
- SMARTLIST_FOREACH(cons2, char *, cp, tor_free(cp));
smartlist_free(cons2);
}
}
/**
- * Helper: For every NL-terminated line in <b>s</b>, add that line
- * (without trailing newline) to <b>out</b>. Return -1 if there are any
- * non-NL terminated lines; 0 otherwise.
- *
- * Modifies <b>s</b> in place: don't do anything with <b>s</b> after you're
- * done here, besides freeing it.
+ * Helper: For every NL-terminated line in <b>s</b>, add a cdline referring to
+ * that line (without trailing newline) to <b>out</b>. Return -1 if there are
+ * any non-NL terminated lines; 0 otherwise.
*
* Unlike tor_split_lines, this function avoids ambiguity on its
* handling of a final line that isn't NL-terminated.
+ *
+ * All cdline_t objects are allocated in the provided memarea. Strings
+ * are not copied: if <b>s</b> changes or becomes invalid, then all
+ * generated cdlines will become invalid.
*/
-static int
-consensus_split_lines(smartlist_t *out, char *s)
+STATIC int
+consensus_split_lines(smartlist_t *out, const char *s, memarea_t *area)
{
- /* XXXX If we used string slices, we could avoid a bunch of copies here. */
while (*s) {
- char *eol = strchr(s, '\n');
+ const char *eol = strchr(s, '\n');
if (!eol) {
/* File doesn't end with newline. */
return -1;
}
- *eol = 0;
- smartlist_add(out, s);
+ if (eol - s > UINT32_MAX) {
+ /* Line is far too long. */
+ return -1;
+ }
+ cdline_t *line = memarea_alloc(area, sizeof(cdline_t));
+ line->s = s;
+ line->len = (uint32_t)(eol - s);
+ smartlist_add(out, line);
s = eol+1;
}
return 0;
}
-/** Given a list of lines, return a newly allocated string containing
+/** Given a list of cdline_t, return a newly allocated string containing
* all of the lines, terminated with NL, concatenated.
*
* Unlike smartlist_join_strings(), avoids lossy operations on empty
consensus_join_lines(const smartlist_t *inp)
{
size_t n = 0;
- SMARTLIST_FOREACH(inp, const char *, cp, n += strlen(cp) + 1);
+ SMARTLIST_FOREACH(inp, const cdline_t *, cdline, n += cdline->len + 1);
n += 1;
char *result = tor_malloc(n);
char *out = result;
- SMARTLIST_FOREACH_BEGIN(inp, const char *, cp) {
- size_t len = strlen(cp);
- memcpy(out, cp, len);
- out += len;
+ SMARTLIST_FOREACH_BEGIN(inp, const cdline_t *, cdline) {
+ memcpy(out, cdline->s, cdline->len);
+ out += cdline->len;
*out++ = '\n';
- } SMARTLIST_FOREACH_END(cp);
+ } SMARTLIST_FOREACH_END(cdline);
*out++ = '\0';
tor_assert(out == result+n);
return result;
if (BUG(r1 < 0 || r2 < 0))
return NULL; // LCOV_EXCL_LINE
- char *cons1_copy = tor_strdup(cons1);
- char *cons2_copy = tor_strdup(cons2);
+ memarea_t *area = memarea_new();
lines1 = smartlist_new();
lines2 = smartlist_new();
- if (consensus_split_lines(lines1, cons1_copy) < 0)
+ if (consensus_split_lines(lines1, cons1, area) < 0)
goto done;
- if (consensus_split_lines(lines2, cons2_copy) < 0)
+ if (consensus_split_lines(lines2, cons2, area) < 0)
goto done;
- result_lines = consdiff_gen_diff(lines1, lines2, &d1, &d2);
+ result_lines = consdiff_gen_diff(lines1, lines2, &d1, &d2, area);
done:
- smartlist_free(lines1);
- smartlist_free(lines2);
- tor_free(cons1_copy);
- tor_free(cons2_copy);
-
if (result_lines) {
result = consensus_join_lines(result_lines);
- SMARTLIST_FOREACH(result_lines, char *, cp, tor_free(cp));
smartlist_free(result_lines);
}
+
+ memarea_drop_all(area);
+ smartlist_free(lines1);
+ smartlist_free(lines2);
+
return result;
}
smartlist_t *lines1 = NULL, *lines2 = NULL;
int r1;
char *result = NULL;
+ memarea_t *area = memarea_new();
r1 = consensus_compute_digest(consensus, &d1);
if (BUG(r1 < 0))
return NULL; // LCOV_EXCL_LINE
- char *cons_copy = tor_strdup(consensus);
- char *diff_copy = tor_strdup(diff);
lines1 = smartlist_new();
lines2 = smartlist_new();
- if (consensus_split_lines(lines1, cons_copy) < 0)
+ if (consensus_split_lines(lines1, consensus, area) < 0)
goto done;
- if (consensus_split_lines(lines2, diff_copy) < 0)
+ if (consensus_split_lines(lines2, diff, area) < 0)
goto done;
result = consdiff_apply_diff(lines1, lines2, &d1);
done:
smartlist_free(lines1);
smartlist_free(lines2);
- tor_free(cons_copy);
- tor_free(diff_copy);
+ memarea_drop_all(area);
return result;
}
#include "test.h"
#include "consdiff.h"
+#include "memarea.h"
#include "log_test_helpers.h"
+#define tt_str_eq_line(a,b) \
+ tt_assert(line_str_eq((b),(a)))
+
static void
test_consdiff_smartlist_slice(void *arg)
{
{
smartlist_t *sl = smartlist_new();
smartlist_slice_t *sls;
+ memarea_t *area = memarea_new();
/* Create a regular smartlist. */
(void)arg;
- smartlist_split_string(sl, "a:d:c:a:b", ":", 0, 0);
+ consensus_split_lines(sl, "a\nd\nc\na\nb\n", area);
/* See that smartlist_slice_string_pos respects the bounds of the slice. */
sls = smartlist_slice(sl, 2, 5);
- tt_int_op(3, OP_EQ, smartlist_slice_string_pos(sls, "a"));
- tt_int_op(-1, OP_EQ, smartlist_slice_string_pos(sls, "d"));
+ cdline_t a_line = { "a", 1 };
+ tt_int_op(3, OP_EQ, smartlist_slice_string_pos(sls, &a_line));
+ cdline_t d_line = { "d", 1 };
+ tt_int_op(-1, OP_EQ, smartlist_slice_string_pos(sls, &d_line));
done:
tor_free(sls);
- if (sl) SMARTLIST_FOREACH(sl, char*, line, tor_free(line));
smartlist_free(sl);
+ memarea_drop_all(area);
}
static void
smartlist_t *sl2 = smartlist_new();
smartlist_slice_t *sls1, *sls2;
int *lengths1, *lengths2;
+ memarea_t *area = memarea_new();
/* Expected lcs lengths in regular and reverse order. */
int e_lengths1[] = { 0, 1, 2, 3, 3, 4 };
int e_lengths2[] = { 0, 1, 1, 2, 3, 4 };
(void)arg;
- smartlist_split_string(sl1, "a:b:c:d:e", ":", 0, 0);
- smartlist_split_string(sl2, "a:c:d:i:e", ":", 0, 0);
+ consensus_split_lines(sl1, "a\nb\nc\nd\ne\n", area);
+ consensus_split_lines(sl2, "a\nc\nd\ni\ne\n", area);
sls1 = smartlist_slice(sl1, 0, -1);
sls2 = smartlist_slice(sl2, 0, -1);
tor_free(lengths2);
tor_free(sls1);
tor_free(sls2);
- if (sl1) SMARTLIST_FOREACH(sl1, char*, line, tor_free(line));
- if (sl2) SMARTLIST_FOREACH(sl2, char*, line, tor_free(line));
smartlist_free(sl1);
smartlist_free(sl2);
+ memarea_drop_all(area);
}
static void
smartlist_t *sl3 = smartlist_new();
smartlist_t *sl4 = smartlist_new();
smartlist_slice_t *sls1, *sls2, *sls3, *sls4;
+ memarea_t *area = memarea_new();
(void)arg;
- smartlist_split_string(sl1, "a:b:b:b:d", ":", 0, 0);
- smartlist_split_string(sl2, "a:c:c:c:d", ":", 0, 0);
- smartlist_split_string(sl3, "a:b:b:b:a", ":", 0, 0);
- smartlist_split_string(sl4, "c:b:b:b:c", ":", 0, 0);
-
+ consensus_split_lines(sl1, "a\nb\nb\nb\nd\n", area);
+ consensus_split_lines(sl2, "a\nc\nc\nc\nd\n", area);
+ consensus_split_lines(sl3, "a\nb\nb\nb\na\n", area);
+ consensus_split_lines(sl4, "c\nb\nb\nb\nc\n", area);
sls1 = smartlist_slice(sl1, 0, -1);
sls2 = smartlist_slice(sl2, 0, -1);
sls3 = smartlist_slice(sl3, 0, -1);
tor_free(sls2);
tor_free(sls3);
tor_free(sls4);
- if (sl1) SMARTLIST_FOREACH(sl1, char*, line, tor_free(line));
- if (sl2) SMARTLIST_FOREACH(sl2, char*, line, tor_free(line));
- if (sl3) SMARTLIST_FOREACH(sl3, char*, line, tor_free(line));
- if (sl4) SMARTLIST_FOREACH(sl4, char*, line, tor_free(line));
smartlist_free(sl1);
smartlist_free(sl2);
smartlist_free(sl3);
smartlist_free(sl4);
+ memarea_drop_all(area);
}
static void
bitarray_t *changed1 = bitarray_init_zero(4);
bitarray_t *changed2 = bitarray_init_zero(4);
smartlist_slice_t *sls1, *sls2;
+ memarea_t *area = memarea_new();
(void)arg;
- smartlist_split_string(sl1, "a:b:a:a", ":", 0, 0);
- smartlist_split_string(sl2, "a:a:a:a", ":", 0, 0);
+ consensus_split_lines(sl1, "a\nb\na\na\n", area);
+ consensus_split_lines(sl2, "a\na\na\na\n", area);
/* Length of sls1 is 0. */
sls1 = smartlist_slice(sl1, 0, 0);
done:
bitarray_free(changed1);
bitarray_free(changed2);
- if (sl1) SMARTLIST_FOREACH(sl1, char*, line, tor_free(line));
- if (sl2) SMARTLIST_FOREACH(sl2, char*, line, tor_free(line));
smartlist_free(sl1);
smartlist_free(sl2);
tor_free(sls1);
tor_free(sls2);
+ memarea_drop_all(area);
}
static void
smartlist_slice_t *sls1, *sls2;
bitarray_t *changed1 = bitarray_init_zero(4);
bitarray_t *changed2 = bitarray_init_zero(4);
+ memarea_t *area = memarea_new();
(void)arg;
- smartlist_split_string(sl1, "a:a:a:a", ":", 0, 0);
- smartlist_split_string(sl2, "a:a:a:a", ":", 0, 0);
+ consensus_split_lines(sl1, "a\na\na\na\n", area);
+ consensus_split_lines(sl2, "a\na\na\na\n", area);
sls1 = smartlist_slice(sl1, 0, -1);
sls2 = smartlist_slice(sl2, 0, -1);
tt_assert(!bitarray_is_set(changed2, 2));
tt_assert(!bitarray_is_set(changed2, 3));
- SMARTLIST_FOREACH(sl2, char*, line, tor_free(line));
smartlist_clear(sl2);
- smartlist_split_string(sl2, "a:b:a:b", ":", 0, 0);
+ consensus_split_lines(sl2, "a\nb\na\nb\n", area);
tor_free(sls1);
tor_free(sls2);
sls1 = smartlist_slice(sl1, 0, -1);
bitarray_clear(changed1, 1);
bitarray_clear(changed1, 3);
- SMARTLIST_FOREACH(sl2, char*, line, tor_free(line));
smartlist_clear(sl2);
- smartlist_split_string(sl2, "b:b:b:b", ":", 0, 0);
+ consensus_split_lines(sl2, "b\nb\nb\nb\n", area);
tor_free(sls1);
tor_free(sls2);
sls1 = smartlist_slice(sl1, 0, -1);
done:
bitarray_free(changed1);
bitarray_free(changed2);
- if (sl1) SMARTLIST_FOREACH(sl1, char*, line, tor_free(line));
- if (sl2) SMARTLIST_FOREACH(sl2, char*, line, tor_free(line));
smartlist_free(sl1);
smartlist_free(sl2);
tor_free(sls1);
tor_free(sls2);
+ memarea_drop_all(area);
}
static void
test_consdiff_get_id_hash(void *arg)
{
- const char *line, *e_hash;
- /* No hash. */
(void)arg;
- tt_ptr_op(NULL, OP_EQ, get_id_hash("r name"));
+
+ cdline_t line1 = { "r name", 6 };
+ cdline_t line2 = { "r name _hash_isnt_base64 etc", 28 };
+ cdline_t line3 = { "r name hash+valid+base64 etc", 28 };
+ cdline_t tmp;
+
+ /* No hash. */
+ tt_int_op(-1, OP_EQ, get_id_hash(&line1, &tmp));
/* The hash contains characters that are not base64. */
- tt_ptr_op(NULL, OP_EQ, get_id_hash( "r name _hash_isnt_base64 etc"));
+ tt_int_op(-1, OP_EQ, get_id_hash(&line2, &tmp));
- line = "r name hash+valid+base64 etc";
- e_hash = line+7;
- tt_ptr_op(e_hash, OP_EQ, get_id_hash(line));
+ /* valid hash. */
+ tt_int_op(0, OP_EQ, get_id_hash(&line3, &tmp));
+ tt_ptr_op(tmp.s, OP_EQ, line3.s + 7);
+ tt_uint_op(tmp.len, OP_EQ, line3.len - 11);
done:
;
{
/* Doesn't start with "r ". */
(void)arg;
- tt_int_op(0, OP_EQ, is_valid_router_entry("foo"));
+ cdline_t line0 = { "foo", 3 };
+ tt_int_op(0, OP_EQ, is_valid_router_entry(&line0));
/* These are already tested with get_id_hash, but make sure it's run
* properly. */
- tt_int_op(0, OP_EQ, is_valid_router_entry("r name"));
- tt_int_op(0, OP_EQ, is_valid_router_entry("r name _hash_isnt_base64 etc"));
- tt_int_op(1, OP_EQ, is_valid_router_entry("r name hash+valid+base64 etc"));
+ cdline_t line1 = { "r name", 6 };
+ cdline_t line2 = { "r name _hash_isnt_base64 etc", 28 };
+ cdline_t line3 = { "r name hash+valid+base64 etc", 28 };
+ tt_int_op(0, OP_EQ, is_valid_router_entry(&line1));
+ tt_int_op(0, OP_EQ, is_valid_router_entry(&line2));
+ tt_int_op(1, OP_EQ, is_valid_router_entry(&line3));
done:
;
test_consdiff_next_router(void *arg)
{
smartlist_t *sl = smartlist_new();
+ memarea_t *area = memarea_new();
(void)arg;
- smartlist_add(sl, (char*)"foo");
- smartlist_add(sl,
- (char*)"r name hash+longer+than+27+chars+and+valid+base64 etc");
- smartlist_add(sl, (char*)"foo");
- smartlist_add(sl, (char*)"foo");
- smartlist_add(sl,
- (char*)"r name hash+longer+than+27+chars+and+valid+base64 etc");
- smartlist_add(sl, (char*)"foo");
+ smartlist_add_linecpy(sl, area, "foo");
+ smartlist_add_linecpy(sl, area,
+ "r name hash+longer+than+27+chars+and+valid+base64 etc");
+ smartlist_add_linecpy(sl, area, "foo");
+ smartlist_add_linecpy(sl, area, "foo");
+ smartlist_add_linecpy(sl, area,
+ "r name hash+longer+than+27+chars+and+valid+base64 etc");
+ smartlist_add_linecpy(sl, area, "foo");
/* Not currently on a router entry line, finding the next one. */
tt_int_op(1, OP_EQ, next_router(sl, 0));
done:
smartlist_free(sl);
+ memarea_drop_all(area);
+}
+
+static int
+base64cmp_wrapper(const char *a, const char *b)
+{
+ cdline_t aa = { a, a ? (uint32_t) strlen(a) : 0 };
+ cdline_t bb = { b, b ? (uint32_t) strlen(b) : 0 };
+ return base64cmp(&aa, &bb);
}
static void
{
/* NULL arguments. */
(void)arg;
- tt_int_op(0, OP_EQ, base64cmp(NULL, NULL));
- tt_int_op(-1, OP_EQ, base64cmp(NULL, "foo"));
- tt_int_op(1, OP_EQ, base64cmp("bar", NULL));
+ tt_int_op(0, OP_EQ, base64cmp_wrapper(NULL, NULL));
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper(NULL, "foo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("bar", NULL));
/* Nil base64 values. */
- tt_int_op(0, OP_EQ, base64cmp("", ""));
- tt_int_op(0, OP_EQ, base64cmp("_", "&"));
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("", ""));
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("_", "&"));
/* Exact same valid strings. */
- tt_int_op(0, OP_EQ, base64cmp("abcABC/+", "abcABC/+"));
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("abcABC/+", "abcABC/+"));
/* Both end with an invalid base64 char other than '\0'. */
- tt_int_op(0, OP_EQ, base64cmp("abcABC/+ ", "abcABC/+ "));
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("abcABC/+ ", "abcABC/+ "));
/* Only one ends with an invalid base64 char other than '\0'. */
- tt_int_op(0, OP_EQ, base64cmp("abcABC/+ ", "abcABC/+"));
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper("abcABC/+ ", "abcABC/+a"));
/* Comparisons that would return differently with strcmp(). */
tt_int_op(-1, OP_EQ, strcmp("/foo", "Afoo"));
- tt_int_op(1, OP_EQ, base64cmp("/foo", "Afoo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("/foo", "Afoo"));
tt_int_op(1, OP_EQ, strcmp("Afoo", "0foo"));
- tt_int_op(-1, OP_EQ, base64cmp("Afoo", "0foo"));
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper("Afoo", "0foo"));
/* Comparisons that would return the same as with strcmp(). */
tt_int_op(1, OP_EQ, strcmp("afoo", "Afoo"));
- tt_int_op(1, OP_EQ, base64cmp("afoo", "Afoo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("afoo", "Afoo"));
/* Different lengths */
- tt_int_op(-1, OP_EQ, base64cmp("afoo", "afooo"));
- tt_int_op(1, OP_EQ, base64cmp("afooo", "afoo"));
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper("afoo", "afooo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("afooo", "afoo"));
done:
;
{
smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL;
int i;
- int free_cons_entries = 0;/* 1 if the cons1 and cons2 contents are
- * heap-allocated */
+ memarea_t *area = memarea_new();
setup_capture_of_logs(LOG_WARN);
(void)arg;
cons2 = smartlist_new();
/* Identity hashes are not sorted properly, return NULL. */
- smartlist_add(cons1, (char*)"r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
- smartlist_add(cons1, (char*)"foo");
- smartlist_add(cons1, (char*)"r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
- smartlist_add(cons1, (char*)"bar");
+ smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
+ smartlist_add_linecpy(cons1, area, "foo");
+ smartlist_add_linecpy(cons1, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
+ smartlist_add_linecpy(cons1, area, "bar");
- smartlist_add(cons2, (char*)"r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
- smartlist_add(cons2, (char*)"foo");
- smartlist_add(cons2, (char*)"r name ccccccccccccccccccccccccccc etc");
- smartlist_add(cons2, (char*)"bar");
+ smartlist_add_linecpy(cons2, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
+ smartlist_add_linecpy(cons2, area, "foo");
+ smartlist_add_linecpy(cons2, area, "r name ccccccccccccccccccccccccccc etc");
+ smartlist_add_linecpy(cons2, area, "bar");
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_EQ, diff);
expect_single_log_msg_containing("Refusing to generate consensus diff "
"because the base consensus doesn't have its router entries sorted "
/* Same, but now with the second consensus. */
mock_clean_saved_logs();
- diff = gen_ed_diff(cons2, cons1);
+ diff = gen_ed_diff(cons2, cons1, area);
tt_ptr_op(NULL, OP_EQ, diff);
expect_single_log_msg_containing("Refusing to generate consensus diff "
"because the target consensus doesn't have its router entries sorted "
/* Same as the two above, but with the reversed thing immediately after a
match. (The code handles this differently) */
smartlist_del(cons1, 0);
- smartlist_add(cons1, (char*)"r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
+ smartlist_add_linecpy(cons1, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
mock_clean_saved_logs();
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_EQ, diff);
expect_single_log_msg_containing("Refusing to generate consensus diff "
"because the base consensus doesn't have its router entries sorted "
"properly.");
mock_clean_saved_logs();
- diff = gen_ed_diff(cons2, cons1);
+ diff = gen_ed_diff(cons2, cons1, area);
tt_ptr_op(NULL, OP_EQ, diff);
expect_single_log_msg_containing("Refusing to generate consensus diff "
"because the target consensus doesn't have its router entries sorted "
/* Identity hashes are repeated, return NULL. */
smartlist_clear(cons1);
- smartlist_add(cons1, (char*)"r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
- smartlist_add(cons1, (char*)"foo");
- smartlist_add(cons1, (char*)"r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
- smartlist_add(cons1, (char*)"bar");
+ smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
+ smartlist_add_linecpy(cons1, area, "foo");
+ smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
+ smartlist_add_linecpy(cons1, area, "bar");
mock_clean_saved_logs();
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_EQ, diff);
expect_single_log_msg_containing("Refusing to generate consensus diff "
"because the base consensus doesn't have its router entries sorted "
smartlist_clear(cons1);
smartlist_clear(cons2);
- smartlist_add(cons1, (char*)"foo1");
- smartlist_add(cons1, (char*)"foo2");
+ smartlist_add_linecpy(cons1, area, "foo1");
+ smartlist_add_linecpy(cons1, area, "foo2");
- smartlist_add(cons2, (char*)"foo1");
- smartlist_add(cons2, (char*)".");
- smartlist_add(cons2, (char*)"foo2");
+ smartlist_add_linecpy(cons2, area, "foo1");
+ smartlist_add_linecpy(cons2, area, ".");
+ smartlist_add_linecpy(cons2, area, "foo2");
mock_clean_saved_logs();
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_EQ, diff);
expect_single_log_msg_containing("Cannot generate consensus diff "
"because one of the lines to be added is \".\".");
smartlist_clear(cons1);
smartlist_clear(cons2);
- for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add(cons1, (char*)"a");
- for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add(cons1, (char*)"b");
+ for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add_linecpy(cons1, area, "a");
+ for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add_linecpy(cons1, area, "b");
mock_clean_saved_logs();
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
+
tt_ptr_op(NULL, OP_EQ, diff);
expect_single_log_msg_containing("Refusing to generate consensus diff "
"because we found too few common router ids.");
smartlist_clear(cons1);
smartlist_clear(cons2);
- smartlist_add(cons1, (char*)"foo1");
- smartlist_add(cons1, (char*)".");
- smartlist_add(cons1, (char*)".");
- smartlist_add(cons1, (char*)"foo2");
+ smartlist_add_linecpy(cons1, area, "foo1");
+ smartlist_add_linecpy(cons1, area, ".");
+ smartlist_add_linecpy(cons1, area, ".");
+ smartlist_add_linecpy(cons1, area, "foo2");
- smartlist_add(cons2, (char*)"foo1");
- smartlist_add(cons2, (char*)".");
- smartlist_add(cons2, (char*)"foo2");
+ smartlist_add_linecpy(cons2, area, "foo1");
+ smartlist_add_linecpy(cons2, area, ".");
+ smartlist_add_linecpy(cons2, area, "foo2");
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
- SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_free(diff);
/* Empty diff tests. */
smartlist_clear(cons1);
smartlist_clear(cons2);
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(0, OP_EQ, smartlist_len(diff));
smartlist_free(diff);
- smartlist_add(cons1, (char*)"foo");
- smartlist_add(cons1, (char*)"bar");
+ smartlist_add_linecpy(cons1, area, "foo");
+ smartlist_add_linecpy(cons1, area, "bar");
- smartlist_add(cons2, (char*)"foo");
- smartlist_add(cons2, (char*)"bar");
+ smartlist_add_linecpy(cons2, area, "foo");
+ smartlist_add_linecpy(cons2, area, "bar");
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(0, OP_EQ, smartlist_len(diff));
smartlist_free(diff);
/* Everything is deleted. */
smartlist_clear(cons2);
- diff = gen_ed_diff(cons1, cons2);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(1, OP_EQ, smartlist_len(diff));
- tt_str_op("1,2d", OP_EQ, smartlist_get(diff, 0));
+ tt_str_eq_line("1,2d", smartlist_get(diff, 0));
- SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_free(diff);
/* Everything is added. */
- diff = gen_ed_diff(cons2, cons1);
+ diff = gen_ed_diff(cons2, cons1, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(4, OP_EQ, smartlist_len(diff));
- tt_str_op("0a", OP_EQ, smartlist_get(diff, 0));
- tt_str_op("foo", OP_EQ, smartlist_get(diff, 1));
- tt_str_op("bar", OP_EQ, smartlist_get(diff, 2));
- tt_str_op(".", OP_EQ, smartlist_get(diff, 3));
+ tt_str_eq_line("0a", smartlist_get(diff, 0));
+ tt_str_eq_line("foo", smartlist_get(diff, 1));
+ tt_str_eq_line("bar", smartlist_get(diff, 2));
+ tt_str_eq_line(".", smartlist_get(diff, 3));
- SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_free(diff);
/* Everything is changed. */
- smartlist_add(cons2, (char*)"foo2");
- smartlist_add(cons2, (char*)"bar2");
- diff = gen_ed_diff(cons1, cons2);
+ smartlist_add_linecpy(cons2, area, "foo2");
+ smartlist_add_linecpy(cons2, area, "bar2");
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(4, OP_EQ, smartlist_len(diff));
- tt_str_op("1,2c", OP_EQ, smartlist_get(diff, 0));
- tt_str_op("foo2", OP_EQ, smartlist_get(diff, 1));
- tt_str_op("bar2", OP_EQ, smartlist_get(diff, 2));
- tt_str_op(".", OP_EQ, smartlist_get(diff, 3));
+ tt_str_eq_line("1,2c", smartlist_get(diff, 0));
+ tt_str_eq_line("foo2", smartlist_get(diff, 1));
+ tt_str_eq_line("bar2", smartlist_get(diff, 2));
+ tt_str_eq_line(".", smartlist_get(diff, 3));
- SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_free(diff);
/* Test 'a', 'c' and 'd' together. See that it is done in reverse order. */
smartlist_clear(cons1);
smartlist_clear(cons2);
- smartlist_split_string(cons1, "A:B:C:D:E", ":", 0, 0);
- smartlist_split_string(cons2, "A:C:O:E:U", ":", 0, 0);
- free_cons_entries = 1;
- diff = gen_ed_diff(cons1, cons2);
+ consensus_split_lines(cons1, "A\nB\nC\nD\nE\n", area);
+ consensus_split_lines(cons2, "A\nC\nO\nE\nU\n", area);
+ diff = gen_ed_diff(cons1, cons2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(7, OP_EQ, smartlist_len(diff));
- tt_str_op("5a", OP_EQ, smartlist_get(diff, 0));
- tt_str_op("U", OP_EQ, smartlist_get(diff, 1));
- tt_str_op(".", OP_EQ, smartlist_get(diff, 2));
- tt_str_op("4c", OP_EQ, smartlist_get(diff, 3));
- tt_str_op("O", OP_EQ, smartlist_get(diff, 4));
- tt_str_op(".", OP_EQ, smartlist_get(diff, 5));
- tt_str_op("2d", OP_EQ, smartlist_get(diff, 6));
+ tt_str_eq_line("5a", smartlist_get(diff, 0));
+ tt_str_eq_line("U", smartlist_get(diff, 1));
+ tt_str_eq_line(".", smartlist_get(diff, 2));
+ tt_str_eq_line("4c", smartlist_get(diff, 3));
+ tt_str_eq_line("O", smartlist_get(diff, 4));
+ tt_str_eq_line(".", smartlist_get(diff, 5));
+ tt_str_eq_line("2d", smartlist_get(diff, 6));
/* TODO: small real use-cases, i.e. consensuses. */
done:
teardown_capture_of_logs();
- if (free_cons_entries) {
- if (cons1) SMARTLIST_FOREACH(cons1, char*, line, tor_free(line));
- if (cons2) SMARTLIST_FOREACH(cons2, char*, line, tor_free(line));
- }
smartlist_free(cons1);
smartlist_free(cons2);
- if (diff) SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_free(diff);
+ memarea_drop_all(area);
}
static void
test_consdiff_apply_ed_diff(void *arg)
{
smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL;
+ memarea_t *area = memarea_new();
(void)arg;
cons1 = smartlist_new();
diff = smartlist_new();
setup_capture_of_logs(LOG_WARN);
- smartlist_split_string(cons1, "A:B:C:D:E", ":", 0, 0);
+ consensus_split_lines(cons1, "A\nB\nC\nD\nE\n", area);
/* Command without range. */
- smartlist_add(diff, (char*)"a");
+ smartlist_add_linecpy(diff, area, "a");
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
expect_single_log_msg_containing("an ed command was missing a line number");
/* Range without command. */
- smartlist_add(diff, (char*)"1");
+ smartlist_add_linecpy(diff, area, "1");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
/* Range without end. */
- smartlist_add(diff, (char*)"1,");
+ smartlist_add_linecpy(diff, area, "1,");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
/* Incoherent ranges. */
- smartlist_add(diff, (char*)"1,1");
+ smartlist_add_linecpy(diff, area, "1,1");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
- smartlist_add(diff, (char*)"3,2");
+ smartlist_add_linecpy(diff, area, "3,2");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
/* Script is not in reverse order. */
- smartlist_add(diff, (char*)"1d");
- smartlist_add(diff, (char*)"3d");
+ smartlist_add_linecpy(diff, area, "1d");
+ smartlist_add_linecpy(diff, area, "3d");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
/* Script contains unrecognised commands longer than one char. */
- smartlist_add(diff, (char*)"1foo");
+ smartlist_add_linecpy(diff, area, "1foo");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
/* Script contains unrecognised commands. */
- smartlist_add(diff, (char*)"1e");
+ smartlist_add_linecpy(diff, area, "1e");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
/* Command that should be followed by at least one line and a ".", but
* isn't. */
- smartlist_add(diff, (char*)"0a");
+ smartlist_add_linecpy(diff, area, "0a");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
"insert zero lines.");
/* Now it is followed by a ".", but it inserts zero lines. */
- smartlist_add(diff, (char*)".");
+ smartlist_add_linecpy(diff, area, ".");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
/* Now it it inserts something, but has no terminator. */
- smartlist_add(diff, (char*)"0a");
- smartlist_add(diff, (char*)"hello");
+ smartlist_add_linecpy(diff, area, "0a");
+ smartlist_add_linecpy(diff, area, "hello");
mock_clean_saved_logs();
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_EQ, cons2);
smartlist_clear(diff);
/* Test appending text, 'a'. */
- smartlist_split_string(diff, "3a:U:O:.:0a:V:.", ":", 0, 0);
+ consensus_split_lines(diff, "3a\nU\nO\n.\n0a\nV\n.\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(8, OP_EQ, smartlist_len(cons2));
- tt_str_op("V", OP_EQ, smartlist_get(cons2, 0));
- tt_str_op("A", OP_EQ, smartlist_get(cons2, 1));
- tt_str_op("B", OP_EQ, smartlist_get(cons2, 2));
- tt_str_op("C", OP_EQ, smartlist_get(cons2, 3));
- tt_str_op("U", OP_EQ, smartlist_get(cons2, 4));
- tt_str_op("O", OP_EQ, smartlist_get(cons2, 5));
- tt_str_op("D", OP_EQ, smartlist_get(cons2, 6));
- tt_str_op("E", OP_EQ, smartlist_get(cons2, 7));
-
- SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
+ tt_str_eq_line("V", smartlist_get(cons2, 0));
+ tt_str_eq_line("A", smartlist_get(cons2, 1));
+ tt_str_eq_line("B", smartlist_get(cons2, 2));
+ tt_str_eq_line("C", smartlist_get(cons2, 3));
+ tt_str_eq_line("U", smartlist_get(cons2, 4));
+ tt_str_eq_line("O", smartlist_get(cons2, 5));
+ tt_str_eq_line("D", smartlist_get(cons2, 6));
+ tt_str_eq_line("E", smartlist_get(cons2, 7));
+
smartlist_clear(diff);
- SMARTLIST_FOREACH(cons2, char*, line, tor_free(line));
smartlist_free(cons2);
/* Test deleting text, 'd'. */
- smartlist_split_string(diff, "4d:1,2d", ":", 0, 0);
+ consensus_split_lines(diff, "4d\n1,2d\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(2, OP_EQ, smartlist_len(cons2));
- tt_str_op("C", OP_EQ, smartlist_get(cons2, 0));
- tt_str_op("E", OP_EQ, smartlist_get(cons2, 1));
+ tt_str_eq_line("C", smartlist_get(cons2, 0));
+ tt_str_eq_line("E", smartlist_get(cons2, 1));
- SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_clear(diff);
- SMARTLIST_FOREACH(cons2, char*, line, tor_free(line));
smartlist_free(cons2);
/* Test changing text, 'c'. */
- smartlist_split_string(diff, "4c:T:X:.:1, 2c:M:.", ":", 0, 0);
+ consensus_split_lines(diff, "4c\nT\nX\n.\n1, 2c\nM\n.\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(5, OP_EQ, smartlist_len(cons2));
- tt_str_op("M", OP_EQ, smartlist_get(cons2, 0));
- tt_str_op("C", OP_EQ, smartlist_get(cons2, 1));
- tt_str_op("T", OP_EQ, smartlist_get(cons2, 2));
- tt_str_op("X", OP_EQ, smartlist_get(cons2, 3));
- tt_str_op("E", OP_EQ, smartlist_get(cons2, 4));
+ tt_str_eq_line("M", smartlist_get(cons2, 0));
+ tt_str_eq_line("C", smartlist_get(cons2, 1));
+ tt_str_eq_line("T", smartlist_get(cons2, 2));
+ tt_str_eq_line("X", smartlist_get(cons2, 3));
+ tt_str_eq_line("E", smartlist_get(cons2, 4));
- SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_clear(diff);
- SMARTLIST_FOREACH(cons2, char*, line, tor_free(line));
smartlist_free(cons2);
/* Test 'a', 'd' and 'c' together. */
- smartlist_split_string(diff, "4c:T:X:.:2d:0a:M:.", ":", 0, 0);
+ consensus_split_lines(diff, "4c\nT\nX\n.\n2d\n0a\nM\n.\n", area);
cons2 = apply_ed_diff(cons1, diff, 0);
tt_ptr_op(NULL, OP_NE, cons2);
tt_int_op(6, OP_EQ, smartlist_len(cons2));
- tt_str_op("M", OP_EQ, smartlist_get(cons2, 0));
- tt_str_op("A", OP_EQ, smartlist_get(cons2, 1));
- tt_str_op("C", OP_EQ, smartlist_get(cons2, 2));
- tt_str_op("T", OP_EQ, smartlist_get(cons2, 3));
- tt_str_op("X", OP_EQ, smartlist_get(cons2, 4));
- tt_str_op("E", OP_EQ, smartlist_get(cons2, 5));
+ tt_str_eq_line("M", smartlist_get(cons2, 0));
+ tt_str_eq_line("A", smartlist_get(cons2, 1));
+ tt_str_eq_line("C", smartlist_get(cons2, 2));
+ tt_str_eq_line("T", smartlist_get(cons2, 3));
+ tt_str_eq_line("X", smartlist_get(cons2, 4));
+ tt_str_eq_line("E", smartlist_get(cons2, 5));
done:
teardown_capture_of_logs();
- if (cons1) SMARTLIST_FOREACH(cons1, char*, line, tor_free(line));
- if (cons2) SMARTLIST_FOREACH(cons2, char*, line, tor_free(line));
smartlist_free(cons1);
smartlist_free(cons2);
- if (diff) SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_free(diff);
+ memarea_drop_all(area);
}
static void
char *cons1_str=NULL, *cons2_str=NULL;
smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL;
consensus_digest_t digests1, digests2;
+ memarea_t *area = memarea_new();
(void)arg;
cons1 = smartlist_new();
cons2 = smartlist_new();
tt_int_op(0, OP_EQ,
consensus_compute_digest(cons2_str, &digests2));
- tor_split_lines(cons1, cons1_str, (int)strlen(cons1_str));
- tor_split_lines(cons2, cons2_str, (int)strlen(cons2_str));
+ consensus_split_lines(cons1, cons1_str, area);
+ consensus_split_lines(cons2, cons2_str, area);
- diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2);
+ diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area);
tt_ptr_op(NULL, OP_EQ, diff);
/* Check that the headers are done properly. */
tt_int_op(0, OP_EQ,
consensus_compute_digest(cons1_str, &digests1));
smartlist_clear(cons1);
- tor_split_lines(cons1, cons1_str, (int)strlen(cons1_str));
- diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2);
+ consensus_split_lines(cons1, cons1_str, area);
+ diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area);
tt_ptr_op(NULL, OP_NE, diff);
tt_int_op(7, OP_EQ, smartlist_len(diff));
- tt_str_op("network-status-diff-version 1", OP_EQ, smartlist_get(diff, 0));
- tt_str_op("hash "
+ tt_assert(line_str_eq(smartlist_get(diff, 0),
+ "network-status-diff-version 1"));
+ tt_assert(line_str_eq(smartlist_get(diff, 1), "hash "
"06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4 "
- "7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1",
- OP_EQ, smartlist_get(diff, 1));
- tt_str_op("3,4d", OP_EQ, smartlist_get(diff, 2));
- tt_str_op("1a", OP_EQ, smartlist_get(diff, 3));
- tt_str_op("r name aaaaaaaaaaaaaaaaa etc", OP_EQ, smartlist_get(diff, 4));
- tt_str_op("foo", OP_EQ, smartlist_get(diff, 5));
- tt_str_op(".", OP_EQ, smartlist_get(diff, 6));
+ "7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1"));
+ tt_assert(line_str_eq(smartlist_get(diff, 2), "3,4d"));
+ tt_assert(line_str_eq(smartlist_get(diff, 3), "1a"));
+ tt_assert(line_str_eq(smartlist_get(diff, 4),
+ "r name aaaaaaaaaaaaaaaaa etc"));
+ tt_assert(line_str_eq(smartlist_get(diff, 5), "foo"));
+ tt_assert(line_str_eq(smartlist_get(diff, 6), "."));
/* TODO: small real use-cases, i.e. consensuses. */
tor_free(cons2_str);
smartlist_free(cons1);
smartlist_free(cons2);
- if (diff) SMARTLIST_FOREACH(diff, char*, line, tor_free(line));
smartlist_free(diff);
+ memarea_drop_all(area);
}
static void
char *cons1_str=NULL, *cons2 = NULL;
consensus_digest_t digests1;
(void)arg;
+ memarea_t *area = memarea_new();
cons1 = smartlist_new();
diff = smartlist_new();
setup_capture_of_logs(LOG_INFO);
);
tt_int_op(0, OP_EQ,
consensus_compute_digest(cons1_str, &digests1));
- tor_split_lines(cons1, cons1_str, (int)strlen(cons1_str));
+ consensus_split_lines(cons1, cons1_str, area);
/* diff doesn't have enough lines. */
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
expect_single_log_msg_containing("too short")
/* first line doesn't match format-version string. */
- smartlist_add(diff, (char*)"foo-bar");
- smartlist_add(diff, (char*)"header-line");
+ smartlist_add_linecpy(diff, area, "foo-bar");
+ smartlist_add_linecpy(diff, area, "header-line");
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
/* The first word of the second header line is not "hash". */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"word a b");
- smartlist_add(diff, (char*)"x");
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "word a b");
+ smartlist_add_linecpy(diff, area, "x");
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
/* Wrong number of words after "hash". */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash a b c");
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash a b c");
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
/* base16 digests do not have the expected length. */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash aaa bbb");
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash aaa bbb");
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
/* base16 digests contain non-base16 characters. */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash"
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
" ????????????????????????????????????????????????????????????????"
" ----------------------------------------------------------------");
mock_clean_saved_logs();
* As tested in apply_ed_diff, but check that apply_diff does return NULL if
* the ed diff can't be applied. */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash"
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
/* sha3 of cons1. */
" 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
/* sha256 of cons2. */
" 635D34593020C08E5ECD865F9986E29D50028EFA62843766A8197AD228A7F6AA");
- smartlist_add(diff, (char*)"foobar");
+ smartlist_add_linecpy(diff, area, "foobar");
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
/* Base consensus doesn't match its digest as found in the diff. */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash"
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
/* bogus sha256. */
" 3333333333333333333333333333333333333333333333333333333333333333"
/* sha256 of cons2. */
/* Resulting consensus doesn't match its digest as found in the diff. */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash"
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
/* sha3 of cons1. */
" 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
/* bogus sha3. */
/* XXXX No longer possible, since we aren't using the other algorithm. */
/* Resulting consensus digest cannot be computed */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash"
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
/* sha3 of cons1. */
" 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
/* bogus sha3. */
" 3333333333333333333333333333333333333333333333333333333333333333");
- smartlist_add(diff, (char*)"1,2d"); // remove starting line
+ smartlist_add_linecpy(diff, area, "1,2d"); // remove starting line
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
/* Very simple test, only to see that nothing errors. */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash"
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
/* sha3 of cons1. */
" 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
/* sha3 of cons2. */
" 90A418881B2FCAB3D9E60EE02E4D666D56CFA38F8A3B7AA3E0ADBA530DDA9353");
- smartlist_add(diff, (char*)"3c");
- smartlist_add(diff, (char*)"sample");
- smartlist_add(diff, (char*)".");
+ smartlist_add_linecpy(diff, area, "3c");
+ smartlist_add_linecpy(diff, area, "sample");
+ smartlist_add_linecpy(diff, area, ".");
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_NE, cons2);
tt_str_op(
/* Check that lowercase letters in base16-encoded digests work too. */
smartlist_clear(diff);
- smartlist_add(diff, (char*)"network-status-diff-version 1");
- smartlist_add(diff, (char*)"hash"
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
/* sha3 of cons1. */
" 06646d6cf563a41869d3b02e73254372ae3140046c5e7d83c9f71e54976af9b4"
/* sha3 of cons2. */
" 90a418881b2fcab3d9e60ee02e4d666d56cfa38f8a3b7aa3e0adba530dda9353");
- smartlist_add(diff, (char*)"3c");
- smartlist_add(diff, (char*)"sample");
- smartlist_add(diff, (char*)".");
+ smartlist_add_linecpy(diff, area, "3c");
+ smartlist_add_linecpy(diff, area, "sample");
+ smartlist_add_linecpy(diff, area, ".");
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_NE, cons2);
tt_str_op(
tor_free(cons1_str);
smartlist_free(cons1);
smartlist_free(diff);
+ memarea_drop_all(area);
}
#define CONSDIFF_LEGACY(name) \