tree schema BUGFIX atomic refcount for types

They may be modified concurrently if creating/
freeing data values that reference them such
as instance-identifiers.

Fixes sysrepo/sysrepo#2553
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 54f14fa..cb10798 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -306,6 +306,9 @@
     source_format_enable()
 endif()
 
+# duplicate compat check, to be placed in config.h
+check_include_file("stdatomic.h" HAVE_STDATOMIC)
+
 # generate files
 configure_file(${PROJECT_SOURCE_DIR}/src/config.h.in ${PROJECT_BINARY_DIR}/src/config.h @ONLY)
 configure_file(${PROJECT_SOURCE_DIR}/src/version.h.in ${PROJECT_BINARY_DIR}/src/version.h @ONLY)
diff --git a/src/config.h.in b/src/config.h.in
index a6aff60..41e1942 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -18,14 +18,24 @@
 /** size of fixed_mem in lyd_value, minimum is 8 (B) */
 #define LYD_VALUE_FIXED_MEM_SIZE @LYD_VALUE_SIZE@
 
-/*
- * Plugins
- */
+/** plugins */
 #define LYPLG_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@"
 #define LYPLG_SUFFIX_LEN (sizeof LYPLG_SUFFIX - 1)
 #define LYPLG_TYPE_DIR "@PLUGINS_DIR_EXTENSIONS@"
 #define LYPLG_EXT_DIR "@PLUGINS_DIR_TYPES@"
 
+/** atomic variables type similar to compat.h */
+#cmakedefine HAVE_STDATOMIC
+
+#ifdef HAVE_STDATOMIC
+# include <stdatomic.h>
+# define LY_ATOMIC_T atomic_uint_fast32_t
+#else
+# include <stdint.h>
+# define LY_ATOMIC_T uint32_t
+#endif
+
+/** printf compiler attribute */
 #if (@CMAKE_C_COMPILER_ID@ == GNU) || (@CMAKE_C_COMPILER_ID@ == Clang)
 # define _FORMAT_PRINTF(FORM, ARGS) __attribute__((format (printf, FORM, ARGS)))
 #else
diff --git a/src/path.c b/src/path.c
index 94f3d21..3d269f8 100644
--- a/src/path.c
+++ b/src/path.c
@@ -552,7 +552,7 @@
             ++(*tok_idx);
 
             /* "allocate" the type to avoid problems when freeing the value after the type was freed */
-            ++((struct lysc_type *)p->value.realtype)->refcount;
+            ATOMIC_INC_RELAXED(((struct lysc_type *)p->value.realtype)->refcount);
 
             /* ']' */
             assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
@@ -613,7 +613,7 @@
         ++(*tok_idx);
 
         /* "allocate" the type to avoid problems when freeing the value after the type was freed */
-        ++((struct lysc_type *)p->value.realtype)->refcount;
+        ATOMIC_INC_RELAXED(((struct lysc_type *)p->value.realtype)->refcount);
 
         /* ']' */
         assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2);
@@ -1105,7 +1105,7 @@
                     /* key-predicate or leaf-list-predicate */
                     (*dup)[u].predicates[v].key = pred->key;
                     pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value);
-                    ++((struct lysc_type *)pred->value.realtype)->refcount;
+                    ATOMIC_INC_RELAXED(((struct lysc_type *)pred->value.realtype)->refcount);
                     break;
                 case LY_PATH_PREDTYPE_NONE:
                     break;
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 8b8c93f..6883b19 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -1067,7 +1067,7 @@
         return ret;
     }
 
-    ++((struct lysc_type *)storage->realtype)->refcount;
+    ATOMIC_INC_RELAXED(((struct lysc_type *)storage->realtype)->refcount);
     return LY_SUCCESS;
 }
 
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 2afc4f6..812d263 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -1424,7 +1424,7 @@
                     lref->basetype = LY_TYPE_LEAFREF;
                     ret = lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)un_aux->types[v])->path, &lref->path);
                     LY_CHECK_GOTO(ret, error);
-                    lref->refcount = 1;
+                    ATOMIC_STORE_RELAXED(lref->refcount, 1);
                     lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
                     ret = lyplg_type_prefix_data_dup(ctx->ctx, LY_VALUE_SCHEMA_RESOLVED,
                             ((struct lysc_type_leafref *)un_aux->types[v])->prefixes, (void **)&lref->prefixes);
@@ -1433,7 +1433,7 @@
 
                 } else {
                     utypes[u + additional] = un_aux->types[v];
-                    ++un_aux->types[v]->refcount;
+                    ATOMIC_INC_RELAXED(un_aux->types[v]->refcount);
                 }
                 ++additional;
                 LY_ARRAY_INCREMENT(utypes);
