ocaml-tsan icon indicating copy to clipboard operation
ocaml-tsan copied to clipboard

String initialization is instrumented, leading to false positives

Open OlivierNicole opened this issue 2 years ago • 0 comments

How to reproduce

let table = Hashtbl.create 64

let read_table () =
  for _ = 0 to 99 do
    let key = QCheck.Gen.(generate1 small_string) in
    try ignore (Hashtbl.find table key) with Not_found -> ()
  done

let record_new_clients () =
  for _ = 0 to 99 do
    let key = QCheck.Gen.(generate1 small_string) in
    let v = QCheck.Gen.(generate1 small_nat) in
    Hashtbl.add table key v
  done

let () =
  let d = Domain.spawn read_table in
  record_new_clients ();
  Domain.join d

Build with

$ cat dune
(executable
 (name race)
 (libraries qcheck-core))
$ dune exec ./race.exe

You get reports like:

==================
WARNING: ThreadSanitizer: data race (pid=4184815)
  Read of size 1 at 0x7f0879dee8cf by thread T1 (mutexes: write M90):
    #0 caml_string_length runtime/str.c:36 (race.exe+0x596e71)
    #1 do_compare_val runtime/compare.c:221 (race.exe+0x56aafb)
    #2 compare_val runtime/compare.c:98 (race.exe+0x56aafb)
    #3 caml_compare runtime/compare.c:345 (race.exe+0x56ae75)
    #4 caml_c_call <null> (race.exe+0x5a09fb)
    #5 camlStdlib__Hashtbl.find_1339 /home/olivier/compiler/tsan/stdlib/hashtbl.ml:552 (race.exe+0x53af11)
    #6 camlDune__exe__Race.read_table_352 /workspace_root/race.ml:6 (race.exe+0x464ec0)
    #7 camlStdlib__Domain.body_703 /home/olivier/compiler/tsan/stdlib/domain.ml:202 (race.exe+0x50bf80)
    #8 caml_start_program <null> (race.exe+0x5a0af7)
    #9 caml_callback_exn runtime/callback.c:197 (race.exe+0x56919b)
    #10 caml_callback runtime/callback.c:293 (race.exe+0x569cd0)
    #11 domain_thread_func runtime/domain.c:1100 (race.exe+0x56d39f)

  Previous write of size 8 at 0x7f0879dee8c8 by main thread (mutexes: write M86):
    #0 __tsan_volatile_write8 runtime/tsan.c:239 (race.exe+0x59af35)
    #1 caml_alloc_string runtime/alloc.c:179 (race.exe+0x560fc5)
    #2 caml_create_bytes runtime/str.c:78 (race.exe+0x596fc7)
    #3 caml_c_call <null> (race.exe+0x5a09fb)
    #4 camlQCheck.bytes_size_inner_5638 src/core/QCheck.ml:369 (race.exe+0x48ffe5)
    #5 camlQCheck.string_size_inner_5644 src/core/QCheck.ml:376 (race.exe+0x4901dc)
    #6 camlDune__exe__Race.record_new_clients_579 /workspace_root/race.ml:11 (race.exe+0x464f9d)
    #7 camlDune__exe__Race.entry /workspace_root/race.ml:18 (race.exe+0x465118)
    #8 caml_program <null> (race.exe+0x45fefe)
    #9 caml_start_program <null> (race.exe+0x5a0af7)
    #10 caml_startup_common runtime/startup_nat.c:132 (race.exe+0x5a0332)
    #11 caml_startup_common runtime/startup_nat.c:88 (race.exe+0x5a0332)
    #12 caml_startup_exn runtime/startup_nat.c:139 (race.exe+0x5a0367)
    #13 caml_startup runtime/startup_nat.c:144 (race.exe+0x5a0395)
    #14 caml_main runtime/startup_nat.c:151 (race.exe+0x5a03d5)
    #15 main runtime/main.c:37 (race.exe+0x45f915)

  Mutex M90 (0x000000672960) created at:
    #0 pthread_mutex_init <null> (libtsan.so.2+0x54bc8)
    [...]

SUMMARY: ThreadSanitizer: data race runtime/str.c:36 in caml_string_length
==================

Reads in the string conflict with a write made during the initialization. These operations should in reality be ordered due to data dependencies (note for future me: can you explain this more precisely?). But data dependencies are not part of C11 and TSan will report a race here.

To avoid this specific instance of false positive, as with other publication safety issues, the initializing writes should be un-instrumented.

OlivierNicole avatar May 26 '23 10:05 OlivierNicole