summaryrefslogtreecommitdiffstats
path: root/toolkit/library/gtest/TestUCRTDepends.cpp
blob: a2faaf5ce37fffb51ebcdac9dc091fcc1d471d9e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "gtest/gtest.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Unused.h"
#include "mozilla/WindowsVersion.h"
#include "nsDependentString.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsWindowsHelpers.h"

using namespace mozilla;

constexpr const WCHAR pattern[] = L"\\api-*.dll";

static LPWSTR GetModuleFileDir(HMODULE module, LPWSTR path, DWORD size) {
  DWORD chars = GetModuleFileNameW(module, path, size);
  if (chars <= 0 || chars >= MAX_PATH) {
    return nullptr;
  }

  // Split the base name from the directory.
  LPWSTR basename = wcsrchr(path, L'\\');
  if (!basename) {
    return nullptr;  // at least one path separator must be present
  }
  *basename++ = L'\0';
  return basename;
}

// Make sure that Universal CRT forwarder DLLs are not in app directory if it
// is in Api Sets.
TEST(TestUCRTDepends, AppDir)
{
  WCHAR appdir[MAX_PATH];
  ASSERT_TRUE(GetModuleFileDir(nullptr, appdir, MAX_PATH));

  WCHAR path[MAX_PATH + ArrayLength(pattern)];
  swprintf(path, L"%s%s", appdir, pattern);

  WIN32_FIND_DATAW wfd;
  HANDLE hFind = FindFirstFileW(path, &wfd);
#if defined(_M_ARM64)  // We do not ship Universal CRT DLLs on aarch64.
  if (hFind == INVALID_HANDLE_VALUE) {
    EXPECT_EQ(GetLastError(), static_cast<DWORD>(ERROR_FILE_NOT_FOUND));
    return;
  }
#else
  ASSERT_NE(hFind, INVALID_HANDLE_VALUE);
#endif
  do {
    nsModuleHandle module(LoadLibraryW(wfd.cFileName));
    EXPECT_TRUE(module);
    if (!module) {
      continue;
    }

    // Get a full path of the loaded module.
    LPWSTR basename = GetModuleFileDir(module, path, MAX_PATH);
    ASSERT_TRUE(basename);

    // If the module is in Api Sets, GetModuleFileName returns the redirected
    // DLL path, so filenames will not match.
    bool inApiSets = wcsicmp(wfd.cFileName, basename);
    if (IsWin10OrLater()) {
      // All files must be in Api Sets on Windows 10.
      EXPECT_TRUE(inApiSets);
      continue;
    }
    if (IsWin8OrLater()) {
      if (inApiSets) {
        continue;  // This file is in Api Sets, OK.
      }
      // Universal CRT files are not in Api Sets on Windows 8.
      EXPECT_TRUE(StringBeginsWith(nsDependentString(wfd.cFileName),
                                   u"api-ms-win-crt-"_ns,
                                   nsCaseInsensitiveStringComparator));
    } else {  // Windows 7
      // All files must not be in Api Sets on Windows 7.
      EXPECT_FALSE(inApiSets);
    }
    // Files must be loaded from appdir
    EXPECT_TRUE(!wcsicmp(path, appdir));
  } while (FindNextFileW(hFind, &wfd));
  EXPECT_EQ(GetLastError(), static_cast<DWORD>(ERROR_NO_MORE_FILES));
  BOOL ret = FindClose(hFind);
  EXPECT_TRUE(ret);
}

// Make sure that we do not depend on Universal CRT forwarder DLLs in the
// system directory.
TEST(TestUCRTDepends, SystemDir)
{
  WCHAR appdir[MAX_PATH];
  ASSERT_TRUE(GetModuleFileDir(nullptr, appdir, MAX_PATH));

  WCHAR path[MAX_PATH + ArrayLength(pattern)];
  UINT chars = GetSystemDirectoryW(path, MAX_PATH);
  ASSERT_TRUE(chars > 0 && chars < MAX_PATH);
  wcscat(path, pattern);

  WIN32_FIND_DATAW wfd;
  HANDLE hFind = FindFirstFileW(path, &wfd);
  if (hFind == INVALID_HANDLE_VALUE) {
    EXPECT_EQ(GetLastError(), static_cast<DWORD>(ERROR_FILE_NOT_FOUND));
    EXPECT_TRUE(IsWin8OrLater());
    return;  // Not found in the system directory, OK.
  }
  // Api Sets forwarders must not be present on Windows 10.
  EXPECT_FALSE(IsWin10OrLater());
  do {
    HMODULE module = GetModuleHandleW(wfd.cFileName);
    if (!module) {
      continue;  // We are not using this file, OK.
    }

    // Get a full path of the loaded module.
    LPWSTR basename = GetModuleFileDir(module, path, MAX_PATH);
    ASSERT_TRUE(basename);

    // If the module is in Api Sets, GetModuleFileName returns the redirected
    // DLL path, so filenames will not match.
    if (wcsicmp(wfd.cFileName, basename)) {
      // If this file is in Api Sets, it must not be present in appdir.
      swprintf(path, L"%s\\%s", appdir, wfd.cFileName);
      EXPECT_EQ(GetFileAttributesW(path), INVALID_FILE_ATTRIBUTES);
    } else {
      // If this file is not in Api Sets, it must be loaded from appdir.
      EXPECT_TRUE(!wcsicmp(path, appdir));
    }
  } while (FindNextFileW(hFind, &wfd));
  EXPECT_EQ(GetLastError(), static_cast<DWORD>(ERROR_NO_MORE_FILES));
  BOOL ret = FindClose(hFind);
  EXPECT_TRUE(ret);
}