[wpiutil] Check MSVC Runtime (#7301)

This commit is contained in:
Thad House
2024-11-05 08:51:48 -08:00
committed by GitHub
parent 63e623d70b
commit f2d2500d1d
9 changed files with 202 additions and 2 deletions

View File

@@ -0,0 +1,73 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "wpi/RuntimeCheck.h"
#ifdef _WIN32
#include <cstdio>
#include <memory>
#include "Windows.h"
extern "C" int32_t WPI_IsRuntimeValid(uint32_t* foundMajor,
uint32_t* foundMinor,
uint32_t* expectedMajor,
uint32_t* expectedMinor,
WPI_String* runtimePath) {
HMODULE msvcRuntimeModule = GetModuleHandleW(L"msvcp140.dll");
if (!msvcRuntimeModule) {
return 1;
}
HRSRC versionResource = FindResourceW(msvcRuntimeModule, MAKEINTRESOURCEW(1),
MAKEINTRESOURCEW(16));
if (!versionResource) {
return 1;
}
HGLOBAL loadedVersion = LoadResource(msvcRuntimeModule, versionResource);
if (!loadedVersion) {
return 1;
}
// No need to unlock. Thats vestigial of windows before my time...
LPVOID lockedResource = LockResource(loadedVersion);
if (!lockedResource) {
return 1;
}
DWORD resourceSize = SizeofResource(msvcRuntimeModule, versionResource);
if (resourceSize == 0) {
return 1;
}
std::unique_ptr<char[]> resourceBuffer = // NOLINT
std::make_unique<char[]>(resourceSize); // NOLINT
std::memcpy(resourceBuffer.get(), lockedResource, resourceSize);
VS_FIXEDFILEINFO* fileInfo = nullptr;
UINT fileInfoLen = 0;
if (!VerQueryValueW(resourceBuffer.get(), L"\\",
reinterpret_cast<void**>(&fileInfo), &fileInfoLen)) {
return 1;
}
*foundMajor = HIWORD(fileInfo->dwProductVersionMS);
*foundMinor = LOWORD(fileInfo->dwProductVersionMS);
*expectedMajor = 14;
*expectedMinor = 40;
bool ValidRuntime =
*foundMajor != *expectedMajor || *foundMinor >= *expectedMinor;
if (!ValidRuntime) {
DWORD Size = MAX_PATH;
char* ValidBuffer = WPI_AllocateString(runtimePath, Size);
DWORD RetVal = GetModuleFileNameA(msvcRuntimeModule, ValidBuffer, Size);
while (RetVal == Size) {
Size *= 2;
WPI_FreeString(runtimePath);
ValidBuffer = WPI_AllocateString(runtimePath, Size);
RetVal = GetModuleFileNameA(msvcRuntimeModule, ValidBuffer, Size);
}
runtimePath->len = RetVal;
}
return ValidRuntime ? 1 : 0;
}
#else
extern "C" int32_t WPI_IsRuntimeValid(uint32_t*, uint32_t*, uint32_t*,
uint32_t*, WPI_String*) {
return 1;
}
#endif

View File

@@ -10,6 +10,7 @@
#include "wpi/DataLog.h"
#include "wpi/FileLogger.h"
#include "wpi/RawFrame.h"
#include "wpi/RuntimeCheck.h"
#include "wpi/Synchronization.h"
#include "wpi/jni_util.h"
#include "wpi/print.h"
@@ -25,13 +26,15 @@ static JException indexOobEx;
static JException interruptedEx;
static JException ioEx;
static JException nullPointerEx;
static JException msvcRuntimeEx;
static const JExceptionInit exceptions[] = {
{"java/lang/IllegalArgumentException", &illegalArgEx},
{"java/lang/IndexOutOfBoundsException", &indexOobEx},
{"java/lang/InterruptedException", &interruptedEx},
{"java/io/IOException", &ioEx},
{"java/lang/NullPointerException", &nullPointerEx}};
{"java/lang/NullPointerException", &nullPointerEx},
{"edu/wpi/first/util/MsvcRuntimeException", &msvcRuntimeEx}};
void wpi::ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg) {
illegalArgEx.Throw(env, msg);
@@ -78,6 +81,34 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
}
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: checkMsvcRuntime
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_util_WPIUtilJNI_checkMsvcRuntime
(JNIEnv* env, jclass)
{
uint32_t foundMajor;
uint32_t foundMinor;
uint32_t expectedMajor;
uint32_t expectedMinor;
WPI_String runtimePath;
if (!WPI_IsRuntimeValid(&foundMajor, &foundMinor, &expectedMajor,
&expectedMinor, &runtimePath)) {
static jmethodID ctor =
env->GetMethodID(msvcRuntimeEx, "<init>", "(IIIILjava/lang/String;)V");
jstring jmsvcruntime = MakeJString(env, wpi::to_string_view(&runtimePath));
jobject exception =
env->NewObject(msvcRuntimeEx, ctor, foundMajor, foundMinor,
expectedMajor, expectedMinor, jmsvcruntime);
WPI_FreeString(&runtimePath);
env->Throw(static_cast<jthrowable>(exception));
}
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
* Method: writeStderr