@@ -1869,7 +1869,7 @@
             break;
         }
 
-        if (tctx->tpdf->type.compiled && (tctx->tpdf->type.compiled->refcount == 1)) {
+        if (tctx->tpdf->type.compiled && (ATOMIC_LOAD_RELAXED(tctx->tpdf->type.compiled->refcount) == 1)) {
             /* context recompilation - everything was freed previously (the only reference is from the parsed type itself)
              * and we need now recompile the type again in the updated context. */
             lysc_type_free(ctx->ctx, tctx->tpdf->type.compiled);
@@ -2009,11 +2009,11 @@
                 (plugin == base->plugin)) {
             /* no change, reuse the compiled base */
             ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = base;
-            ++base->refcount;
+            ATOMIC_INC_RELAXED(base->refcount);
             continue;
         }
 
-        ++(*type)->refcount;
+        ATOMIC_INC_RELAXED((*type)->refcount);
         if (~type_substmt_map[basetype] & tctx->tpdf->type.flags) {
             LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid type \"%s\" restriction(s) for %s type.",
                     tctx->tpdf->name, ly_data_type2str[basetype]);
@@ -2048,14 +2048,14 @@
         /* get restrictions from the node itself */
         (*type)->basetype = basetype;
         (*type)->plugin = base ? base->plugin : lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
-        ++(*type)->refcount;
+        ATOMIC_INC_RELAXED((*type)->refcount);
         ret = lys_compile_type_(ctx, context_pnode, context_flags, context_name, type_p, basetype, NULL, base, type);
         LY_CHECK_GOTO(ret, cleanup);
     } else if ((basetype != LY_TYPE_BOOL) && (basetype != LY_TYPE_EMPTY)) {
         /* no specific restriction in leaf's type definition, copy from the base */
         free(*type);
         (*type) = base;
-        ++(*type)->refcount;
+        ATOMIC_INC_RELAXED((*type)->refcount);
     }
 
     COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), ret, cleanup);
diff --git a/src/tree_schema.h b/src/tree_schema.h
index be95005..4b58017 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -22,6 +22,7 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include "config.h"
 #include "log.h"
 #include "tree.h"
 
@@ -1530,14 +1531,15 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing, it may be accessed concurrently when
+                                          creating/freeing data node values that reference it (instance-identifier) */
 };
 
 struct lysc_type_num {
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lysc_range *range;        /**< Optional range limitation */
 };
 
@@ -1545,7 +1547,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     uint8_t fraction_digits;         /**< fraction digits specification */
     struct lysc_range *range;        /**< Optional range limitation */
 };
@@ -1554,7 +1556,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lysc_range *length;       /**< Optional length limitation */
     struct lysc_pattern **patterns;  /**< Optional list of pointers to pattern limitations ([sized array](@ref sizedarrays)) */
 };
@@ -1576,7 +1578,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lysc_type_bitenum_item *enums; /**< enumerations list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
 };
 
@@ -1584,7 +1586,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lysc_type_bitenum_item *bits; /**< bits list ([sized array](@ref sizedarrays)), mandatory (at least 1 item),
                                               the items are ordered by their position value. */
 };
@@ -1593,7 +1595,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lyxp_expr *path;          /**< parsed target path, compiled path cannot be stored because of type sharing */
     struct lysc_prefix *prefixes;    /**< resolved prefixes used in the path */
     const struct lys_module *cur_mod;/**< unused, not needed */
@@ -1605,7 +1607,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lysc_ident **bases;       /**< list of pointers to the base identities ([sized array](@ref sizedarrays)),
                                           mandatory (at least 1 item) */
 };
@@ -1614,7 +1616,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     uint8_t require_instance;        /**< require-instance flag */
 };
 
@@ -1622,7 +1624,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lysc_type **types;        /**< list of types in the union ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
 };
 
@@ -1630,7 +1632,7 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     struct lyplg_type *plugin;       /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
-    uint32_t refcount;               /**< reference counter for type sharing */
+    LY_ATOMIC_T refcount;            /**< reference counter for type sharing */
     struct lysc_range *length;       /**< Optional length limitation */
 };
 
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index be848ce..1f2d9d3 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -666,7 +666,7 @@
 void
 lysc_type_free(struct ly_ctx *ctx, struct lysc_type *type)
 {
-    if (--type->refcount) {
+    if (ATOMIC_DEC_RELAXED(type->refcount) > 1) {
         return;
     }