]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/jit/jit-w32.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / jit / jit-w32.cc
CommitLineData
c83027f3 1/* Functions used by the Windows port of libgccjit.
83ffe9cd 2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
c83027f3
NB
3 Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22
23/* Required for rand_s */
24#define _CRT_RAND_S
25
26#include <cstdio>
27#include <cstdint>
28
29#include "jit-w32.h"
30
31#include "libiberty.h"
32
33#include <accctrl.h>
34#include <aclapi.h>
35
36namespace gcc {
37namespace jit {
38void
39print_last_error (void)
40{
41 LPSTR psz = NULL;
42 DWORD dwErrorCode;
43 dwErrorCode = GetLastError();
44 const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
45 | FORMAT_MESSAGE_IGNORE_INSERTS
46 | FORMAT_MESSAGE_ALLOCATE_BUFFER
47 | FORMAT_MESSAGE_MAX_WIDTH_MASK,
48 NULL,
49 dwErrorCode,
50 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
51 reinterpret_cast<LPSTR>(&psz),
52 0,
53 NULL);
54 if (cchMsg > 0)
55 {
56 fprintf (stderr, "%s\n", psz);
57 LocalFree (psz);
58 }
59 else
60 {
61 fprintf (stderr, "Failed to retrieve error message string for error %lu\n",
62 dwErrorCode);
63 }
64}
65
66/* Helper function used for getting the SID belonging to the current user. */
67static TOKEN_USER*
68get_TOKEN_USER_current_user ()
69{
70 TOKEN_USER *result = NULL;
71
72 HANDLE process_token = INVALID_HANDLE_VALUE;
73
74 DWORD token_user_info_len;
75 TOKEN_USER *token_user = NULL;
76
77 /* Get current process access token. */
78 if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ,
79 &process_token))
80 return NULL;
81
82 /* Get necessary buffer size. */
83 if (!GetTokenInformation(process_token, TokenUser, NULL, 0, &token_user_info_len)
84 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
85 goto cleanup;
86
87 token_user = (TOKEN_USER*) new char[token_user_info_len];
88
89 /* Get info about the user of the process */
90 if (!GetTokenInformation (process_token, TokenUser, token_user,
91 token_user_info_len, &token_user_info_len))
92 goto cleanup;
93
94 result = token_user;
95
96 cleanup:
97 if (process_token != INVALID_HANDLE_VALUE)
98 CloseHandle(process_token);
99
100 if (token_user != NULL && result == NULL)
101 delete[] (char*)token_user;
102
103 return result;
104}
105
106/* Helper function to create a directory with permissions such that only the
107 current user can access it. */
108static bool
109create_directory_for_current_user (const char * path)
110{
111 PACL pACL = NULL;
112 EXPLICIT_ACCESS ea;
113 SECURITY_ATTRIBUTES sa;
114 SECURITY_DESCRIPTOR SD;
115 DWORD dwRes;
116 bool result = true;
117 TOKEN_USER *token_user = NULL;
118
119 token_user = get_TOKEN_USER_current_user();
120 if (!token_user)
121 return false;
122
123 memset (&ea, 0, sizeof (EXPLICIT_ACCESS));
124 ea.grfAccessPermissions = GENERIC_ALL; /* Access to all. */
125 ea.grfAccessMode = SET_ACCESS; /* Set access and revoke everything else. */
126 /* This is necessary for the Windows Explorer GUI to show the correct tick
127 boxes in the "Security" tab. */
128 ea.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
129 ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
130 ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
131 ea.Trustee.ptstrName = (char*) token_user->User.Sid;
132
133 /* Create a new ACL that contains the new ACEs. */
134 dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
135 if (dwRes != ERROR_SUCCESS)
136 return false;
137
138 if (!InitializeSecurityDescriptor (&SD,
139 SECURITY_DESCRIPTOR_REVISION))
140 goto cleanup;
141
142 /* Add the ACL to the security descriptor. */
143 if (!SetSecurityDescriptorDacl (&SD,
144 TRUE, /* use pACL */
145 pACL,
146 FALSE)) /* not a default DACL */
147 goto cleanup;
148
149 /* Initialize a security attributes structure. */
150 sa.nLength = sizeof (SECURITY_ATTRIBUTES);
151 sa.lpSecurityDescriptor = &SD;
152 sa.bInheritHandle = FALSE;
153
154 /* Finally create the directory */
155 if (!CreateDirectoryA (path, &sa))
156 result = false;
157
158 cleanup:
159 if (pACL)
160 LocalFree (pACL);
161
162 if (token_user)
163 delete[] (char*)token_user;
164
165 return result;
166}
167
168
169char *
170win_mkdtemp (void)
171{
172 char lpTempPathBuffer[MAX_PATH];
173
174 /* Gets the temp path env string (no guarantee it's a valid path). */
175 DWORD dwRetVal = GetTempPath (MAX_PATH, lpTempPathBuffer);
176 if (dwRetVal > MAX_PATH || (dwRetVal == 0))
177 {
178 print_last_error ();
179 return NULL;
180 }
181
182 /* Check that the directory actually exists. */
183 DWORD dwAttrib = GetFileAttributes (lpTempPathBuffer);
184 bool temp_path_exists = (dwAttrib != INVALID_FILE_ATTRIBUTES
185 && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
186 if (!temp_path_exists)
187 {
188 fprintf (stderr, "Path returned by GetTempPath does not exist: %s\n",
189 lpTempPathBuffer);
190 }
191
192 /* Make sure there is enough space in the buffer for the prefix and random
193 number.*/
194 int temp_path_buffer_len = dwRetVal;
195 const int appended_len = strlen ("\\libgccjit-123456");
196 if (temp_path_buffer_len + appended_len + 1 >= MAX_PATH)
197 {
198 fprintf (stderr, "Temporary file path too long for generation of random"
199 " directories: %s", lpTempPathBuffer);
200 }
201
202 /* This is all the space we have in the buffer to store the random number and
203 prefix. */
204 int extraspace = MAX_PATH - temp_path_buffer_len - 1;
205
206 int tries;
207 const int max_tries = 1000;
208
209 for (tries = 0; tries < max_tries; ++tries)
210 {
211 /* Get a random number in [0; UINT_MAX]. */
212 unsigned int rand_num;
213 if (rand_s (&rand_num) != 0)
214 {
215 fprintf (stderr,
216 "Failed to create a random number using rand_s(): %s\n",
217 _strerror (NULL));
218 return NULL;
219 }
220
221 /* Create 6 digits random number. */
222 rand_num = ((double)rand_num / ((double) UINT_MAX + 1 ) * 1000000);
223
224 /* Copy the prefix and random number to the buffer. */
225 snprintf (&lpTempPathBuffer[temp_path_buffer_len], extraspace,
226 "\\libgccjit-%06u", rand_num);
227
228 if (create_directory_for_current_user (lpTempPathBuffer))
229 break; // success!
230
231 /* If we can't create the directory because we got unlucky and the
232 directory already exists retry, otherwise fail. */
233 if (GetLastError () != ERROR_ALREADY_EXISTS)
234 {
235 print_last_error ();
236 return NULL;
237 }
238 }
239
240 if (tries == max_tries)
241 {
242 fprintf (stderr, "Failed to create a random directory in %s\n",
243 lpTempPathBuffer);
244 return NULL;
245 }
246
247 {
248 int allocate_len = temp_path_buffer_len + appended_len + 1;
249 char * result = XNEWVEC (char, allocate_len);
250 strcpy (result, lpTempPathBuffer);
251 return result;
252 }
253}
254}
255}