Skip to content

<atomic>: Tearing of 64-bit atomic on 32-bit x86 target when compiling with clang-cl #5705

@AlexGuteniev

Description

@AlexGuteniev

Describe the bug

Originally reported as DevCom-10958910

On 32-bit x86 build, atomic<(u)int64_t> load/store sequence produces unexpected results.

Command-line test case

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.14.13-pre.1.0
** Copyright (c) 2025 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x86'

C:\Program Files\Microsoft Visual Studio\2022\Preview>cd %temp%

C:\Users\ALEXG~1\AppData\Local\Temp>type repro.cpp
#include <iostream>
#include <iostream>
#include <atomic>
#include <thread>

struct mre_example {
  struct data_t {
    alignas(std::hardware_destructive_interference_size) std::atomic<int64_t> atomical{0};
  };
  data_t* data_ptr;
  std::thread reader_thread;
  std::thread writer_thread;

mre_example() {
    data_ptr = static_cast<data_t *>(_aligned_malloc(sizeof(data_t), 1024));
    new (data_ptr) data_t;
    reader_thread = std::thread(&reader, data_ptr);
    writer_thread = std::thread(&writer, data_ptr);
  }

~mre_example() {
    reader_thread.join();
    writer_thread.join();
    _aligned_free(data_ptr);
  }

static void writer(data_t* data_ptr) {
    auto& data = *data_ptr;
    int64_t my_local = 0;
    while (true) {
      my_local += 100;
      if ((my_local % 100) != 0) {
        std::cout << "my_local is somehow broken: " << my_local << std::endl;
        my_local = 0;
      }
      data.atomical.store(my_local, std::memory_order_release);
    }
  }

static void reader(data_t* data_ptr) {
    auto& data = *data_ptr;
    while (true) {
      auto red_atomical = data.atomical.load(std::memory_order_acquire);
      if ((red_atomical % 100) != 0) {
        std::cout << "red_atomical is broken: " << red_atomical << std::endl;
        std::terminate();
      }
    }
  }
};

int main() {
  mre_example m1;
  mre_example m2;
  mre_example m3;

return 0;
}
C:\Users\ALEXG~1\AppData\Local\Temp>clang-cl /std:c++20 /O2 /MT repro.cpp

C:\Users\ALEXG~1\AppData\Local\Temp>repro.exe
red_atomical is broken: 8589933396

Expected behavior

The program should loop forever or until 64-bit integer overflows

STL version

Version 17.14.13 Preview 1.0

Additional context

  • Clang bug reported as LLVM-156228
  • Workaround using other instirisics or inline assembly may be possible, but may be not worth doing

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcompilerCompiler work involvedfixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions