Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sal/osl/unx/module.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <sal/config.h>
21
22
#include <sal/log.hxx>
23
#include <sal/types.h>
24
#include <osl/module.h>
25
#include <osl/thread.h>
26
#include <osl/file.h>
27
#include <rtl/string.hxx>
28
#include <rtl/ustring.hxx>
29
#include <assert.h>
30
#include <dlfcn.h>
31
#include <limits.h>
32
#include "file_url.hxx"
33
34
#include <optional>
35
36
static std::optional<OString> getModulePathFromAddress(void* address)
37
0
{
38
0
    std::optional<OString> oPath;
39
0
#if HAVE_UNIX_DLAPI
40
0
    Dl_info dl_info;
41
0
    if (dladdr(address, &dl_info) != 0)
42
0
    {
43
0
        oPath = OString(dl_info.dli_fname);
44
0
    }
45
#else
46
    (void) address;
47
#endif
48
0
    return oPath;
49
0
}
50
51
#ifndef DISABLE_DYNLOADING
52
53
/*****************************************************************************/
54
/* osl_loadModule */
55
/*****************************************************************************/
56
57
oslModule SAL_CALL osl_loadModule(rtl_uString *ustrModuleName, sal_Int32 nRtldMode)
58
{
59
    oslModule pModule=nullptr;
60
    rtl_uString* ustrTmp = nullptr;
61
62
    SAL_WARN_IF(ustrModuleName == nullptr, "sal.osl", "string is not valid");
63
64
    /* ensure ustrTmp hold valid string */
65
    if (osl_getSystemPathFromFileURL(ustrModuleName, &ustrTmp) != osl_File_E_None)
66
        rtl_uString_assign(&ustrTmp, ustrModuleName);
67
68
    if (ustrTmp)
69
    {
70
        char buffer[PATH_MAX];
71
72
        if (UnicodeToText(buffer, PATH_MAX, ustrTmp->buffer, ustrTmp->length))
73
            pModule = osl_loadModuleAscii(buffer, nRtldMode);
74
        rtl_uString_release(ustrTmp);
75
    }
76
77
    return pModule;
78
}
79
80
/*****************************************************************************/
81
/* osl_loadModuleAscii */
82
/*****************************************************************************/
83
84
oslModule SAL_CALL osl_loadModuleAscii(const char *pModuleName, sal_Int32 nRtldMode)
85
{
86
#if HAVE_UNIX_DLAPI
87
    SAL_WARN_IF(
88
        ((nRtldMode & SAL_LOADMODULE_LAZY) != 0
89
         && (nRtldMode & SAL_LOADMODULE_NOW) != 0),
90
        "sal.osl", "only either LAZY or NOW");
91
    if (pModuleName)
92
    {
93
        int rtld_mode =
94
            ((nRtldMode & SAL_LOADMODULE_NOW) ? RTLD_NOW : RTLD_LAZY) |
95
            ((nRtldMode & SAL_LOADMODULE_GLOBAL) ? RTLD_GLOBAL : RTLD_LOCAL);
96
        void* pLib = dlopen(pModuleName, rtld_mode);
97
98
        SAL_WARN_IF(
99
            pLib == nullptr, "sal.osl",
100
            "dlopen(" << pModuleName << ", " << rtld_mode << "): "
101
                << dlerror());
102
        return pLib;
103
    }
104
#else
105
    (void) pModuleName;
106
    (void) nRtldMode;
107
#endif
108
    return nullptr;
109
}
110
111
oslModule osl_loadModuleRelativeAscii(
112
    oslGenericFunction baseModule, char const * relativePath, sal_Int32 mode)
