Coverage Report

Created: 2025-07-04 06:49

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