From: "Nicolas Bértolo" <nicolasbertolo@gmail.com>
To: David Malcolm <dmalcolm@redhat.com>
Cc: jit@gcc.gnu.org, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] Port libgccjit to Windows.
Date: Wed, 27 May 2020 22:27:54 -0300 [thread overview]
Message-ID: <CAFnS-Oncc2W_1UZv1BhHQLjBUGOiBi65wT6uv=mEkbDO9HMLJw@mail.gmail.com> (raw)
In-Reply-To: <5de2a5202b50882612e1fe51d254f2b125f61716.camel@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 1775 bytes --]
Hi,
> Do you have commit/push access to the gcc repository?
No I don't.
> BTW, why isn't it necessary to use --enable-host-shared in Windows?
> Can we document that?
That's because all code is position independent in Windows.
> On the subject of nitpicking, I find myself getting distracted by the
> indentation in the patch; there seem to be a lot of mismatches.
> What editor are you using, and does it have options to
> (a) show visible whitespace, and
> (b) to apply a formatting convention?
> I use Emacs, and it takes care of this for me. I haven't used it, but
> there's a contrib/clang-format file in the gcc source tree which
> presumably describes GCC's coding conventions, if that helps for the
> new code.
The problem seems to be that I was writing tabs but since I have set up my
editor to show them as 2 spaces I couldn't see what was wrong.
> Am I right in thinking that this installs the libgccjit.a file on Windows?
> Why is this done?
That is the file libgccjit.dll.a
It is the import library for gccjit. It is part of the way Windows handles
dynamic libraries.
> New C++ source files should have a .cc extension.
> I hope that at some point we'll rename all the existing .c ones
> accordingly.
I just couldn't get Make to generate jit-w32.o from jit-w32.cc.
It looks for jit-w32.c.
I had to leave it with the .c extension.
> Does this call generate a directory that's only accessible to the
> current user?
> Otherwise there could be a risk of a hostile user on the same machine
> clobbering the contents and injecting code into this process.
I changed the code to generate a directory than can only be accessed by the
current user.
I've attached a new version. It contains a rewrite of the code that creates
temporary directories.
Nico
[-- Attachment #2: 0001-Port-libgccjit-to-Windows.patch --]
[-- Type: application/octet-stream, Size: 26872 bytes --]
From f9f560132837b3454cce93d6098d05973f09ee8b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20B=C3=A9rtolo?= <nicolasbertolo@gmail.com>
Date: Fri, 22 May 2020 17:54:41 -0300
Subject: [PATCH] Port libgccjit to Windows.
* configure: Regenerate.
* configure.ac: Don't require --enable-host-shared when building for Mingw.
* gcc/Makefile.in: don't look for libiberty in the "pic" subdirectory when
building for Mingw. Add dependency on xgcc with the proper extension.
* gcc/c/Make-lang.in: Remove extra slash.
* gcc/jit/Make-lang.in: Remove extra slash. Build libgccjit.dll and its import
library in Windows.
* gcc/jit/jit-w32.h: New file.
* gcc/jit/jit-w32.c (print_last_error): New function that prints the error
string corresponding to GetLastError().
(get_TOKEN_USER_current_user): Helper function used for getting the SID
belonging to the current user.
(create_directory_for_current_user): Helper function to create a directory with
permissions such that only the current user can access it.
(win_mkdtemp): Create a temporary directory using Windows APIs.
* gcc/jit/jit-playback.c: Do not chmod files in Windows. Use LoadLibrary,
FreeLibrary and GetProcAddress instead of libdl.
* gcc/jit/jit-result.{h,c}: Introduce result::handle_t to abstract over the
types used for dynamic library handles.
* gcc/jit/jit-tempdir.c: Do not use mkdtemp() in Windows, use win_mkdtemp().
---
configure | 32 +++---
configure.ac | 33 +++---
gcc/Makefile.in | 10 +-
gcc/c/Make-lang.in | 2 +-
gcc/jit/Make-lang.in | 56 +++++++--
gcc/jit/config-lang.in | 2 +-
gcc/jit/jit-playback.c | 24 +++-
gcc/jit/jit-result.c | 35 +++++-
gcc/jit/jit-result.h | 14 ++-
gcc/jit/jit-tempdir.c | 10 ++
gcc/jit/jit-w32.c | 255 +++++++++++++++++++++++++++++++++++++++++
gcc/jit/jit-w32.h | 30 +++++
12 files changed, 452 insertions(+), 51 deletions(-)
create mode 100644 gcc/jit/jit-w32.c
create mode 100644 gcc/jit/jit-w32.h
diff --git a/configure b/configure
index 3af6a530b..b7897446c 100755
--- a/configure
+++ b/configure
@@ -6489,9 +6489,13 @@ $as_echo "$as_me: WARNING: GNAT is required to build $language" >&2;}
esac
# Disable jit if -enable-host-shared not specified
- case ${add_this_lang}:${language}:${host_shared} in
- yes:jit:no)
- # PR jit/64780: explicitly specify --enable-host-shared
+ # but not if building for Mingw
+ case $target in
+ *mingw*) ;;
+ *)
+ case ${add_this_lang}:${language}:${host_shared} in
+ yes:jit:no)
+ # PR jit/64780: explicitly specify --enable-host-shared
as_fn_error $? "
Enabling language \"jit\" requires --enable-host-shared.
@@ -6502,17 +6506,19 @@ If you want to build both the jit and the regular compiler, it is often
best to do this via two separate configure/builds, in separate
directories, to avoid imposing the performance cost of
--enable-host-shared on the regular compiler." "$LINENO" 5
- ;;
- all:jit:no)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-host-shared required to build $language" >&5
+ ;;
+ all:jit:no)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-host-shared required to build $language" >&5
$as_echo "$as_me: WARNING: --enable-host-shared required to build $language" >&2;}
- add_this_lang=unsupported
- ;;
- *:jit:no)
- # Silently disable.
- add_this_lang=unsupported
- ;;
- esac
+ add_this_lang=unsupported
+ ;;
+ *:jit:no)
+ # Silently disable.
+ add_this_lang=unsupported
+ ;;
+ esac
+ ;;
+ esac
# Disable a language that is unsupported by the target.
case "${add_this_lang}: $unsupported_languages " in
diff --git a/configure.ac b/configure.ac
index a67801371..59bd92a3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2079,9 +2079,14 @@ if test -d ${srcdir}/gcc; then
esac
# Disable jit if -enable-host-shared not specified
- case ${add_this_lang}:${language}:${host_shared} in
- yes:jit:no)
- # PR jit/64780: explicitly specify --enable-host-shared
+ # but not if building for Mingw. All code in Windows
+ # is position independent code (PIC).
+ case $target in
+ *mingw*) ;;
+ *)
+ case ${add_this_lang}:${language}:${host_shared} in
+ yes:jit:no)
+ # PR jit/64780: explicitly specify --enable-host-shared
AC_MSG_ERROR([
Enabling language "jit" requires --enable-host-shared.
@@ -2092,16 +2097,18 @@ If you want to build both the jit and the regular compiler, it is often
best to do this via two separate configure/builds, in separate
directories, to avoid imposing the performance cost of
--enable-host-shared on the regular compiler.])
- ;;
- all:jit:no)
- AC_MSG_WARN([--enable-host-shared required to build $language])
- add_this_lang=unsupported
- ;;
- *:jit:no)
- # Silently disable.
- add_this_lang=unsupported
- ;;
- esac
+ ;;
+ all:jit:no)
+ AC_MSG_WARN([--enable-host-shared required to build $language])
+ add_this_lang=unsupported
+ ;;
+ *:jit:no)
+ # Silently disable.
+ add_this_lang=unsupported
+ ;;
+ esac
+ ;;
+ esac
# Disable a language that is unsupported by the target.
case "${add_this_lang}: $unsupported_languages " in
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 0fe2ba241..45851eca8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1046,10 +1046,12 @@ ALL_LINKERFLAGS = $(ALL_CXXFLAGS)
# Build and host support libraries.
-# Use the "pic" build of libiberty if --enable-host-shared.
+# Use the "pic" build of libiberty if --enable-host-shared, unless we are
+# building for mingw.
+LIBIBERTY_PICDIR=$(if $(findstring mingw,$(target)),,pic)
ifeq ($(enable_host_shared),yes)
-LIBIBERTY = ../libiberty/pic/libiberty.a
-BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/pic/libiberty.a
+LIBIBERTY = ../libiberty/$(LIBIBERTY_PICDIR)/libiberty.a
+BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/$(LIBIBERTY_PICDIR)/libiberty.a
else
LIBIBERTY = ../libiberty/libiberty.a
BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/libiberty.a
@@ -1726,7 +1728,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
# This symlink makes the full installation name of the driver be available
# from within the *build* directory, for use when running the JIT library
# from there (e.g. when running its testsuite).
-$(FULL_DRIVER_NAME): ./xgcc
+$(FULL_DRIVER_NAME): ./xgcc$(exeext)
rm -f $@
$(LN_S) $< $@
diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in
index 8944b9b9f..7efc7c2c3 100644
--- a/gcc/c/Make-lang.in
+++ b/gcc/c/Make-lang.in
@@ -162,7 +162,7 @@ c.install-plugin: installdirs
# Install import library.
ifeq ($(plugin_implib),yes)
$(mkinstalldirs) $(DESTDIR)$(plugin_resourcesdir)
- $(INSTALL_DATA) cc1$(exeext).a $(DESTDIR)/$(plugin_resourcesdir)/cc1$(exeext).a
+ $(INSTALL_DATA) cc1$(exeext).a $(DESTDIR)$(plugin_resourcesdir)/cc1$(exeext).a
endif
c.uninstall:
diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
index 38ddfad28..9cb7814d6 100644
--- a/gcc/jit/Make-lang.in
+++ b/gcc/jit/Make-lang.in
@@ -40,10 +40,19 @@
# into the jit rule, but that needs a little bit of work
# to do the right thing within all.cross.
+ifneq (,$(findstring mingw,$(target)))
+LIBGCCJIT_FILENAME = libgccjit.dll
+
+jit: $(LIBGCCJIT_FILENAME) \
+ $(FULL_DRIVER_NAME)
+
+else
+
LIBGCCJIT_LINKER_NAME = libgccjit.so
LIBGCCJIT_VERSION_NUM = 0
LIBGCCJIT_MINOR_NUM = 0
LIBGCCJIT_RELEASE_NUM = 1
+
LIBGCCJIT_SONAME = $(LIBGCCJIT_LINKER_NAME).$(LIBGCCJIT_VERSION_NUM)
LIBGCCJIT_FILENAME = \
$(LIBGCCJIT_SONAME).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_RELEASE_NUM)
@@ -68,6 +77,7 @@ jit: $(LIBGCCJIT_FILENAME) \
$(LIBGCCJIT_SYMLINK) \
$(LIBGCCJIT_LINKER_NAME_SYMLINK) \
$(FULL_DRIVER_NAME)
+endif
# Tell GNU make to ignore these if they exist.
.PHONY: jit
@@ -84,9 +94,21 @@ jit_OBJS = attribs.o \
jit/jit-spec.o \
gcc.o
+ifneq (,$(findstring mingw,$(target)))
+jit_OBJS += jit/jit-w32.o
+endif
+
# Use strict warnings for this front end.
jit-warn = $(STRICT_WARN)
+ifneq (,$(findstring mingw,$(target)))
+# Create import library libgccjit.dll.a
+LIBGCCJIT_EXTRA_OPTS = -Wl,--out-implib,$(LIBGCCJIT_FILENAME).a
+else
+LIBGCCJIT_EXTRA_OPTS = $(LIBGCCJIT_VERSION_SCRIPT_OPTION) \
+ $(LIBGCCJIT_SONAME_OPTION)
+endif
+
# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
# in main.o
$(LIBGCCJIT_FILENAME): $(jit_OBJS) \
@@ -98,14 +120,16 @@ $(LIBGCCJIT_FILENAME): $(jit_OBJS) \
$(jit_OBJS) libbackend.a libcommon-target.a libcommon.a \
$(CPPLIB) $(LIBDECNUMBER) $(EXTRA_GCC_LIBS) $(LIBS) $(BACKENDLIBS) \
$(EXTRA_GCC_OBJS) \
- $(LIBGCCJIT_VERSION_SCRIPT_OPTION) \
- $(LIBGCCJIT_SONAME_OPTION)
+ $(LIBGCCJIT_EXTRA_OPTS)
+# Create symlinks when not building for Windows
+ifeq (,$(findstring mingw,$(target)))
$(LIBGCCJIT_SONAME_SYMLINK): $(LIBGCCJIT_FILENAME)
ln -sf $(LIBGCCJIT_FILENAME) $(LIBGCCJIT_SONAME_SYMLINK)
$(LIBGCCJIT_LINKER_NAME_SYMLINK): $(LIBGCCJIT_SONAME_SYMLINK)
ln -sf $(LIBGCCJIT_SONAME_SYMLINK) $(LIBGCCJIT_LINKER_NAME_SYMLINK)
+endif
#\f
# Build hooks:
@@ -275,19 +299,31 @@ selftest-jit:
#\f
# Install hooks:
-jit.install-common: installdirs
+jit.install-headers:
+ $(INSTALL_DATA) $(srcdir)/jit/libgccjit.h \
+ $(DESTDIR)$(includedir)/libgccjit.h
+ $(INSTALL_DATA) $(srcdir)/jit/libgccjit++.h \
+ $(DESTDIR)$(includedir)/libgccjit++.h
+
+ifneq (,$(findstring mingw,$(target)))
+jit.install-common: installdirs jit.install-headers
+# Install import library
+ $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME).a \
+ $(DESTDIR)$(libdir)/$(LIBGCCJIT_FILENAME).a
+# Install DLL file
$(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \
- $(DESTDIR)/$(libdir)/$(LIBGCCJIT_FILENAME)
+ $(DESTDIR)$(bindir)/$(LIBGCCJIT_FILENAME)
+else
+jit.install-common: installdirs jit.install-headers
+ $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \
+ $(DESTDIR)$(libdir)/$(LIBGCCJIT_FILENAME)
ln -sf \
$(LIBGCCJIT_FILENAME) \
- $(DESTDIR)/$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK)
+ $(DESTDIR)$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK)
ln -sf \
$(LIBGCCJIT_SONAME_SYMLINK)\
- $(DESTDIR)/$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK)
- $(INSTALL_DATA) $(srcdir)/jit/libgccjit.h \
- $(DESTDIR)/$(includedir)/libgccjit.h
- $(INSTALL_DATA) $(srcdir)/jit/libgccjit++.h \
- $(DESTDIR)/$(includedir)/libgccjit++.h
+ $(DESTDIR)$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK)
+endif
jit.install-man:
diff --git a/gcc/jit/config-lang.in b/gcc/jit/config-lang.in
index 89e3bfe0a..f8ef6042b 100644
--- a/gcc/jit/config-lang.in
+++ b/gcc/jit/config-lang.in
@@ -32,7 +32,7 @@ target_libs=""
gtfiles="\$(srcdir)/jit/dummy-frontend.c"
# The configuration requires --enable-host-shared
-# for jit to be supported.
+# for jit to be supported (only when not building for Mingw).
# Hence to get the jit, one must configure with:
# --enable-host-shared --enable-languages=jit
build_by_default="no"
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index d2c8bb4c1..0fddf04da 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -47,6 +47,10 @@ along with GCC; see the file COPYING3. If not see
#include "jit-builtins.h"
#include "jit-tempdir.h"
+#ifdef _WIN32
+#include "jit-w32.h"
+#endif
+
/* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
SET_DECL_C_BIT_FIELD.
These are redefined here to avoid depending from the C frontend. */
@@ -2159,8 +2163,10 @@ playback::compile_to_file::copy_file (const char *src_path,
gcc_assert (total_sz_in == total_sz_out);
if (get_logger ())
- get_logger ()->log ("total bytes copied: %ld", total_sz_out);
+ get_logger ()->log ("total bytes copied: %zu", total_sz_out);
+ /* fchmod does not exist in Windows. */
+#ifndef _WIN32
/* Set the permissions of the copy to those of the original file,
in particular the "executable" bits. */
if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
@@ -2168,6 +2174,7 @@ playback::compile_to_file::copy_file (const char *src_path,
"error setting mode of %s: %s",
dst_path,
xstrerror (errno));
+#endif
fclose (f_out);
}
@@ -2644,10 +2651,19 @@ dlopen_built_dso ()
{
JIT_LOG_SCOPE (get_logger ());
auto_timevar load_timevar (get_timer (), TV_LOAD);
- void *handle = NULL;
- const char *error = NULL;
+ result::handle handle = NULL;
result *result_obj = NULL;
+#ifdef _WIN32
+ /* Clear any existing error. */
+ SetLastError(0);
+
+ handle = LoadLibrary(m_tempdir->get_path_so_file ());
+ if (GetLastError() != 0) {
+ print_last_error();
+ }
+#else
+ const char *error = NULL;
/* Clear any existing error. */
dlerror ();
@@ -2656,6 +2672,8 @@ dlopen_built_dso ()
if ((error = dlerror()) != NULL) {
add_error (NULL, "%s", error);
}
+#endif
+
if (handle)
{
/* We've successfully dlopened the result; create a
diff --git a/gcc/jit/jit-result.c b/gcc/jit/jit-result.c
index c10e5a13c..633626412 100644
--- a/gcc/jit/jit-result.c
+++ b/gcc/jit/jit-result.c
@@ -27,13 +27,17 @@ along with GCC; see the file COPYING3. If not see
#include "jit-result.h"
#include "jit-tempdir.h"
+#ifdef _WIN32
+#include "jit-w32.h"
+#endif
+
namespace gcc {
namespace jit {
/* Constructor for gcc::jit::result. */
result::
-result(logger *logger, void *dso_handle, tempdir *tempdir_) :
+result(logger *logger, handle dso_handle, tempdir *tempdir_) :
log_user (logger),
m_dso_handle (dso_handle),
m_tempdir (tempdir_)
@@ -49,8 +53,11 @@ result::~result()
{
JIT_LOG_SCOPE (get_logger ());
+#ifdef _WIN32
+ FreeLibrary(m_dso_handle);
+#else
dlclose (m_dso_handle);
-
+#endif
/* Responsibility for cleaning up the tempdir (including "fake.so" within
the filesystem) might have been handed to us by the playback::context,
so that the cleanup can be delayed (see PR jit/64206).
@@ -72,8 +79,17 @@ get_code (const char *funcname)
JIT_LOG_SCOPE (get_logger ());
void *code;
- const char *error;
+#ifdef _WIN32
+ /* Clear any existing error. */
+ SetLastError(0);
+
+ code = (void *)GetProcAddress(m_dso_handle, funcname);
+ if (GetLastError() != 0) {
+ print_last_error ();
+ }
+#else
+ const char *error;
/* Clear any existing error. */
dlerror ();
@@ -82,6 +98,7 @@ get_code (const char *funcname)
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
}
+#endif
return code;
}
@@ -99,8 +116,17 @@ get_global (const char *name)
JIT_LOG_SCOPE (get_logger ());
void *global;
- const char *error;
+#ifdef _WIN32
+ /* Clear any existing error. */
+ SetLastError(0);
+
+ global = (void *)GetProcAddress(m_dso_handle, name);
+ if (GetLastError() != 0) {
+ print_last_error ();
+ }
+#else
+ const char *error;
/* Clear any existing error. */
dlerror ();
@@ -109,6 +135,7 @@ get_global (const char *name)
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
}
+#endif
return global;
}
diff --git a/gcc/jit/jit-result.h b/gcc/jit/jit-result.h
index 025860603..d8e940aaf 100644
--- a/gcc/jit/jit-result.h
+++ b/gcc/jit/jit-result.h
@@ -21,6 +21,10 @@ along with GCC; see the file COPYING3. If not see
#ifndef JIT_RESULT_H
#define JIT_RESULT_H
+#ifdef _WIN32
+#include <minwindef.h>
+#endif
+
namespace gcc {
namespace jit {
@@ -29,7 +33,13 @@ namespace jit {
class result : public log_user
{
public:
- result(logger *logger, void *dso_handle, tempdir *tempdir_);
+#ifdef _WIN32
+ typedef HMODULE handle;
+#else
+ typedef void* handle;
+#endif
+
+ result(logger *logger, handle dso_handle, tempdir *tempdir_);
virtual ~result();
@@ -40,7 +50,7 @@ public:
get_global (const char *name);
private:
- void *m_dso_handle;
+ handle m_dso_handle;
tempdir *m_tempdir;
};
diff --git a/gcc/jit/jit-tempdir.c b/gcc/jit/jit-tempdir.c
index 10c528faf..050d53409 100644
--- a/gcc/jit/jit-tempdir.c
+++ b/gcc/jit/jit-tempdir.c
@@ -24,7 +24,11 @@ along with GCC; see the file COPYING3. If not see
#include "jit-tempdir.h"
+#ifdef _WIN32
+#include "jit-w32.h"
+#endif
+#ifndef _WIN32
/* Construct a tempdir path template suitable for use by mkdtemp
e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
libiberty's choose_tempdir rather than hardcoding "/tmp/".
@@ -62,6 +66,7 @@ make_tempdir_path_template ()
return result;
}
+#endif
/* The constructor for the jit::tempdir object.
The real work is done by the jit::tempdir::create method. */
@@ -87,6 +92,9 @@ gcc::jit::tempdir::create ()
{
JIT_LOG_SCOPE (get_logger ());
+#ifdef _WIN32
+ m_path_tempdir = win_mkdtemp ();
+#else
m_path_template = make_tempdir_path_template ();
if (!m_path_template)
return false;
@@ -97,6 +105,8 @@ gcc::jit::tempdir::create ()
is unique. Hence no other (non-root) users should have access to
the paths within it. */
m_path_tempdir = mkdtemp (m_path_template);
+#endif
+
if (!m_path_tempdir)
return false;
log ("m_path_tempdir: %s", m_path_tempdir);
diff --git a/gcc/jit/jit-w32.c b/gcc/jit/jit-w32.c
new file mode 100644
index 000000000..99a6ed693
--- /dev/null
+++ b/gcc/jit/jit-w32.c
@@ -0,0 +1,255 @@
+/* Functions used by the Windows port of libgccjit.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+
+/* Required for rand_s */
+#define _CRT_RAND_S
+
+#include <cstdio>
+#include <cstdint>
+
+#include "jit-w32.h"
+
+#include "libiberty.h"
+
+#include <accctrl.h>
+#include <aclapi.h>
+
+namespace gcc {
+namespace jit {
+void
+print_last_error (void)
+{
+ LPSTR psz = NULL;
+ DWORD dwErrorCode;
+ dwErrorCode = GetLastError();
+ const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL,
+ dwErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ reinterpret_cast<LPSTR>(&psz),
+ 0,
+ NULL);
+ if (cchMsg > 0)
+ {
+ fprintf (stderr, "%s\n", psz);
+ LocalFree (psz);
+ }
+ else
+ {
+ fprintf (stderr, "Failed to retrieve error message string for error %lu\n",
+ dwErrorCode);
+ }
+}
+
+/* Helper function used for getting the SID belonging to the current user. */
+static TOKEN_USER*
+get_TOKEN_USER_current_user ()
+{
+ TOKEN_USER *result = NULL;
+
+ HANDLE process_token = INVALID_HANDLE_VALUE;
+
+ DWORD token_user_info_len;
+ TOKEN_USER *token_user = NULL;
+
+ /* Get current process access token. */
+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ,
+ &process_token))
+ return NULL;
+
+ /* Get necessary buffer size. */
+ if (!GetTokenInformation(process_token, TokenUser, NULL, 0, &token_user_info_len)
+ && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto cleanup;
+
+ token_user = (TOKEN_USER*) new char[token_user_info_len];
+
+ /* Get info about the user of the process */
+ if (!GetTokenInformation (process_token, TokenUser, token_user,
+ token_user_info_len, &token_user_info_len))
+ goto cleanup;
+
+ result = token_user;
+
+ cleanup:
+ if (process_token != INVALID_HANDLE_VALUE)
+ CloseHandle(process_token);
+
+ if (token_user != NULL && result == NULL)
+ delete[] (char*)token_user;
+
+ return result;
+}
+
+/* Helper function to create a directory with permissions such that only the
+ current user can access it. */
+static bool
+create_directory_for_current_user (const char * path)
+{
+ PACL pACL = NULL;
+ EXPLICIT_ACCESS ea;
+ SECURITY_ATTRIBUTES sa;
+ SECURITY_DESCRIPTOR SD;
+ DWORD dwRes;
+ bool result = true;
+ TOKEN_USER *token_user = NULL;
+
+ token_user = get_TOKEN_USER_current_user();
+ if (!token_user)
+ return false;
+
+ memset (&ea, 0, sizeof (EXPLICIT_ACCESS));
+ ea.grfAccessPermissions = GENERIC_ALL; /* Access to all. */
+ ea.grfAccessMode = SET_ACCESS; /* Set access and revoke everything else. */
+ /* This is necessary for the Windows Explorer GUI to show the correct tick
+ boxes in the "Security" tab. */
+ ea.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+ ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
+ ea.Trustee.ptstrName = (char*) token_user->User.Sid;
+
+ /* Create a new ACL that contains the new ACEs. */
+ dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
+ if (dwRes != ERROR_SUCCESS)
+ return false;
+
+ if (!InitializeSecurityDescriptor (&SD,
+ SECURITY_DESCRIPTOR_REVISION))
+ goto cleanup;
+
+ /* Add the ACL to the security descriptor. */
+ if (!SetSecurityDescriptorDacl (&SD,
+ TRUE, /* use pACL */
+ pACL,
+ FALSE)) /* not a default DACL */
+ goto cleanup;
+
+ /* Initialize a security attributes structure. */
+ sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = &SD;
+ sa.bInheritHandle = FALSE;
+
+ /* Finally create the directory */
+ if (!CreateDirectoryA (path, &sa))
+ result = false;
+
+ cleanup:
+ if (pACL)
+ LocalFree (pACL);
+
+ if (token_user)
+ delete[] (char*)token_user;
+
+ return result;
+}
+
+
+char *
+win_mkdtemp (void)
+{
+ char lpTempPathBuffer[MAX_PATH];
+
+ /* Gets the temp path env string (no guarantee it's a valid path). */
+ DWORD dwRetVal = GetTempPath (MAX_PATH, lpTempPathBuffer);
+ if (dwRetVal > MAX_PATH || (dwRetVal == 0))
+ {
+ print_last_error ();
+ return NULL;
+ }
+
+ /* Check that the directory actually exists. */
+ DWORD dwAttrib = GetFileAttributes (lpTempPathBuffer);
+ bool temp_path_exists = (dwAttrib != INVALID_FILE_ATTRIBUTES
+ && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
+ if (!temp_path_exists)
+ {
+ fprintf (stderr, "Path returned by GetTempPath does not exist: %s\n",
+ lpTempPathBuffer);
+ }
+
+ /* Make sure there is enough space in the buffer for the prefix and random
+ number.*/
+ int temp_path_buffer_len = dwRetVal;
+ const int appended_len = strlen ("\\libgccjit-123456");
+ if (temp_path_buffer_len + appended_len + 1 >= MAX_PATH)
+ {
+ fprintf (stderr, "Temporary file path too long for generation of random"
+ " directories: %s", lpTempPathBuffer);
+ }
+
+ /* This is all the space we have in the buffer to store the random number and
+ prefix. */
+ int extraspace = MAX_PATH - temp_path_buffer_len - 1;
+
+ int tries;
+ const int max_tries = 1000;
+
+ for (tries = 0; tries < max_tries; ++tries)
+ {
+ /* Get a random number in [0; UINT_MAX]. */
+ unsigned int rand_num;
+ if (rand_s (&rand_num) != 0)
+ {
+ fprintf (stderr,
+ "Failed to create a random number using rand_s(): %s\n",
+ _strerror (NULL));
+ return NULL;
+ }
+
+ /* Create 6 digits random number. */
+ rand_num = ((double)rand_num / ((double) UINT_MAX + 1 ) * 1000000);
+
+ /* Copy the prefix and random number to the buffer. */
+ snprintf (&lpTempPathBuffer[temp_path_buffer_len], extraspace,
+ "\\libgccjit-%06u", rand_num);
+
+ if (create_directory_for_current_user (lpTempPathBuffer))
+ break; // success!
+
+ /* If we can't create the directory because we got unlucky and the
+ directory already exists retry, otherwise fail. */
+ if (GetLastError () != ERROR_ALREADY_EXISTS)
+ {
+ print_last_error ();
+ return NULL;
+ }
+ }
+
+ if (tries == max_tries)
+ {
+ fprintf (stderr, "Failed to create a random directory in %s\n",
+ lpTempPathBuffer);
+ return NULL;
+ }
+
+ {
+ int allocate_len = temp_path_buffer_len + appended_len + 1;
+ char * result = XNEWVEC (char, allocate_len);
+ strcpy (result, lpTempPathBuffer);
+ return result;
+ }
+}
+}
+}
diff --git a/gcc/jit/jit-w32.h b/gcc/jit/jit-w32.h
new file mode 100644
index 000000000..4ab50d259
--- /dev/null
+++ b/gcc/jit/jit-w32.h
@@ -0,0 +1,30 @@
+/* Functions used by the Windows port of libgccjit.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+
+#include <windows.h>
+
+namespace gcc {
+namespace jit {
+extern void print_last_error (void);
+extern char * win_mkdtemp(void);
+}
+}
--
2.25.1.windows.1
next prev parent reply other threads:[~2020-05-28 1:28 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-24 20:02 Nicolas Bértolo
2020-05-24 20:48 ` David Malcolm
2020-05-25 19:48 ` Nicolas Bértolo
2020-05-26 18:40 ` David Malcolm
2020-05-28 1:27 ` Nicolas Bértolo [this message]
2020-05-28 19:00 ` David Malcolm
2020-05-28 19:51 ` Nicolas Bértolo
2020-05-28 20:46 ` David Malcolm
2020-06-02 16:26 ` JonY
2020-06-07 16:03 ` Nicolas Bértolo
2020-06-08 2:11 ` JonY
2020-06-11 22:02 ` Nicolas Bértolo
2020-06-12 0:19 ` JonY
2020-06-16 0:12 ` JonY
2020-06-16 0:15 ` Nicolas Bértolo
2020-05-29 14:48 ` NightStrike
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAFnS-Oncc2W_1UZv1BhHQLjBUGOiBi65wT6uv=mEkbDO9HMLJw@mail.gmail.com' \
--to=nicolasbertolo@gmail.com \
--cc=dmalcolm@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jit@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).