Skip to content

crashes when a printed context is shared across threads #2570

Description

@jeremie6wind

Hi,
Sometimes I come this crash while calling lyd_parse from several threads:

_lyht_insert_with_resize_cb at libyang/src/hash_table.c:406
ly_ctx_shared_data_pattern_get at libyang/src/ly_common.c:60
lyplg_type_validate_patterns at libyang/src/plugins_types.c:
lyplg_type_store_string at libyang/src/plugins_types/string.
union_store_type at libyang/src/plugins_types/union.c:279
union_find_type at libyang/src/plugins_types/union.c:348
lyplg_type_store_union at libyang/src/plugins_types/union.c:
lyd_value_store at libyang/src/tree_data_common.c:509 (discr
lyd_create_term at libyang/src/tree_data_new.c:73
lyd_parser_create_term at libyang/src/parser_common.c:212 (d
lydjson_parse_instance at libyang/src/parser_json.c:1476
lydjson_subtree_r at libyang/src/parser_json.c:1729
lydjson_parse_instance_inner at libyang/src/parser_json.c:13
lydjson_subtree_r at libyang/src/parser_json.c:1708
lydjson_parse_instance_inner at libyang/src/parser_json.c:13
lydjson_subtree_r at libyang/src/parser_json.c:1729
lyd_parse_json at libyang/src/parser_json.c:1952
lyd_parse at libyang/src/tree_data.c:130

Sometimes I get another backtrace with the same tool:

#1   in pcre2_match_data_create_8 () from /lib/x86_64-linux-gnu/libpcre2-8.so.0
#2   in ly_pat_match_xmlschema (pat_comp=0x7f03c000a1b0, pattern=0x0, str=0x7f03c000a190 "p0-value", str_len=8, err=0x7f03c7427328)
    at /build/libyang_upstream/src/ly_common.c:1124
#3   in ly_pat_match (pat_comp=0x7f03c000a1b0, pattern=0x0, format=0 '\000', str=0x7f03c000a190 "p0-value", str_len=8, err=0x7f03c7427328)
    at /build/libyang_upstream/src/ly_common.c:1168
#4   in lyplg_type_validate_patterns (ctx=0x7f03c842b000, patterns=0x7f03c8442238, str=0x7f03c000a190 "p0-value", str_len=8, 
#5   in lyplg_type_validate_value_string (ctx=0x7f03c842b000, type=0x7f03c8442200, storage=0x7f03c000a408, err=0x7f03c74274e0)
    at /build/libyang_upstream/src/plugins_types/string.c:137
#6   in lyplg_type_store_string (ctx=0x7f03c842b000, type=0x7f03c8442200, value=0x7f03c000a1d2, value_size_bits=64, options=4, 
    format=LY_VALUE_JSON, UNUSED_prefix_data=0x0, hints=17, UNUSED_ctx_node=0x7f03c8442180, storage=0x7f03c000a408, UNUSED_unres=0x0, err=0x7f03c74274e0)
    at /build/libyang_upstream/src/plugins_types/string.c:100
#7   in lyd_value_store (ctx=0x7f03c842b000, lnode=0x7f03c000a380, val=0x7f03c000a408, type=0x7f03c8442200, value=0x7f03c000a1d2, 
    value_size_bits=64, is_utf8=1 '\001', store_only=0 '\000', dynamic=0x7f03c000a2ac "", format=LY_VALUE_JSON, prefix_data=0x0, hints=17, 
    ctx_snode=0x7f03c8442180, incomplete=0x7f03c742760e "") at /build/libyang_upstream/src/tree_data_common.c:511
#8  0x00007f03c882479c in lyd_create_term (schema=0x7f03c8442180, lnode=0x7f03c000a380, value=0x7f03c000a1d2, value_size_bits=64, is_utf8=1 '\001', 
    store_only=0 '\000', dynamic=0x7f03c000a2ac "", format=LY_VALUE_JSON, prefix_data=0x0, hints=17, incomplete=0x7f03c742760e "", node=0x7f03c74277c8)
    at /build/libyang_upstream/src/tree_data_new.c:71
#9  0x00007f03c889e546 in lyd_parser_create_term (lydctx=0x7f03c0008e60, schema=0x7f03c8442180, lnode=0x7f03c000a380, value=0x7f03c000a1d2, 
    value_size_bits=64, dynamic=0x7f03c000a2ac "", format=LY_VALUE_JSON, prefix_data=0x0, hints=17, node=0x7f03c74277c8)
    at /build/libyang_upstream/src/parser_common.c:212
#10 0x00007f03c88365f1 in lydjson_parse_instance_term (lydctx=0x7f03c0008e60, snode=0x7f03c8442180, ext=0x0, type_hints=17, parent=0x7f03c000a380, 
    first_p=0x7f03c000a3b8, status=0x7f03c7427794, node=0x7f03c74277c8) at /build/libyang_upstream/src/parser_json.c:1517
#11 0x00007f03c8836898 in lydjson_parse_instance (lydctx=0x7f03c0008e60, parent=0x7f03c000a380, first_p=0x7f03c000a3b8, snode=0x7f03c8442180, ext=0x0, 
    name=0x7f03c000a1cc "p0\": \"p0-value\",   \"p1\": \"p1-value\",   \"p2\": \"p2-value\",   \"p3\": \"p3-value\" } }", name_len=2, prefix=0x0, 
    prefix_len=0, status=0x7f03c7427794, node=0x7f03c74277c8) at /build/libyang_upstream/src/parser_json.c:1580
#12 0x00007f03c88378e9 in lydjson_subtree_r (lydctx=0x7f03c0008e60, parent=0x7f03c000a380, first_p=0x7f03c000a3b8, parsed=0x0)
    at /build/libyang_upstream/src/parser_json.c:1822
#13 0x00007f03c88362c6 in lydjson_parse_instance_inner (lydctx=0x7f03c0008e60, snode=0x7f03c8442108, ext=0x0, parent=0x0, first_p=0x7f03c7427c68, 
    status=0x7f03c74279a4, node=0x7f03c74279d8) at /build/libyang_upstream/src/parser_json.c:1452
#14 0x00007f03c8836949 in lydjson_parse_instance (lydctx=0x7f03c0008e60, parent=0x0, first_p=0x7f03c7427c68, snode=0x7f03c8442108, ext=0x0, 
    name=0x7f03c000a1c1 "top\": {   \"p0\": \"p0-value\",   \"p1\": \"p1-value\",   \"p2\": \"p2-value\",   \"p3\": \"p3-value\" } }", name_len=3, 
    prefix=0x7f03c000a1b4 "test-pattern:top\": {   \"p0\": \"p0-value\",   \"p1\": \"p1-value\",   \"p2\": \"p2-value\",   \"p3\": \"p3-value\" } }", 
    prefix_len=12, status=0x7f03c74279a4, node=0x7f03c74279d8) at /build/libyang_upstream/src/parser_json.c:1584
#15 0x00007f03c88378e9 in lydjson_subtree_r (lydctx=0x7f03c0008e60, parent=0x0, first_p=0x7f03c7427c68, parsed=0x7f03c7427b50)
    at /build/libyang_upstream/src/parser_json.c:1822
#16 0x00007f03c883820c in lyd_parse_json (ctx=0x7f03c842b000, parent=0x0, schema=0x0, first_p=0x7f03c7427c68, in=0x7f03c000a230, parse_opts=131072, 
    val_opts=2, int_opts=32, parsed=0x7f03c7427b50, lydctx_p=0x7f03c7427b40) at /build/libyang_upstream/src/parser_json.c:2047
#17 0x00007f03c8810066 in lyd_parse (ctx=0x7f03c842b000, parent=0x0, first_p=0x7f03c7427c68, in=0x7f03c000a230, format=LYD_JSON, parse_opts=131072, 

I could reproduce it with the attached sample:

/*
 * pattern_ht_race_repro.c
 *
 gcc -I/usr/local/include/libyang -O0 -g -Wall -o pattern_ht_race_repro pattern_ht_race_repro.c       $(pkg-config --cflags --libs libyang) -lpthread
 */

#define _GNU_SOURCE
#include <libyang.h>

#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

#define N_THREADS   5
#define N_ITERS     5

static void *printed_mem;

static char *
build_yang(void)
{

    return strdup("module test-pattern { \
  yang-version 1.1; \
  namespace \"urn:test:pattern\"; \
  prefix tp; \
  container top { \
    leaf p0 { type string { pattern \"p0-.*\"; } } \
    leaf p1 { type string { pattern \"p1-.*\"; } } \
    leaf p2 { type string { pattern \"p2-.*\"; } } \
    leaf p3 { type string { pattern \"p3-.*\"; } } \
  } \
}");
}

static char *
build_data(void)
{
    return strdup(" \
{ \"test-pattern:top\": { \
  \"p0\": \"p0-value\", \
  \"p1\": \"p1-value\", \
  \"p2\": \"p2-value\", \
  \"p3\": \"p3-value\" \
} }");
}

static void *
worker(void *arg)
{
    int tid = (int)(intptr_t)arg;
    struct ly_ctx *ctx = NULL;

    if (ly_ctx_new_printed(printed_mem, &ctx)) {
	    fprintf(stderr, "[thread %d] ly_ctx_new_printed failed\n", tid);
	    goto error;
    }

    for (int iter = 0; iter < N_ITERS; ++iter) {
        struct lyd_node *tree = NULL;
        char *data = build_data();
        LY_ERR rc;

        rc = lyd_parse_data_mem(ctx, data, LYD_JSON, LYD_PARSE_STRICT,
                LYD_VALIDATE_PRESENT, &tree);
        if (rc) {
            fprintf(stderr, "[thread %d] parse error %d\n", tid, rc);
        }

        lyd_free_all(tree);
        free(data);
    }

error:
    ly_ctx_destroy(ctx);
    return NULL;
}

int
main(void)
{
    struct ly_ctx *base_ctx = NULL;
    struct lys_module *mod = NULL;
    char *yang = build_yang();
    pthread_t threads[N_THREADS];
    int size;

    const char *modules_dir = getenv("LY_MODULES_DIR");
    if (!modules_dir) {
        return 1;
    }
    fprintf(stderr, "Using YANG modules search directory: %s\n", modules_dir);

    if (ly_ctx_new(modules_dir, LY_CTX_STATIC_PLUGINS_ONLY, &base_ctx)) {
        fprintf(stderr, "ly_ctx_new failed\n");
        return 1;
    }
    if (lys_parse_mem(base_ctx, yang, LYS_IN_YANG, &mod)) {
        fprintf(stderr, "lys_parse_mem failed\n");
        return 1;
    }
    free(yang);

    size = ly_ctx_compiled_size(base_ctx);
    if (size < 0) {
        fprintf(stderr, "ly_ctx_compiled_size failed\n");
        return 1;
    }

    printed_mem = mmap(NULL, (size_t)size, PROT_READ | PROT_WRITE,
            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (printed_mem == MAP_FAILED) {
        perror("mmap");
        return 1;
    }

    if (ly_ctx_compiled_print(base_ctx, printed_mem, NULL)) {
        fprintf(stderr, "ly_ctx_compiled_print failed\n");
        return 1;
    }

    for (int i = 0; i < N_THREADS; ++i) {
        pthread_create(&threads[i], NULL, worker, (void *)(intptr_t)i);
    }
    for (int i = 0; i < N_THREADS; ++i) {
        pthread_join(threads[i], NULL);
    }

    ly_ctx_destroy(base_ctx);

    return 0;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions