Coverage Report

Created: 2026-09-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/library/library.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Library Loader
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <winpr/crt.h>
23
#include <winpr/platform.h>
24
25
#include <winpr/library.h>
26
27
#include "../log.h"
28
#define TAG WINPR_TAG("library")
29
30
/**
31
 * api-ms-win-core-libraryloader-l1-1-1.dll:
32
 *
33
 * AddDllDirectory
34
 * RemoveDllDirectory
35
 * SetDefaultDllDirectories
36
 * DisableThreadLibraryCalls
37
 * EnumResourceLanguagesExA
38
 * EnumResourceLanguagesExW
39
 * EnumResourceNamesExA
40
 * EnumResourceNamesExW
41
 * EnumResourceTypesExA
42
 * EnumResourceTypesExW
43
 * FindResourceExW
44
 * FindStringOrdinal
45
 * FreeLibrary
46
 * FreeLibraryAndExitThread
47
 * FreeResource
48
 * GetModuleFileNameA
49
 * GetModuleFileNameW
50
 * GetModuleHandleA
51
 * GetModuleHandleExA
52
 * GetModuleHandleExW
53
 * GetModuleHandleW
54
 * GetProcAddress
55
 * LoadLibraryExA
56
 * LoadLibraryExW
57
 * LoadResource
58
 * LoadStringA
59
 * LoadStringW
60
 * LockResource
61
 * QueryOptionalDelayLoadedAPI
62
 * SizeofResource
63
 */
64
65
#if (!defined(_WIN32) && !defined(__CYGWIN__)) || defined(_UWP)
66
67
#ifndef _WIN32
68
69
#include <dlfcn.h>
70
#include <stdio.h>
71
#include <stdlib.h>
72
#include <unistd.h>
73
#include <sys/types.h>
74
#include <sys/stat.h>
75
76
#ifdef __MACOSX__
77
#include <mach-o/dyld.h>
78
#endif
79
80
#if defined(__FreeBSD__)
81
#include <sys/sysctl.h>
82
#endif
83
84
#if defined(__OpenBSD__)
85
#include <errno.h>
86
#endif
87
88
#endif
89
90
DLL_DIRECTORY_COOKIE AddDllDirectory(WINPR_ATTR_UNUSED PCWSTR NewDirectory)
91
0
{
92
  /* TODO: Implement */
93
0
  WLog_ERR(TAG, "not implemented");
94
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
95
0
  return nullptr;
96
0
}
97
98
BOOL RemoveDllDirectory(WINPR_ATTR_UNUSED DLL_DIRECTORY_COOKIE Cookie)
99
0
{
100
  /* TODO: Implement */
101
0
  WLog_ERR(TAG, "not implemented");
102
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
103
0
  return FALSE;
104
0
}
105
106
BOOL SetDefaultDllDirectories(WINPR_ATTR_UNUSED DWORD DirectoryFlags)
107
0
{
108
  /* TODO: Implement */
109
0
  WLog_ERR(TAG, "not implemented");
110
0
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
111
0
  return FALSE;
112
0
}
113
114
HMODULE LoadLibraryA(LPCSTR lpLibFileName)
115
0
{
116
0
  if (!lpLibFileName)
117
0
    return nullptr;
118
119
#if defined(_UWP)
120
  int status;
121
  HMODULE hModule = nullptr;
122
  WCHAR* filenameW = nullptr;
123
124
  filenameW = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
125
  if (filenameW)
126
    return nullptr;
127
128
  hModule = LoadLibraryW(filenameW);
129
  free(filenameW);
130
  return hModule;
131
#else
132
0
  HMODULE library = dlopen(lpLibFileName, RTLD_LOCAL | RTLD_LAZY);
133
134
0
  if (!library)
135
0
  {
136
    // NOLINTNEXTLINE(concurrency-mt-unsafe)
137
0
    const char* err = dlerror();
138
0
    WLog_VRB(TAG, "failed with %s", err);
139
0
    return nullptr;
140
0
  }
141
142
0
  return library;
143
0
#endif
144
0
}
145
146
HMODULE LoadLibraryW(LPCWSTR lpLibFileName)
147
0
{
148
#if defined(_UWP)
149
  return LoadPackagedLibrary(lpLibFileName, 0);
150
#else
151
0
  char* name = nullptr;
152
153
0
  if (lpLibFileName)
154
0
    name = ConvertWCharToUtf8Alloc(lpLibFileName, nullptr);
155
156
0
  HMODULE module = LoadLibraryA(name);
157
0
  free(name);
158
0
  return module;
159
0
#endif
160
0
}
161
162
HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
163
0
{
164
0
  if (dwFlags != 0)
165
0
    WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
166
167
0
  if (hFile)
168
0
    WLog_WARN(TAG, "does not support hFile != nullptr");
169
170
0
  return LoadLibraryA(lpLibFileName);
171
0
}
172
173
HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
174
0
{
175
0
  if (dwFlags != 0)
176
0
    WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
177
178
0
  if (hFile)
179
0
    WLog_WARN(TAG, "does not support hFile != nullptr");
180
181
0
  return LoadLibraryW(lpLibFileName);
182
0
}
183
184
#endif
185
186
#if !defined(_WIN32) && !defined(__CYGWIN__)
187
188
FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
189
0
{
190
0
  FARPROC proc = nullptr;
191
0
  proc = dlsym(hModule, lpProcName);
192
193
0
  if (proc == nullptr)
194
0
  {
195
    // NOLINTNEXTLINE(concurrency-mt-unsafe)
196
0
    WLog_ERR(TAG, "GetProcAddress: could not find procedure %s: %s", lpProcName, dlerror());
197
0
    return (FARPROC) nullptr;
198
0
  }
199
200
0
  return proc;
201
0
}
202
203
BOOL FreeLibrary(HMODULE hLibModule)
204
0
{
205
0
  int status = 0;
206
0
  status = dlclose(hLibModule);
207
208
0
  return (status == 0);
209
0
}
210
211
HMODULE GetModuleHandleA(LPCSTR lpModuleName)
212
0
{
213
0
  return dlopen(lpModuleName, RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
214
0
}
215
216
HMODULE GetModuleHandleW(LPCWSTR lpModuleName)
217
0
{
218
0
  char* name = nullptr;
219
0
  if (lpModuleName)
220
0
    name = ConvertWCharToUtf8Alloc(lpModuleName, nullptr);
221
0
  HANDLE hdl = GetModuleHandleA(name);
222
0
  free(name);
223
0
  return hdl;
224
0
}
225
226
/**
227
 * GetModuleFileName:
228
 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms683197/
229
 *
230
 * Finding current executable's path without /proc/self/exe:
231
 * http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
232
 */
233
234
DWORD GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize)
235
0
{
236
0
  DWORD status = 0;
237
0
  if (!lpFilename)
238
0
  {
239
0
    SetLastError(ERROR_INTERNAL_ERROR);
240
0
    return 0;
241
0
  }
242
243
0
  char* name = calloc(nSize, sizeof(char));
244
0
  if (!name)
245
0
  {
246
0
    SetLastError(ERROR_INTERNAL_ERROR);
247
0
    return 0;
248
0
  }
249
0
  status = GetModuleFileNameA(hModule, name, nSize);
250
251
0
  if ((status > INT_MAX) || (nSize > INT_MAX))
252
0
  {
253
0
    SetLastError(ERROR_INTERNAL_ERROR);
254
0
    status = 0;
255
0
  }
256
257
0
  if (status > 0)
258
0
  {
259
0
    if (ConvertUtf8NToWChar(name, status, lpFilename, nSize) < 0)
260
0
    {
261
0
      free(name);
262
0
      SetLastError(ERROR_INTERNAL_ERROR);
263
0
      return 0;
264
0
    }
265
0
  }
266
267
0
  free(name);
268
0
  return status;
269
0
}
270
271
#if defined(__linux__) || defined(__NetBSD__) || defined(__DragonFly__)
272
static DWORD module_from_proc(const char* proc, LPSTR lpFilename, DWORD nSize)
273
0
{
274
0
  char buffer[8192] = WINPR_C_ARRAY_INIT;
275
0
  ssize_t status = readlink(proc, buffer, ARRAYSIZE(buffer) - 1);
276
277
0
  if ((status < 0) || ((size_t)status >= ARRAYSIZE(buffer)))
278
0
  {
279
0
    SetLastError(ERROR_INTERNAL_ERROR);
280
0
    return 0;
281
0
  }
282
283
0
  const size_t length = strnlen(buffer, ARRAYSIZE(buffer));
284
285
0
  if (length < nSize)
286
0
  {
287
0
    CopyMemory(lpFilename, buffer, length);
288
0
    lpFilename[length] = '\0';
289
0
    return (DWORD)length;
290
0
  }
291
292
0
  CopyMemory(lpFilename, buffer, nSize - 1);
293
0
  lpFilename[nSize - 1] = '\0';
294
0
  SetLastError(ERROR_INSUFFICIENT_BUFFER);
295
0
  return nSize;
296
0
}
297
#endif
298
299
#if defined(__FreeBSD__)
300
WINPR_ATTR_NODISCARD
301
static DWORD freebsd_get_module_file_name(char* lpFilename, uint32_t nSize)
302
{
303
  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
304
  size_t cb = nSize;
305
306
  {
307
    const int rc = sysctl(mib, ARRAYSIZE(mib), nullptr, &cb, nullptr, 0);
308
    if (rc != 0)
309
    {
310
      SetLastError(ERROR_INTERNAL_ERROR);
311
      return 0;
312
    }
313
  }
314
315
  char* fullname = calloc(cb + 1, sizeof(char));
316
  if (!fullname)
317
  {
318
    SetLastError(ERROR_INTERNAL_ERROR);
319
    return 0;
320
  }
321
322
  {
323
    size_t cb2 = cb;
324
    const int rc = sysctl(mib, ARRAYSIZE(mib), fullname, &cb2, nullptr, 0);
325
    if ((rc != 0) || (cb2 != cb))
326
    {
327
      SetLastError(ERROR_INTERNAL_ERROR);
328
      free(fullname);
329
      return 0;
330
    }
331
  }
332
333
  if (nSize > 0)
334
  {
335
    strncpy(lpFilename, fullname, nSize - 1);
336
    lpFilename[nSize - 1] = '\0';
337
  }
338
  free(fullname);
339
340
  if (nSize < cb)
341
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
342
343
  return (DWORD)MIN(nSize, cb);
344
}
345
#endif
346
347
#if defined(__MACOSX__)
348
WINPR_ATTR_NODISCARD
349
static uint32_t get_required_size(void)
350
{
351
  char buffer[1] = WINPR_C_ARRAY_INIT;
352
  uint32_t size = sizeof(buffer);
353
  if (_NSGetExecutablePath(buffer, &size) == 0)
354
    return sizeof(buffer);
355
  return size;
356
}
357
358
WINPR_ATTR_NODISCARD
359
static DWORD mac_get_module_file_name(char* lpFilename, uint32_t nSize)
360
{
361
  const uint32_t required = get_required_size();
362
  if (required == 0)
363
    return 0;
364
365
  if (required < nSize)
366
  {
367
    uint32_t size = nSize;
368
    if (_NSGetExecutablePath(lpFilename, &size) == 0)
369
      return (DWORD)strnlen(lpFilename, nSize);
370
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
371
    return nSize;
372
  }
373
374
  char* buffer = calloc(1ull + required, sizeof(char));
375
  if (!buffer)
376
  {
377
    SetLastError(ERROR_OUTOFMEMORY);
378
    return 0;
379
  }
380
381
  uint32_t size = required;
382
  const int status = _NSGetExecutablePath(buffer, &size);
383
384
  if (status != 0)
385
  {
386
    /* path too small */
387
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
388
    free(buffer);
389
    return size;
390
  }
391
392
  /*
393
   * _NSGetExecutablePath may not return the canonical path,
394
   * so use realpath to find the absolute, canonical path.
395
   */
396
  char* real = realpath(buffer, nullptr);
397
  free(buffer);
398
  if (!real)
399
  {
400
    SetLastError(ERROR_OUTOFMEMORY);
401
    return 0;
402
  }
403
  const size_t length = strlen(real);
404
  if (length < nSize)
405
  {
406
    strncpy(lpFilename, real, length + 1);
407
    free(real);
408
    return (DWORD)strnlen(lpFilename, nSize);
409
  }
410
411
  strncpy(lpFilename, real, nSize - 1);
412
  free(real);
413
  lpFilename[nSize - 1] = '\0';
414
  SetLastError(ERROR_INSUFFICIENT_BUFFER);
415
  return nSize;
416
}
417
#endif
418
419
#if defined(__OpenBSD__)
420
WINPR_ATTR_NODISCARD
421
static DWORD openbsd_get_module_file_name(char* lpFilename, uint32_t nSize)
422
{
423
#ifdef WITH_GETEXECPATH
424
  size_t size = nSize + 1ull;
425
  char* path = calloc(1, size);
426
427
  if (path == nullptr)
428
  {
429
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
430
    return 0;
431
  }
432
433
  while (getexecpath(path, size) != 0)
434
  {
435
    if (errno != ERANGE)
436
    {
437
      free(path);
438
      SetLastError(ERROR_INTERNAL_ERROR);
439
      return 0;
440
    }
441
442
    size += PATH_MAX;
443
444
    char* tmp = realloc(path, size);
445
446
    if (tmp == nullptr)
447
    {
448
      free(path);
449
      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
450
      return 0;
451
    }
452
453
    path = tmp;
454
  }
455
456
  const size_t length = strnlen(path, size);
457
458
  memset(lpFilename, 0, nSize);
459
  memcpy(lpFilename, path, MIN(length, nSize));
460
461
  free(path);
462
463
  if (length >= nSize)
464
  {
465
    SetLastError(ERROR_INSUFFICIENT_BUFFER);
466
    return nSize;
467
  }
468
469
  return WINPR_ASSERTING_INT_CAST(DWORD, length);
470
#else
471
  WLog_ERR(TAG, "is not implemented");
472
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
473
  return 0;
474
#endif
475
}
476
#endif
477
478
DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
479
0
{
480
0
  if (hModule)
481
0
  {
482
0
    WLog_ERR(TAG, "is not implemented");
483
0
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
484
0
    return 0;
485
0
  }
486
487
0
#if defined(__linux__)
488
0
  return module_from_proc("/proc/self/exe", lpFilename, nSize);
489
#elif defined(__FreeBSD__)
490
  return freebsd_get_module_file_name(lpFilename, nSize);
491
#elif defined(__NetBSD__)
492
  return module_from_proc("/proc/curproc/exe", lpFilename, nSize);
493
#elif defined(__DragonFly__)
494
  return module_from_proc("/proc/curproc/file", lpFilename, nSize);
495
#elif defined(__MACOSX__)
496
  return mac_get_module_file_name(lpFilename, nSize);
497
#elif defined(__OpenBSD__)
498
  return openbsd_get_module_file_name(lpFilename, nSize);
499
#else
500
  WLog_ERR(TAG, "is not implemented");
501
  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
502
  return 0;
503
#endif
504
0
}
505
506
#endif
507
508
HMODULE LoadLibraryX(LPCSTR lpLibFileName)
509
0
{
510
#if defined(_WIN32)
511
  HMODULE hm = nullptr;
512
  WCHAR* wstr = nullptr;
513
514
  if (lpLibFileName)
515
    wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
516
517
  hm = LoadLibraryW(wstr);
518
  free(wstr);
519
  return hm;
520
#else
521
0
  return LoadLibraryA(lpLibFileName);
522
0
#endif
523
0
}
524
525
HMODULE LoadLibraryExX(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
526
0
{
527
0
  if (!lpLibFileName)
528
0
    return nullptr;
529
#if defined(_WIN32)
530
  HMODULE hm = nullptr;
531
  WCHAR* wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, nullptr);
532
  if (wstr)
533
    hm = LoadLibraryExW(wstr, hFile, dwFlags);
534
  free(wstr);
535
  return hm;
536
#else
537
0
  return LoadLibraryExA(lpLibFileName, hFile, dwFlags);
538
0
#endif
539
0
}