Coverage Report

Created: 2025-11-24 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/python-library-fuzzers/fuzzer.cpp
Line
Count
Source
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
56
static std::string ToAbsolutePath(const std::string argv0, const std::string relativePath) {
19
56
    char absoluteRootPath[PATH_MAX+1];
20
56
    char argv0Copy[argv0.size()+1];
21
56
    memcpy(argv0Copy, argv0.c_str(), argv0.size()+1);
22
56
    if ( realpath(dirname(argv0Copy), absoluteRootPath) == nullptr ) {
23
0
        printf("Fatal error: Cannot resolve absolute root path\n");
24
0
        abort();
25
0
    }
26
27
56
    return std::string(std::string(absoluteRootPath) + "/" + relativePath);
28
56
}
29
30
void* pFunc = nullptr;
31
28
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
32
28
    const std::string argv0 = (*argv)[0];
33
34
28
    const std::string absoluteCPythonInstallPath = ToAbsolutePath(argv0, "cpython-install");
35
28
    const std::string absoluteScriptPath = ToAbsolutePath(argv0, PYTHON_HARNESS_PATH);
36
37
28
    std::vector<uint8_t> program;
38
39
28
    {
40
28
        if ( setenv("PYTHONHOME", absoluteCPythonInstallPath.c_str(), 1) != 0 ) {
41
0
            printf("Fatal error: Cannot set PYTHONHOME\n");
42
0
            abort();
43
0
        }
44
28
    }
45
46
28
    FILE* fp = fopen(absoluteScriptPath.c_str(), "rb");
47
28
    if ( fp == nullptr ) {
48
0
        printf("Fatal error: Cannot open script: %s\n", absoluteScriptPath.c_str());
49
0
        abort();
50
0
    }
51
52
28
    fseek (fp, 0, SEEK_END);
53
28
    long length = ftell(fp);
54
28
    if ( length < 1 ) {
55
0
        printf("Fatal error: Cannot retrieve script file size\n");
56
0
        abort();
57
0
    }
58
28
    fseek (fp, 0, SEEK_SET);
59
28
    program.resize(length);
60
28
    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
28
    fclose(fp);
65
66
28
    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
28
    Py_Initialize();
77
78
28
    {
79
28
        std::string setArgv0;
80
28
        setArgv0 += "import sys";
81
28
        setArgv0 += "\n";
82
28
        setArgv0 += "sys.argv[0] = '" + absoluteScriptPath + "'\n";
83
28
        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
28
    }
89
90
28
    {
91
28
        std::string setPYTHONPATH;
92
28
        setPYTHONPATH += "import sys";
93
28
        setPYTHONPATH += "\n";
94
28
        setPYTHONPATH += "sys.path.append('" + absoluteScriptPath + "')\n";
95
28
        setPYTHONPATH += "\n";
96
28
        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
28
    }
102
103
28
    PyObject *pValue, *pModule, *pLocal;
104
105
28
    pModule = PyModule_New("fuzzermod");
106
28
    PyModule_AddStringConstant(pModule, "__file__", "");
107
28
    pLocal = PyModule_GetDict(pModule);
108
28
    pValue = PyRun_String(code.c_str(), Py_file_input, pLocal, pLocal);
109
110
28
    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
28
    Py_DECREF(pValue);
116
117
28
    pFunc = PyObject_GetAttrString(pModule, "FuzzerRunOne");
118
119
28
    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
28
    return 0;
125
28
}
126
127
96.4k
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
128
96.4k
    std::optional<std::vector<uint8_t>> ret = std::nullopt;
129
130
96.4k
    PyObject *pArgs, *pValue;
131
132
96.4k
    pArgs = PyTuple_New(1);
133
96.4k
    pValue = PyBytes_FromStringAndSize((const char*)data, size);
134
96.4k
    PyTuple_SetItem(pArgs, 0, pValue);
135
136
96.4k
    pValue = PyObject_CallObject(static_cast<PyObject*>(pFunc), pArgs);
137
138
96.4k
    if ( pValue == nullptr ) {
139
        /* Abort on unhandled exception */
140
0
        PyErr_PrintEx(1);
141
0
        abort();
142
0
    }
143
144
96.4k
    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
96.4k
end:
160
96.4k
    Py_DECREF(pValue);
161
96.4k
    Py_DECREF(pArgs);
162
    //return ret;
163
96.4k
    return 0;
164
96.4k
}