Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is is_dir() unreliable, or are there race conditions that can be mitigated here?

Tags:

At work, I've inherited a web application that has a file upload process. Part of this process occasionally (once every two weeks or so) triggers the following error:

PHP Warning:  mkdir(): File exists in {{{file_path_name_redacted}}} on line 7

Looking at lines 6-8, gives us:

if(!is_dir($storeFolder)){
    mkdir($storeFolder, 0644, TRUE);
}

Given this file can be hit by multiple PHP processes, I believe race conditions may be coming into play here. I've seen the same problem on other sites that I've managed in the past, similarly occurring only once in a blue moon.

What I believe is happening is that users are double-clicking on the upload button, which causes two PHP processes to execute at almost exactly the same time, like this:

Process 1 executes line 6 - dir does not exist
Process 2 executes line 6 - dir does not exist
Process 1 executes line 7 - directory is created
Process 2 executes line 7 - directory cannot be created as it already exists

Is this a case of race conditions, as I explained above (i.e. has anyone else noticed this), and/or is there some way of mitigating the error other turning off error reporting for warnings?

like image 680
e_i_pi Avatar asked Jun 02 '17 07:06

e_i_pi


People also ask

Can a race condition occur within a single process?

A race condition can only occur between two or more threads / external state (one of them can be the OS). We cannot have race conditions inside a single thread process, non I/O doing program.

What is a race condition in software?

A race condition occurs when two threads access a shared variable at the same time. The first thread reads the variable, and the second thread reads the same value from the variable.


1 Answers

Php inspections confirms that a race condition exists, and suggests that the safest way to write your code is:

if (!is_dir($dir) && !mkdir($dir) && !is_dir($dir)) {
        throw new \RuntimeException(sprintf('Directory "%s" could not be created', $dir));
    }

A bit more of explanation

It feels strange, but it certainly works. Best of luck.

like image 157
Hugues D Avatar answered Oct 11 '22 15:10

Hugues D