Mercurial > mxe-octave
view installer-files/octave-launch.c @ 5985:1b5d45d7afd4
octave-launch: Don't use undefined behavior (bug #61208).
* installer-files/octave-launch.c (get_num_physical_cores): Incrementing a
"void *" is undefined behavior. Use "char *" instead.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Fri, 26 Nov 2021 23:14:29 +0100 |
parents | 532c6ba0156f |
children | 88762923aa9a |
line wrap: on
line source
/* * Wrapper application to set octave env variables and then run octave * * Copyright (C) 2020-2021 John Donoghue <john.donoghue@ieee.org> * * This program 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 of the License, or (at your option) any later * version. * * This program 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 * this program; if not, see <http: *www.gnu.org/licenses/>. */ #include <windows.h> #include <shlwapi.h> #include <strsafe.h> static int ParentDir (wchar_t *dir) { int len = lstrlenW (dir); while (len > 0 && dir[len] != L'\\') len --; dir[len] = 0; return len; } static wchar_t * FilePart (wchar_t *dir) { int len = lstrlenW (dir); while (len > 0 && dir[len-1] != L'\\') len --; return &dir[len]; } static size_t get_num_physical_cores (void) { DWORD length; char *lpi; BOOL res; size_t num_physical_cores; size_t offset; length = 0; GetLogicalProcessorInformationEx (RelationProcessorCore, NULL, &length); if (GetLastError () != ERROR_INSUFFICIENT_BUFFER) return 0; lpi = malloc (length); res = GetLogicalProcessorInformationEx (RelationProcessorCore, (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) lpi, &length); if (! res) { free (lpi); return 0; } num_physical_cores = 0; offset = 0; do { const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX cur_lpi = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) (lpi + offset); offset += cur_lpi->Size; num_physical_cores++; } while (offset < length); free (lpi); return num_physical_cores; } // Set up environment and launch octave.exe with appropriate // arguments. NOTE: There are corresponding VBS and BAT script // versions of this program so any changes here may need to be made in // those scripts as well. int wmain (int argc, wchar_t **argv) { PROCESS_INFORMATION pi; // FIXME: There are currently have no checks to ensure that the // following fixed-size buffers are sufficiently large. MAX_PATH is // 260 on Winndows by default. But a user might have increased that // limit to 32767 characters by manually changing policy settings. // Maybe it would be better if we used C++ and std::string objects? // Note that the use of sizeof(path)-1 will fail if we switch to // using // // wchar_t *path = (wchar_t *) malloc (...); // // instead of literal character arrays. #define PATH_SZ 1024 wchar_t msyspath[PATH_SZ]; wchar_t rootpath[PATH_SZ]; wchar_t path[PATH_SZ]; wchar_t binpath[PATH_SZ]; int gui_arg_found = 0; int no_gui_arg_found = 0; int no_gui_libs = 0; int i; /* get path of us which we will assume is the root of the install */ DWORD nSize = GetModuleFileNameW (NULL, path, PATH_SZ-1); if (nSize) { while (nSize > 0 && path[nSize] != L'\\') nSize --; path[nSize] = L'\0'; } #ifdef NO_SHORT_PATH_NAMES StringCchCopyW (rootpath, PATH_SZ, path); #else /* transform to short paths to work around issues with spaces in paths */ /* FIXME: This won't help on systems with de-activated short paths */ nSize = GetShortPathNameW (path, rootpath, PATH_SZ-1); if (nSize == 0) StringCchCopyW (rootpath, PATH_SZ, path); #endif SetEnvironmentVariableW (L"MXE_ROOT", rootpath); /* get msys path and set env */ StringCchCopyW (msyspath, PATH_SZ, rootpath); StringCchCopyW (path, PATH_SZ, rootpath); StringCchCatW (path, PATH_SZ, L"\\mingw64\\bin\\octave.exe"); if (PathFileExistsW (path)) { SetEnvironmentVariableW (L"MSYSTEM", L"MINGW64"); StringCchCatW (msyspath, PATH_SZ, L"\\usr"); SetEnvironmentVariableW (L"MSYSPATH", msyspath); StringCchCatW (msyspath, PATH_SZ, L"\\bin"); StringCchCopyW (binpath, PATH_SZ, rootpath); StringCchCatW (binpath, PATH_SZ, L"\\mingw64\\bin"); } else { StringCchCopyW (path, PATH_SZ, rootpath); StringCchCatW (path, PATH_SZ, L"\\mingw32\\bin\\octave.exe"); if (PathFileExistsW (path)) { SetEnvironmentVariableW (L"MSYSTEM", L"MINGW32"); StringCchCatW (msyspath, PATH_SZ, L"\\usr"); SetEnvironmentVariableW (L"MSYSPATH", msyspath); StringCchCatW (msyspath, PATH_SZ, L"\\bin"); StringCchCopyW (binpath, PATH_SZ, rootpath); StringCchCatW (binpath, PATH_SZ, L"\\mingw32\\bin"); } else { SetEnvironmentVariableW (L"MSYSTEM", L"MSYS"); SetEnvironmentVariableW (L"MSYSPATH", msyspath); StringCchCatW (msyspath, PATH_SZ, L"\\bin"); StringCchCopyW (binpath, PATH_SZ, rootpath); StringCchCatW (binpath, PATH_SZ, L"\\bin"); } } /* binpath is to the octave bin dir so get the parent */ StringCchCopyW (path, PATH_SZ, binpath); ParentDir (path); #ifdef SHOW_PATHS MessageBoxW (NULL, rootpath, L"octroot", MB_OK); MessageBoxW (NULL, path, L"octhome", MB_OK); MessageBoxW (NULL, binpath, L"octbin", MB_OK); MessageBoxW (NULL, msyspath, L"msysbin", MB_OK); #endif /* qt paths * either %OCT_HOME%\qt5\plugins * or %OCT_HOME\plugins */ nSize = lstrlenW (path); StringCchCatW (path, PATH_SZ, L"\\qt5\\plugins"); SetEnvironmentVariableW (L"QT_PLUGIN_PATH", path); path[nSize] = L'\0'; /* exe paths */ { #define PATHBUF_SZ 8096 wchar_t pathbuffer[PATHBUF_SZ]; wchar_t newpathbuffer[PATHBUF_SZ]; nSize = GetEnvironmentVariableW (L"PATH", pathbuffer, PATHBUF_SZ-1); pathbuffer[nSize] = '\0'; /* set our paths first */ StringCchCopyW (newpathbuffer, PATHBUF_SZ, binpath); StringCchCatW (newpathbuffer, PATHBUF_SZ, L";"); StringCchCatW (newpathbuffer, PATHBUF_SZ, msyspath); StringCchCatW (newpathbuffer, PATHBUF_SZ, L";"); StringCchCatW (newpathbuffer, PATHBUF_SZ, pathbuffer); SetEnvironmentVariableW (L"PATH", newpathbuffer); } /* other env */ SetEnvironmentVariableW (L"TERM", L"cygwin"); SetEnvironmentVariableW (L"GNUTERM", L"wxt"); SetEnvironmentVariableW (L"GS", L"gs.exe"); /* home set */ nSize = GetEnvironmentVariableW (L"HOME", path, PATH_SZ-1); if (nSize == 0 || path[0] == 0) { wchar_t newhome[PATH_SZ]; nSize = GetEnvironmentVariableW (L"USERPROFILE", path, PATH_SZ-1); if (nSize == 0 || path[0] == 0) { /* build dir from drive and path */ wchar_t tmpbuff[PATH_SZ]; nSize = GetEnvironmentVariableW (L"HOMEDRIVE", tmpbuff, PATH_SZ-1); if (nSize) StringCchCopyW (path, PATH_SZ, tmpbuff); else path[0] = '\0'; nSize = GetEnvironmentVariableW (L"HOMEPATH", tmpbuff, PATH_SZ-1); if (nSize) StringCchCopyW (path, PATH_SZ, tmpbuff); } #ifdef NO_SHORT_PATH_NAMES StringCchCopyW (newhome, PATH_SZ, path); #else /* transform to short paths to work around issues with spaces in paths */ /* FIXME: This won't help on systems with de-activated short paths */ nSize = GetShortPathNameW (path, newhome, PATH_SZ-1); if (nSize == 0) StringCchCopyW (newhome, PATH_SZ, path); #endif SetEnvironmentVariableW (L"HOME", newhome); } /* set number of OpenBLAS threads */ nSize = GetEnvironmentVariableW (L"OPENBLAS_NUM_THREADS", NULL, 0); if (nSize == 0) { /* Only set if it wasn't already set in the environment */ size_t num_threads; num_threads = get_num_physical_cores (); if (num_threads > 0) { #define THREADS_SZ 64 wchar_t buffer[THREADS_SZ]; StringCchPrintfW (buffer, THREADS_SZ, L"%zu", num_threads); SetEnvironmentVariableW (L"OPENBLAS_NUM_THREADS", buffer); } } /* check for gui mode */ for (i = 1; i < argc; i++) { if (StrCmpW (argv[i], L"--no-gui-libs") == 0) { if (gui_arg_found) { /* Inconsistent options. We can't start the GUI without gui libs. How should we fail? For now, --no-gui-libs will override the other options. */ } no_gui_libs = 1; } else if (StrCmpW (argv[i], L"--gui") == 0 || StrCmpW (argv[i], L"--force-gui") == 0) { if (no_gui_libs) { /* Inconsistent options. We can't start the GUI without gui libs. How should we fail? For now, --no-gui-libs will override the other options. */ } gui_arg_found = 1; } else if (StrCmpW (argv[i], L"--no-gui") == 0) no_gui_arg_found = 1; /* NOTE: specifying both --no-gui and --gui is also an inconsistent set of options but we leave it to octave.exe to detect that. */ } #ifdef FIRST_TIME { /* change directory to USERPROFILE before starting Octave */ wchar_t tmpbuff[PATH_SZ]; nSize = GetEnvironmentVariableW (L"USERPROFILE", tmpbuff, PATH_SZ-1); if (nSize) StringCchCopyW (path, PATH_SZ, tmpbuff); SetCurrentDirectoryW (path); } #endif /* set up process args and start it */ { STARTUPINFO si; #define ARGBUF_SZ 4096 wchar_t argbuffer[ARGBUF_SZ]; ZeroMemory (&si, sizeof (si)); si.cb = sizeof (si); ZeroMemory (&pi, sizeof (pi)); StringCchCopyW (path, PATH_SZ, binpath); StringCchCopyW (argbuffer, ARGBUF_SZ, L"octave.exe "); StringCchCatW (path, PATH_SZ, L"\\octave.exe"); if (! (no_gui_libs || no_gui_arg_found)) { /* Unless --no-gui or --no-gui-libs is specified, we will use a GUI window. */ si.dwFlags = STARTF_USESHOWWINDOW; /* If none of the options --no-gui, --gui, or --force-gui were specified, then we'll add --gui to start the gui as most Windows users would expect. */ if (! gui_arg_found) StringCchCatW (argbuffer, ARGBUF_SZ, L"--gui "); } /* quote and append each arg */ for (i = 1; i < argc; i++) { StringCchCatW (argbuffer, ARGBUF_SZ, L"\""); StringCchCatW (argbuffer, ARGBUF_SZ, argv[i]); StringCchCatW (argbuffer, ARGBUF_SZ, L"\" "); } /* Start the child process */ int status = CreateProcessW (path, // Module name argbuffer, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO &pi); // Pointer to PROCESS_INFORMATION if (! status) return 1; } /* Wait until child process exits. */ WaitForSingleObject (pi.hProcess, INFINITE); /* Close process and thread handles */ CloseHandle (pi.hProcess); CloseHandle (pi.hThread); return 0; }