Skip to content

libFuzzer's runtime argument -stop_file doesn't work with empty files #72334

Open
@markszabo

Description

@markszabo

libFuzzer has a runtime argument -stop-file with this description:

stop_file: "Stop fuzzing ASAP if this file exists"

However fuzzing only stops if the file exists and has some content. If the file is empty, the fuzzing continues.

Steps to reproduce

  1. Create a simple fuzz test, e.g.

    #include <fuzzer/FuzzedDataProvider.h>
    #include <assert.h>
    
    extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
    {
        FuzzedDataProvider provider(data, size);
        int a = provider.ConsumeIntegral<int>();
        int b = provider.ConsumeIntegral<int>();
    
        assert(a+b == b+a);
    
        return 0;
    }

    Save it as test.cpp

  2. Compile the test

    clang++ -g -fsanitize=address,fuzzer test.cpp -o test
  3. Run the resulting binary with the -stop_file argument:

    ./test -stop_file=/tmp/stop-file
  4. In a separate terminal create the stop-file as an empty file:

    touch /tmp/stop-file

    Observe that the fuzzing run continues.

  5. Create a file with some content:

    rm /tmp/stop-file # optional
    echo abc > /tmp/stop-file

    Observe that the fuzzing stops quickly with a message like Done 5036370 runs in 21 second(s).

Expected behavior

Either the flag description should say that the file can't be empty, or fuzzing should stop even if the file is empty.

Potential cause of the issue

I believe this is the part of the code that stops the fuzzing loop if the file exists:

    if (!Options.StopFile.empty() &&
        !FileToVector(Options.StopFile, 1, false).empty())
      break;

FileToVector() is implemented here:

Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
  std::ifstream T(Path, std::ios::binary);
  if (ExitOnError && !T) {
    Printf("No such directory: %s; exiting\n", Path.c_str());
    exit(1);
  }

  T.seekg(0, T.end);
  auto EndPos = T.tellg();
  if (EndPos < 0) return {};
  size_t FileLen = EndPos;
  if (MaxSize)
    FileLen = std::min(FileLen, MaxSize);

  T.seekg(0, T.beg);
  Unit Res(FileLen);
  T.read(reinterpret_cast<char *>(Res.data()), FileLen);
  return Res;
}

This returns {} if the file doesn't exist, but also if the file is empty, leading to this behavior.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions