From 5ccae6decf934f39d6414d16221a7e1bdbc8b205 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Wed, 3 Apr 2024 09:50:31 -0400 Subject: [PATCH] ASAN/LSAN fixes --- .clang-tidy | 172 +++++++------------------------------------------ .gitignore | 127 +++++++++++++++++++++++++++++++++--- Makefile | 7 +- examples/slm.c | 73 +++++++++++++++------ include/sl.h | 81 ++++++++++++----------- 5 files changed, 242 insertions(+), 218 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 764f500..05cca42 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,149 +1,25 @@ -# Generated from CLion Inspection settings -#bugprone-reserved-identifier, -#misc-no-recursion, --- -Checks: '-*, --deprecated-non-prototype -bugprone-argument-comment, -bugprone-assert-side-effect, -bugprone-bad-signal-to-kill-thread, -bugprone-branch-clone, -bugprone-copy-constructor-init, -bugprone-dangling-handle, -bugprone-dynamic-static-initializers, -bugprone-fold-init-type, -bugprone-forward-declaration-namespace, -bugprone-forwarding-reference-overload, -bugprone-inaccurate-erase, -bugprone-incorrect-roundings, -bugprone-integer-division, -bugprone-lambda-function-name, -bugprone-macro-parentheses, -bugprone-macro-repeated-side-effects, -bugprone-misplaced-operator-in-strlen-in-alloc, -bugprone-misplaced-pointer-arithmetic-in-alloc, -bugprone-misplaced-widening-cast, -bugprone-move-forwarding-reference, -bugprone-multiple-statement-macro, -bugprone-no-escape, -bugprone-not-null-terminated-result, -bugprone-parent-virtual-call, -bugprone-posix-return, -bugprone-sizeof-container, -bugprone-sizeof-expression, -bugprone-spuriously-wake-up-functions, -bugprone-string-constructor, -bugprone-string-integer-assignment, -bugprone-string-literal-with-embedded-nul, -bugprone-suspicious-enum-usage, -bugprone-suspicious-include, -bugprone-suspicious-memset-usage, -bugprone-suspicious-missing-comma, -bugprone-suspicious-semicolon, -bugprone-suspicious-string-compare, -bugprone-suspicious-memory-comparison, -bugprone-suspicious-realloc-usage, -bugprone-swapped-arguments, -bugprone-terminating-continue, -bugprone-throw-keyword-missing, -bugprone-too-small-loop-variable, -bugprone-undefined-memory-manipulation, -bugprone-undelegated-constructor, -bugprone-unhandled-self-assignment, -bugprone-unused-raii, -bugprone-unused-return-value, -bugprone-use-after-move, -bugprone-virtual-near-miss, -cert-dcl21-cpp, -cert-dcl58-cpp, -cert-err34-c, -cert-err52-cpp, -cert-err60-cpp, -cert-flp30-c, -cert-msc50-cpp, -cert-msc51-cpp, -cert-str34-c, -cppcoreguidelines-interfaces-global-init, -cppcoreguidelines-narrowing-conversions, -cppcoreguidelines-pro-type-member-init, -cppcoreguidelines-pro-type-static-cast-downcast, -cppcoreguidelines-slicing, -google-default-arguments, -google-explicit-constructor, -google-runtime-operator, -hicpp-exception-baseclass, -hicpp-multiway-paths-covered, -misc-misplaced-const, -misc-new-delete-overloads, -misc-non-copyable-objects, -misc-throw-by-value-catch-by-reference, -misc-unconventional-assign-operator, -misc-uniqueptr-reset-release, -modernize-avoid-bind, -modernize-concat-nested-namespaces, -modernize-deprecated-headers, -modernize-deprecated-ios-base-aliases, -modernize-loop-convert, -modernize-make-shared, -modernize-make-unique, -modernize-pass-by-value, -modernize-raw-string-literal, -modernize-redundant-void-arg, -modernize-replace-auto-ptr, -modernize-replace-disallow-copy-and-assign-macro, -modernize-replace-random-shuffle, -modernize-return-braced-init-list, -modernize-shrink-to-fit, -modernize-unary-static-assert, -modernize-use-auto, -modernize-use-bool-literals, -modernize-use-emplace, -modernize-use-equals-default, -modernize-use-equals-delete, -modernize-use-nodiscard, -modernize-use-noexcept, -modernize-use-nullptr, -modernize-use-override, -modernize-use-transparent-functors, -modernize-use-uncaught-exceptions, -mpi-buffer-deref, -mpi-type-mismatch, -openmp-use-default-none, -performance-faster-string-find, -performance-for-range-copy, -performance-implicit-conversion-in-loop, -performance-inefficient-algorithm, -performance-inefficient-string-concatenation, -performance-inefficient-vector-operation, -performance-move-const-arg, -performance-move-constructor-init, -performance-no-automatic-move, -performance-noexcept-move-constructor, -performance-trivially-destructible, -performance-type-promotion-in-math-fn, -performance-unnecessary-copy-initialization, -performance-unnecessary-value-param, -portability-simd-intrinsics, -readability-avoid-const-params-in-decls, -readability-const-return-type, -readability-container-size-empty, -readability-convert-member-functions-to-static, -readability-delete-null-pointer, -readability-deleted-default, -readability-inconsistent-declaration-parameter-name, -readability-make-member-function-const, -readability-misleading-indentation, -readability-misplaced-array-index, -readability-non-const-parameter, -readability-redundant-control-flow, -readability-redundant-declaration, -readability-redundant-function-ptr-dereference, -readability-redundant-smartptr-get, -readability-redundant-string-cstr, -readability-redundant-string-init, -readability-simplify-subscript-expr, -readability-static-accessed-through-instance, -readability-static-definition-in-anonymous-namespace, -readability-string-compare, -readability-uniqueptr-delete-release, -readability-use-anyofallof' +Checks: > + bugprone-*, + clang-analyzer-*, + google-*, + misc-*, + modernize-*, + performance-*, + portability-*, + -bugprone-branch-clone, + -bugprone-easily-swappable-parameters, + -bugprone-macro-parentheses, + -bugprone-narrowing-conversions, + -bugprone-not-null-terminated-result, + -bugprone-reserved-identifier, + -bugprone-sizeof-expression, + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + -clang-analyzer-security.insecureAPI.strcpy, + -google-readability-todo, + -misc-unused-parameters, + -misc-no-recursion, + -performance-no-int-to-ptr, + -bugprone-assignment-in-if-condition, + +... diff --git a/.gitignore b/.gitignore index 5174543..b062548 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,121 @@ -build_unix/** -*~ -*.o -libskiplist.so libskiplist.a +libskiplist.so +**/*.o tests/test -examples/skip examples/mls -examples/mls.c -examples/slm -.direnv/ -.idea/ +/mxe +.cache +hints.txt +tmp/ +git.diff +.direnv +.vscode/.ropeproject +.vscode/ipch +.codelite/ +.cmaketools.json +*.tags +*.dll +build/ +cmake-build* +.cmake_dirty +Makefile +Testing/ +compile_commands.json +.tern* +*.iml +*.dat +*.fsm +*.db + +# Created by https://www.gitignore.io/api/jetbrains +# Edit at https://www.gitignore.io/?templates=jetbrains + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +# End of https://www.gitignore.io/api/jetbrains diff --git a/Makefile b/Makefile index 5c368bc..40ba5e6 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,11 @@ SHARED_LIB = libskiplist.so # https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html #CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c99 -Iinclude/ -fPIC -CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c99 -Iinclude/ -fPIC -#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,undefined -std=c99 -Iinclude/ -fPIC +#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c99 -Iinclude/ -fPIC +CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c99 -Iinclude/ -fPIC +#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c99 -Iinclude/ -fPIC +#env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./examples/mls + TEST_FLAGS = -Itests/ TESTS = tests/test diff --git a/examples/slm.c b/examples/slm.c index f3cdd35..c8a7747 100644 --- a/examples/slm.c +++ b/examples/slm.c @@ -21,7 +21,7 @@ #define TEST_ARRAY_SIZE 1000 #define VALIDATE //define SNAPSHOTS -//define DOT +#define DOT #ifdef DOT size_t gen = 0; FILE *of = 0; @@ -79,9 +79,10 @@ SKIPLIST_DECL( { free(node->value); }, /* update entry: rc, node, value */ { + char *numeral = (char *)value; if (node->value) free(node->value); - node->value = (char*)value; + node->value = numeral; }, /* archive an entry: rc, src, dest */ { @@ -363,7 +364,6 @@ main() api_skip_del_esempio(list, key); CHECK; key = -(TEST_ARRAY_SIZE)-1; - numeral = int_to_roman_numeral(key); api_skip_del_esempio(list, key); CHECK; @@ -378,35 +378,68 @@ main() api_skip_release_snapshots_esempio(list); #endif - assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, -2)->value, int_to_roman_numeral(-2)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, 0)->value, int_to_roman_numeral(1)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, 2)->value, int_to_roman_numeral(2)) == 0); + numeral = int_to_roman_numeral(-(TEST_ARRAY_SIZE)); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(-2); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, -2)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(1); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, 0)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(2); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, 2)->value, numeral) == 0); + free(numeral); assert(api_skip_pos_esempio(list, SKIP_GTE, (TEST_ARRAY_SIZE + 1)) == NULL); - assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, -2)->value, int_to_roman_numeral(-1)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, 0)->value, int_to_roman_numeral(1)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, 1)->value, int_to_roman_numeral(2)) == 0); + numeral = int_to_roman_numeral(-(TEST_ARRAY_SIZE)); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, -(TEST_ARRAY_SIZE)-1)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(-1); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, -2)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(1); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, 0)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(2); + assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, 1)->value, numeral) == 0); + free(numeral); assert(api_skip_pos_esempio(list, SKIP_GT, TEST_ARRAY_SIZE) == NULL); assert(api_skip_pos_esempio(list, SKIP_LT, -(TEST_ARRAY_SIZE)) == NULL); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, -1)->value, int_to_roman_numeral(-2)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, 0)->value, int_to_roman_numeral(-1)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, 2)->value, int_to_roman_numeral(1)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, (TEST_ARRAY_SIZE + 1))->value, int_to_roman_numeral(TEST_ARRAY_SIZE)) == 0); + numeral = int_to_roman_numeral(-2); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, -1)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(-1); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, 0)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(1); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, 2)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(TEST_ARRAY_SIZE); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, (TEST_ARRAY_SIZE + 1))->value, numeral) == 0); + free(numeral); assert(api_skip_pos_esempio(list, SKIP_LTE, -(TEST_ARRAY_SIZE)-1) == NULL); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, -2)->value, int_to_roman_numeral(-2)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, 0)->value, int_to_roman_numeral(-1)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, 2)->value, int_to_roman_numeral(2)) == 0); - assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, (TEST_ARRAY_SIZE + 1))->value, int_to_roman_numeral(TEST_ARRAY_SIZE)) == 0); + numeral = int_to_roman_numeral(-2); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, -2)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(-1); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, 0)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(2); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, 2)->value, numeral) == 0); + free(numeral); + numeral = int_to_roman_numeral(TEST_ARRAY_SIZE); + assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, (TEST_ARRAY_SIZE + 1))->value, numeral) == 0); + free(numeral); - api_skip_free_esempio(list); #ifdef DOT api_skip_dot_end_esempio(of, gen); fclose(of); #endif + api_skip_free_esempio(list); + free(list); return rc; } #pragma GCC pop_options diff --git a/include/sl.h b/include/sl.h index 86ee196..2e60795 100644 --- a/include/sl.h +++ b/include/sl.h @@ -213,13 +213,12 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li } *sle_levels; \ } -#define SKIPLIST_FOREACH_H2T(decl, prefix, list, elm, iter) \ - for (iter = 0, (elm) = prefix##skip_head_##decl(list); (elm) != NULL; iter++, (elm) = prefix##skip_next_node_##decl(list, elm)) +#define SKIPLIST_FOREACH_H2T(decl, prefix, field, list, elm, iter) \ + for (iter = 0, (elm) = (list)->slh_head; ((elm) = (elm)->field.sle_levels[0].next) != (list)->slh_tail; iter++) /* Iterate from tail to head over the nodes. */ -#define SKIPLIST_FOREACH_T2H(decl, prefix, list, elm, iter) \ - for (iter = prefix##skip_size_##decl(list), (elm) = prefix##skip_tailf_##decl(list); (elm) != NULL; \ - iter--, (elm) = prefix##skip_prev_node_##decl(list, elm)) +#define SKIPLIST_FOREACH_T2H(decl, prefix, field, list, elm, iter) \ + for (iter = (list)->slh_length, (elm) = (list)->slh_tail; ((elm) = (elm)->field.sle_prev) != (list)->slh_head; iter--) /* Iterate over the next pointers in a node from bottom to top (B2T) or top to bottom (T2B). */ #define __SKIP_ALL_ENTRIES_T2B(field, elm) for (size_t lvl = slist->slh_max_height; lvl != (size_t)-1; lvl--) @@ -227,9 +226,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li #define __SKIP_ENTRIES_T2B_FROM(field, elm, off) for (size_t lvl = off; lvl != (size_t)-1; lvl--) #define __SKIP_IS_LAST_ENTRY_T2B() if (lvl == 0) -#define __SKIP_ALL_ENTRIES_B2T(field, elm) for (size_t lvl = 0; lvl < slist->slh_max_height + 1; lvl++) -#define __SKIP_ENTRIES_B2T(field, elm) for (size_t lvl = 0; lvl < elm->field.sle_height + 1; lvl++) -#define __SKIP_ENTRIES_B2T_FROM(field, elm, off) for (size_t lvl = off; lvl < elm->field.sle_height + 1; lvl++) +#define __SKIP_ALL_ENTRIES_B2T(field, elm) for (size_t lvl = 0; lvl < slist->slh_max_height; lvl++) +#define __SKIP_ENTRIES_B2T(field, elm) for (size_t lvl = 0; lvl < elm->field.sle_height; lvl++) +#define __SKIP_ENTRIES_B2T_FROM(field, elm, off) for (size_t lvl = off; lvl < elm->field.sle_height; lvl++) #define __SKIP_IS_LAST_ENTRY_B2T() if (lvl + 1 == elm->field.sle_height) /* Iterate over the subtree to the left (v, or 'lt') and right (u) or "CHu" and "CHv". */ @@ -421,6 +420,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li slist->slh_length = 0; \ slist->slh_max_height = SKIPLIST_MAX_HEIGHT == 1 ? (size_t)(max < 0 ? -max : max) : SKIPLIST_MAX_HEIGHT; \ slist->slh_snap.era = 0; \ + slist->slh_snap.pres = 0; \ slist->slh_fns.free_entry = __skip_free_entry_fn_##decl; \ slist->slh_fns.update_entry = __skip_update_entry_fn_##decl; \ slist->slh_fns.archive_entry = __skip_archive_entry_fn_##decl; \ @@ -433,7 +433,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li if (rc) \ goto fail; \ \ - slist->slh_head->field.sle_height = floor(log(slist->slh_max_height) / M_LOG2E); \ + slist->slh_head->field.sle_height = 0; \ for (i = 0; i < slist->slh_max_height; i++) \ slist->slh_head->field.sle_levels[i].next = slist->slh_tail; \ slist->slh_head->field.sle_prev = NULL; \ @@ -555,18 +555,11 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li return; \ if (prefix##skip_is_empty_##decl(slist)) \ return; \ - node = prefix##skip_head_##decl(slist); \ - do { \ - next = prefix##skip_next_node_##decl(slist, node); \ + node = slist->slh_head->field.sle_levels[0].next; \ + while (node != slist->slh_tail) { \ + next = node->field.sle_levels[0].next; \ prefix##skip_free_node_##decl(slist, node); \ node = next; \ - } while (node != NULL); \ - \ - while (node) { \ - next = node->field.sle_levels[0].next; \ - if (next->field.sle_prev) \ - slist->slh_fns.free_entry(node); \ - free(node); \ } \ if (slist->slh_fns.snapshot_incr_era) \ slist->slh_fns.snapshot_incr_era(slist); \ @@ -589,7 +582,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li if (nodes != NULL) { \ nodes[0] = (decl##_node_t *)(uintptr_t)len; \ nodes++; \ - SKIPLIST_FOREACH_H2T(decl, prefix, slist, node, nth) \ + SKIPLIST_FOREACH_H2T(decl, prefix, field, slist, node, nth) \ { \ nodes[nth] = node; \ } \ @@ -773,7 +766,15 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li if (path == NULL) \ return ENOMEM; \ } \ - memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \ + /* First element in path should be NULL, reset should start pointing at tail. */ \ + path[0].node = NULL; \ + path[0].in = 0; \ + path[0].pu = 0; \ + for (i = 1; i < slist->slh_max_height + 1; i++) { \ + path[i].node = slist->slh_tail; \ + path[i].in = 0; \ + path[i].pu = 0; \ + } \ \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ len = __skip_locate_##decl(slist, new, path); \ @@ -785,21 +786,19 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li } \ /* Coin toss to determine level of this new node [0, max) */ \ cur_height = slist->slh_head->field.sle_height; \ - new_height = __skip_toss_##decl(slist->slh_max_height); \ + new_height = __skip_toss_##decl(slist->slh_max_height - 1); \ new->field.sle_height = new_height; \ /* Trim the path to at most the new height for the new node. */ \ - if (new_height > cur_height) { \ - for (i = cur_height + 1; i <= new_height; i++) { \ - path[i + 1].node = slist->slh_tail; \ - } \ + for (i = cur_height + 1; i <= new_height; i++) { \ + path[i + 1].node = slist->slh_tail; \ } \ /* Ensure all next[] point to tail. */ \ - __SKIP_ENTRIES_B2T(field, new) \ + __SKIP_ALL_ENTRIES_B2T(field, new) \ { \ new->field.sle_levels[lvl].next = slist->slh_tail; \ } \ /* Adjust all forward pointers for each element in the path. */ \ - for (i = 0; i <= new_height; i++) { \ + for (i = 0; i <= new_height; i++) { \ /* The tail's next[i] is always NULL, we don't want that in the \ next[i] for our new node. Also, don't set the tail's next[i] \ because it is always NULL. */ \ @@ -822,9 +821,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li new->field.sle_prev = path[1].node; \ new->field.sle_levels[0].next->field.sle_prev = new; \ /* Account for insert at tail. */ \ - if (new->field.sle_levels[0].next == slist->slh_tail) { \ + if (new->field.sle_levels[0].next == slist->slh_tail) \ slist->slh_tail->field.sle_prev = new; \ - } \ /* Adjust the head/tail boundary node heights if necessary. */ \ if (new_height > cur_height) { \ slist->slh_head->field.sle_height = new_height; \ @@ -1212,6 +1210,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li \ prefix##skip_release_##decl(slist); \ \ + if (slist->slh_fns.release_snapshots) \ + slist->slh_fns.release_snapshots(slist); \ + \ free(slist->slh_head); \ free(slist->slh_tail); \ } @@ -1380,7 +1381,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li cur_era = slist->slh_fns.snapshot_current_era(slist); \ \ /* (a) */ \ - SKIPLIST_FOREACH_H2T(decl, prefix, slist, node, i) \ + SKIPLIST_FOREACH_H2T(decl, prefix, field, slist, node, i) \ { \ ((void)i); \ if (node->field.sle_era > era) \ @@ -1704,12 +1705,14 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li if (flags) \ return n_err; \ } \ - if (node->field.sle_levels[lvl].next != slist->slh_tail) { \ - __skip_integrity_failure_##decl("after internal nodes, the head's %lu next node should always be the tail\n", lvl); \ - n_err++; \ - if (flags) \ - return n_err; \ - } \ + /* TODO: really? \ + if (node->field.sle_levels[lvl].next != slist->slh_tail) { \ + __skip_integrity_failure_##decl("after internal nodes, the head's %lu next node should always be the tail\n", lvl); \ + n_err++; \ + if (flags) \ + return n_err; \ + } \ + */ \ } \ \ if (slist->slh_length > 0 && slist->slh_tail->field.sle_prev == slist->slh_head) { \ @@ -1724,7 +1727,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li /* Validate the tail node */ \ \ /* Validate each node */ \ - SKIPLIST_FOREACH_H2T(decl, prefix, slist, node, nth) \ + SKIPLIST_FOREACH_H2T(decl, prefix, field, slist, node, nth) \ { \ this = &node->field; \ \ @@ -2154,7 +2157,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li /* Now all nodes via level 0, if non-empty */ \ node = slist->slh_head; \ if (letitgo) { \ - SKIPLIST_FOREACH_H2T(decl, prefix, slist, next, i) \ + SKIPLIST_FOREACH_H2T(decl, prefix, field, slist, next, i) \ { \ ((void)i); \ __skip_dot_node_##decl(os, slist, next, nsg, fn); \