Opened 7 years ago

Last modified 4 years ago

#11873 new Bugs

boost::filesystem does not work on windows when multiple processes access the same junction (directory)

Reported by: stsoe <stsoe@…> Owned by: Beman Dawes
Milestone: To Be Determined Component: filesystem
Version: Boost 1.64.0 Severity: Regression
Keywords: symlink, junction, windows Cc:

Description

Hi,

I just upgraded to boost_1_60_0 ran into a regression on windows only, which I think is related to issue 9016. My windows tests are failing sporadically with the error:

boost::filesystem::read_symlink: The process cannot access the file because it is being used by another process: "r:/data"

Debugging this by comparing 1_60_0 to the earlier 1_56_0 I finally narrowed the difference to operations.cpp: bool is_reparse_point_a_symlink, which returns true in 1_60_0 but false in 1_56_0. The return value triggers canonical to call detail::read_symlink, which in turn ends up calling ::CreateFileW with dwShareMode set to 0 so that the file/directory is locked and cannot be opened by another process.

I am running my tests on LSF and many many processes end up accessing the same file / directory at the same time, thus leading the the above error message.

I have not debugged enough to be able to suggest a fix or a work-around, but this bug currently prevents me from upgrading to boost_1_60_0. I am thinking that I can maybe revert the change to is_reparse_point_a_symlink in my installation so I can proceed with the upgrade, but I am worried that other changes have been made that depend on the current behavior.

Thanks,

Soren Soe

Change History (4)

comment:1 by stsoe <stsoe@…>, 7 years ago

Version: Boost 1.61.0Boost 1.60.0

comment:2 by emenchen@…, 4 years ago

This problem still exists in 1.64. Make a link in Windows, and pass a path that includes the link to testBoost in the following:

std::atomic<int> boostResult(0);

void boostThread(const std::string& _path) 
{
  try {
    boost::filesystem::path boostPath(_path);
    boost::filesystem::path canonicalFile = boost::filesystem::canonical(boostPath);
    std::string canonicalPath = canonicalFile.string();
    //std::cout << "canonicalPath: " << canonicalPath << std::endl;
  } catch (boost::filesystem::filesystem_error &e) {
    std::cerr << e.what() << ", failed to resolve path" << std::endl;
    ++boostResult;
  } catch (std::exception &e) {
    std::cerr << e.what() << ", failed to resolve path" << std::endl;
    ++boostResult;
  }
}

int testBoost(const std::string& _path)
{
  std::cout << "Testing path: " << _path << std::endl;

  static const int numThreads(100);
  std::thread t[numThreads];

  for (int i = 0; i < numThreads; ++i)
    t[i] = std::thread(boostThread, _path);

  for (int i = 0; i < numThreads; ++i)
    t[i].join();

  std::cout << "Boost result: " << boostResult << std::endl;
  return boostResult;
}

I did 5 runs and had between 8 and 14 failures each time.

comment:3 by anonymous, 4 years ago

Version: Boost 1.60.0Boost 1.64.0

comment:4 by emenchen@…, 4 years ago

And the code is the same in 1.67 as well.

Note: See TracTickets for help on using tickets.