Skip to content

Commit

Permalink
simple dynamic race detector for jl_array_to_string
Browse files Browse the repository at this point in the history
  • Loading branch information
d-netto committed Aug 20, 2024
1 parent ec21f11 commit bea69bc
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
28 changes: 28 additions & 0 deletions src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,13 +457,39 @@ JL_DLLEXPORT jl_array_t *jl_pchar_to_array(const char *str, size_t len)
return a;
}

JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT;

void jl_set_in_flight_bit_for_array_to_string(jl_array_t *a)
{
uintptr_t msk = (1 << ARRAY_TO_STRING_IN_FLIGHT_BIT_OFFSET);
uintptr_t header = jl_atomic_fetch_or((_Atomic(uintptr_t) *)jl_astaggedvalue(a), msk);
if (header & msk) {
// Race detected... Someone already set the in-flight bit.
jl_safe_printf("Race detected... Someone already set the in-flight bit.\n");
jl_print_task_backtraces(0);
}
}

void jl_reset_in_flight_bit_for_array_to_string(jl_array_t *a)
{
uintptr_t msk = (1 << ARRAY_TO_STRING_IN_FLIGHT_BIT_OFFSET);
uintptr_t header = jl_atomic_fetch_and((_Atomic(uintptr_t) *)jl_astaggedvalue(a), ~msk);
if (!(header & msk)) {
// Race detected... Someone reset the in-flight bit before we could.
jl_safe_printf("Race detected... Someone reset the in-flight bit before we could.\n");
jl_print_task_backtraces(0);
}
}

JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a)
{
jl_set_in_flight_bit_for_array_to_string(a);
size_t len = jl_array_len(a);
if (len == 0) {
// this may seem like purely an optimization (which it also is), but it
// also ensures that calling `String(a)` doesn't corrupt a previous
// string also created the same way, where `a = StringVector(_)`.
jl_reset_in_flight_bit_for_array_to_string(a);
return jl_an_empty_string;
}
if (a->flags.how == 3 && a->offset == 0 && a->elsize == 1 &&
Expand All @@ -476,11 +502,13 @@ JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a)
a->nrows = 0;
a->length = 0;
a->maxsize = 0;
jl_reset_in_flight_bit_for_array_to_string(a);
return o;
}
}
a->nrows = 0;
a->length = 0;
jl_reset_in_flight_bit_for_array_to_string(a);
return jl_pchar_to_string((const char*)jl_array_data(a), len);
}

Expand Down
6 changes: 5 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ typedef struct _jl_value_t jl_value_t;
struct _jl_taggedvalue_bits {
uintptr_t gc:2;
uintptr_t in_image:1;
uintptr_t unused:1;
// Bit to indicate whether a call to `jl_array_to_string` is in-flight
// Mostly used to implement a poor-man's dynamic race detector.
// See usage in `jl_array_to_string`.
#define ARRAY_TO_STRING_IN_FLIGHT_BIT_OFFSET (3)
uintptr_t array_to_string_in_flight:1;
#ifdef _P64
uintptr_t tag:60;
#else
Expand Down

0 comments on commit bea69bc

Please sign in to comment.