Coverage Report

Created: 2026-04-12 06:54

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