113
{
114
    assert(relativePath && "illegal argument");
115
    if (relativePath[0] == '/') {
116
        return osl_loadModuleAscii(relativePath, mode);
117
    }
118
    oslModule module;
119
    std::optional<OString> oPath = getModulePathFromAddress(reinterpret_cast<void*>(baseModule));
120
    if (!oPath.has_value())
121
        return nullptr;
122
123
    OString sPath = oPath->copy(0, oPath->lastIndexOf('/') + 1);
124
125
        /* cut off everything after the last slash; should the original path
126
           contain no slash, the resulting path is the empty string */
127
    sPath += relativePath;
128
    module = osl_loadModuleAscii(sPath.getStr(), mode);
129
    return module;
130
}
131
132
#endif // !DISABLE_DYNLOADING
133
134
/*****************************************************************************/
135
/* osl_getModuleHandle */
136
/*****************************************************************************/
137
138
sal_Bool SAL_CALL
139
osl_getModuleHandle(rtl_uString *, oslModule *pResult)
140
0
{
141
0
#if HAVE_UNIX_DLAPI
142
0
    *pResult = static_cast<oslModule>(RTLD_DEFAULT);
143
0
    return true;
144
#else
145
    *pResult = nullptr;
146
    return false;
147
#endif
148
0
}
149
150
/*****************************************************************************/
151
/* osl_unloadModule */
152
/*****************************************************************************/
153
void SAL_CALL osl_unloadModule(oslModule hModule)
154
0
{
155
#if !defined(DISABLE_DYNLOADING) && HAVE_UNIX_DLAPI
156
    if (hModule)
157
    {
158
        int nRet = dlclose(hModule);
159
        SAL_INFO_IF(
160
            nRet != 0, "sal.osl", "dlclose(" << hModule << "): " << dlerror());
161
    }
162
#else
163
0
    (void) hModule;
164
0
#endif
165
0
}
166
167
namespace {
168
169
void * getSymbol(oslModule module, char const * symbol)
170
0
{
171
0
    assert(symbol != nullptr);
172
0
#if HAVE_UNIX_DLAPI
173
    // We do want to use dlsym() also in the DISABLE_DYNLOADING case
174
    // just to look up symbols in the static executable, I think:
175
0
    void * p = dlsym(module, symbol);
176
0
    SAL_INFO_IF(
177
0
        p == nullptr, "sal.osl",
178
0
        "dlsym(" << module << ", " << symbol << "): " << dlerror());
179
#else
180
    (void) module;
181
    (void) symbol;
182
    void *p = nullptr;
183
#endif
184
0
    return p;
185
0
}
186
187
}
188
189
/*****************************************************************************/
190
/* osl_getSymbol */
191
/*****************************************************************************/
192
void* SAL_CALL
193
osl_getSymbol(oslModule Module, rtl_uString* pSymbolName)
194
0
{
195
    // Arbitrarily using UTF-8:
196
0
    OString s;
197
0
    if (!OUString::unacquired(&pSymbolName).convertToString(
198
0
            &s, RTL_TEXTENCODING_UTF8,
199
0
            (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
200
0
             RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
201
0
    {
202
0
        SAL_INFO(
203
0
            "sal.osl", "cannot convert \"" << OUString::unacquired(&pSymbolName)
204
0
                << "\" to UTF-8");
205
0
        return nullptr;
206
0
    }
207
0
    if (s.indexOf('\0') != -1) {
208
0
        SAL_INFO("sal.osl", "\"" << s << "\" contains embedded NUL");
209
0
        return nullptr;
210
0
    }
211
0
    return getSymbol(Module, s.getStr());
212
0
}
213
214
/*****************************************************************************/
215
/* osl_getAsciiFunctionSymbol */
216
/*****************************************************************************/
217
oslGenericFunction SAL_CALL
218
osl_getAsciiFunctionSymbol(oslModule Module, const char *pSymbol)
219
0
{
220
0
    return reinterpret_cast<oslGenericFunction>(getSymbol(Module, pSymbol));
221
        // requires conditionally-supported conversion from void * to function
222
        // pointer
223
0
}
224
225
/*****************************************************************************/
226
/* osl_getFunctionSymbol */
227
/*****************************************************************************/
228
oslGenericFunction SAL_CALL
229
osl_getFunctionSymbol(oslModule module, rtl_uString *puFunctionSymbolName)
230
0
{
231
0
    return reinterpret_cast<oslGenericFunction>(
232
0
        osl_getSymbol(module, puFunctionSymbolName));
233
        // requires conditionally-supported conversion from void * to function
234
        // pointer
235
0
}
236
237
/*****************************************************************************/
238
/* osl_getModuleURLFromAddress */
239
/*****************************************************************************/
240
sal_Bool SAL_CALL osl_getModuleURLFromAddress(void * addr, rtl_uString ** ppLibraryUrl)
241
0
{
242
0
    bool result = false;
243
0
    std::optional<OString> oPath = getModulePathFromAddress(addr);
244
0
    if (oPath.has_value())
245
0
    {
246
0
        rtl_string2UString(ppLibraryUrl,
247
0
                           oPath->getStr(),
248
0
                           oPath->getLength(),
249
0
                           osl_getThreadTextEncoding(),
250
0
                           OSTRING_TO_OUSTRING_CVTFLAGS);
251
252
0
        SAL_WARN_IF(
253
0
            *ppLibraryUrl == nullptr, "sal.osl", "rtl_string2UString failed");
254
0
        auto const e = osl_getFileURLFromSystemPath(*ppLibraryUrl, ppLibraryUrl);
255
0
        if (e == osl_File_E_None)
256
0
        {
257
0
            SAL_INFO("sal.osl", "osl_getModuleURLFromAddress(" << addr << ") => " << OUString(*ppLibraryUrl));
258
259
0
            result = true;
260
0
        }
261
0
        else
262
0
        {
263
0
            SAL_WARN(
264
0
                "sal.osl",
265
0
                "osl_getModuleURLFromAddress(" << addr << "), osl_getFileURLFromSystemPath("
266
0
                    << OUString::unacquired(ppLibraryUrl) << ") failed with " << e);
267
0
            result = false;
268
0
        }
269
0
    }
270
0
    return result;
271
0
}
272
273
/*****************************************************************************/
274
/* osl_getModuleURLFromFunctionAddress */
275
/*****************************************************************************/
276
sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress(oslGenericFunction addr, rtl_uString ** ppLibraryUrl)
277
0
{
278
0
    return osl_getModuleURLFromAddress(
279
0
        reinterpret_cast<void*>(addr), ppLibraryUrl);
280
        // requires conditionally-supported conversion from function pointer to
281
        // void *
282
0
}
283
284
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */