Coverage Report

Created: 2026-10-31 06:21

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