Coverage Report

Created: 2026-05-16 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/library-fuzzers/fuzzer.cpp
Line
Count
Source
1
#include <climits>
2
#include <cstdlib>
3
#include <iomanip>
4
#include <libgen.h>
5
#include <vector>
6
#include <string>
7
#include <optional>
8
#include <Python.h>
9
10
#ifndef PYTHON_HARNESS_PATH
11
#error "Define PYTHON_HARNESS_PATH"
12
#endif
13
14
#define PY_SSIZE_T_CLEAN
15
#include <Python.h>
16
17
74
static std::string ToAbsolutePath(const std::string argv0, const std::string relativePath) {
18
74
    char absoluteRootPath[PATH_MAX+1];
19
74
    char argv0Copy[argv0.size()+1];
20
74
    memcpy(argv0Copy, argv0.c_str(), argv0.size()+1);
21
74
    if ( realpath(dirname(argv0Copy), absoluteRootPath) == nullptr ) {
22
0
        printf("Fatal error: Cannot resolve absolute root path\n");
23
0
        abort();
24
0
    }
25
26
74
    return std::string(std::string(absoluteRootPath) + "/" + relativePath);
27
74
}
28
29
void* pFunc = nullptr;
30
37
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
31
37
    const std::string argv0 = (*argv)[0];
32
33
37
    const std::string absoluteCPythonInstallPath = ToAbsolutePath(argv0, "cpython-install");
34
37
    const std::string absoluteScriptPath = ToAbsolutePath(argv0, PYTHON_HARNESS_PATH);
35
36
37
    std::vector<uint8_t> program;
37
38
37
    {
39
37
        if ( setenv("PYTHONHOME", absoluteCPythonInstallPath.c_str(), 1) != 0 ) {
40
0
            printf("Fatal error: Cannot set PYTHONHOME\n");
41
0
            abort();
42
0
        }
43
37
    }
44
45
37
    FILE* fp = fopen(absoluteScriptPath.c_str(), "rb");
46
37
    if ( fp == nullptr ) {
47
0
        printf("Fatal error: Cannot open script: %s\n", absoluteScriptPath.c_str());
48
0
        abort();
49
0
    }
50
51
37
    fseek (fp, 0, SEEK_END);
52
37
    long length = ftell(fp);
53
37
    if ( length < 1 ) {
54
0
        printf("Fatal error: Cannot retrieve script file size\n");
55
0
        abort();
56
0
    }
57
37
    fseek (fp, 0, SEEK_SET);
58
37
    program.resize(length);
59
37
    if ( fread(program.data(), 1, length, fp) != static_cast<size_t>(length) ) {
60
0
        printf("Fatal error: Cannot read script\n");
61
0
        abort();
62
0
    }
63
37
    fclose(fp);
64
65
37
    std::string code = std::string(program.data(), program.data() + program.size());
66
67
37
    Py_Initialize();
68
69
37
    {
70
37
        std::string setArgv0;
71
37
        setArgv0 += "import sys";
72
37
        setArgv0 += "\n";
73
37
        setArgv0 += "sys.argv[0] = '" + absoluteScriptPath + "'\n";
74
37
        if ( PyRun_SimpleString(setArgv0.c_str()) != 0 ) {
75
0
            printf("Fatal: Cannot set argv[0]\n");
76
0
            PyErr_PrintEx(1);
77
0
            abort();
78
0
        }
79
37
    }
80
81
37
    {
82
37
        const std::string absoluteScriptDir = absoluteScriptPath.substr(0, absoluteScriptPath.find_last_of('/'));
83
37
        std::string setPYTHONPATH;
84
37
        setPYTHONPATH += "import sys";
85
37
        setPYTHONPATH += "\n";
86
37
        setPYTHONPATH += "sys.path.append('" + absoluteScriptDir + "')\n";
87
37
        setPYTHONPATH += "\n";
88
37
        if ( PyRun_SimpleString(setPYTHONPATH.c_str()) != 0 ) {
89
0
            printf("Fatal: Cannot set PYTHONPATH\n");
90
0
            PyErr_PrintEx(1);
91
0
            abort();
92
0
        }
93
37
    }
94
95
37
    PyObject *pValue, *pModule, *pLocal;
96
97
37
    pModule = PyModule_New("fuzzermod");
98
37
    PyModule_AddStringConstant(pModule, "__file__", "");
99
37
    pLocal = PyModule_GetDict(pModule);
100
37
    pValue = PyRun_String(code.c_str(), Py_file_input, pLocal, pLocal);
101
102
37
    if ( pValue == nullptr ) {
103
0
        printf("Fatal: Cannot create Python function from string\n");
104
0
        PyErr_PrintEx(1);
105
0
        abort();
106
0
    }
107
37
    Py_DECREF(pValue);
108
109
37
    pFunc = PyObject_GetAttrString(pModule, "FuzzerRunOne");
110
111
37
    if (pFunc == nullptr || !PyCallable_Check(static_cast<PyObject*>(pFunc))) {
112
0
        printf("Fatal: FuzzerRunOne not defined or not callable\n");
113
0
        abort();
114
0
    }
115
116
37
    return 0;
117
37
}
118
119
143k
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
120
143k
    std::optional<std::vector<uint8_t>> ret = std::nullopt;
121
122
143k
    PyObject *pArgs, *pValue;
123
124
143k
    pArgs = PyTuple_New(1);
125
143k
    pValue = PyBytes_FromStringAndSize((const char*)data, size);
126
143k
    PyTuple_SetItem(pArgs, 0, pValue);
127
128
143k
    pValue = PyObject_CallObject(static_cast<PyObject*>(pFunc), pArgs);
129
130
143k
    if ( pValue == nullptr ) {
131
        /* Abort on unhandled exception */
132
0
        PyErr_PrintEx(1);
133
0
        abort();
134
0
    }
135
136
143k
    if ( PyBytes_Check(pValue) ) {
137
        /* Retrieve output */
138
139
113
        uint8_t* output;
140
113
        Py_ssize_t outputSize;
141
113
        if ( PyBytes_AsStringAndSize(pValue, (char**)&output, &outputSize) != -1) {
142
            /* Return output */
143
113
            ret = std::vector<uint8_t>(output, output + outputSize);
144
113
            goto end;
145
113
        } else {
146
            /* TODO this should not happen */
147
0
        }
148
149
113
    }
150
151
143k
end:
152
143k
    Py_DECREF(pValue);
153
143k
    Py_DECREF(pArgs);
154
    //return ret;
155
143k
    return 0;
156
143k
}