Skip to content

Possible race condition if 2 calls write to the same file #13

@Soulike

Description

@Soulike

I think there is a race condition when 2 write() calls write to the same file at almost the same time, like the test case below:

const targetFile = path.join(os.tmpdir(), 'test.txt');

fs.rmSync(targetFile, {force: true});

const content1 = Buffer.alloc(100 * 1024 * 1024); // A will finish writing later than B
const content2 = Buffer.alloc(50 * 1024 * 1024);

crypto.randomFillSync(content1);
crypto.randomFillSync(content2);

process.on('uncaughtException', (e) =>
{
    console.error(e);
});

process.on('beforeExit', () =>
{
    fs.rmSync(targetFile, {force: true});
});

// A
write(targetFile, content1, {overwrite: true}, err =>
{
    if (err)
    {
        console.error(err);
    }
    else
    {
        const targetContent = fs.readFileSync(targetFile);
        assert.ok(targetContent.equals(content1), `The content of targetFile is not content1!`);
    }
});


// B
write(targetFile, content2, {overwrite: true}, err =>
{
    if (err)
    {
        console.error(err);
    }
    else
    {
        const targetContent = fs.readFileSync(targetFile);
        assert.ok(targetContent.equals(content2), `The content of targetFile is not content2!`);
    }
});

And the execution result is:

AssertionError [ERR_ASSERTION]: The content of targetFile is not content2!
...
AssertionError [ERR_ASSERTION]: The content of targetFile is not content1!
...

targetFile may become a corrupted file with content different from either content1 or content2.

I think the bug is caused by the use of stream:

write/index.js

Lines 58 to 61 in f537eb6

fs.createWriteStream(destpath, opts)
.on('error', err => reject(err))
.on('close', resolve)
.end(ensureNewline(data, opts));

Both A and B can create write streams and write to targetFile at the same time. I think write() should check whether a file is being written before writing to it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions