,
This crash happened once, after having edited things for a long while. It happened when re-opening the Project Settings dialog (it had previously been opened during this session.) My first-order-approximation guess would be that there is some memory leak in the editor, and it ran out of RAM and got a NULL pointer. My second-order-approximation guess would be that the cursor happened to be/move over the tab fields on the left in that dialog when opening it, and somehow the UI code asked for the widget information before it was fully loaded/constructed. These are just hunches, though.
MyItemFromWidget() is part of an Unreal Engine internal source file, not my source file. In fact, no source file of mine is on the stack.
I’m 99% sure it’s not the custom code I’ve added that’s the problem, but in case you care, here it is:
// Copyright 2015 Jon Watte
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include <type_traits>
#include "LocalStorage.generated.h"
USTRUCT()
struct FLocalTime {
GENERATED_USTRUCT_BODY()
UPROPERTY()
int32 Year;
UPROPERTY()
int32 Month;
UPROPERTY()
int32 Day;
UPROPERTY()
int32 Hour;
UPROPERTY()
int32 Minute;
UPROPERTY()
int32 Second;
UPROPERTY()
int32 DayOfWeek;
FLocalTime() {
Year = 0;
Month = 0;
Day = 0;
Hour = 0;
Minute = 0;
Second = 0;
DayOfWeek = 0;
}
};
UCLASS()
class TABLETPUZZLEONE_API ULocalStorage : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Storage")
static void ClearStorage();
UFUNCTION(BlueprintCallable, Category = "Storage")
static bool LoadStorageFrom(const FString &name = FString(TEXT("LocalData")));
UFUNCTION(BlueprintCallable, Category = "Storage")
static bool SaveStorageTo(const FString &name = FString(TEXT("LocalData")));
UFUNCTION(BlueprintCallable, Category = "Storage")
static void SetStorageVariable(const FString &name = FString(TEXT("KeyName")), const FString &value = FStrin
g(TEXT("Value")));
UFUNCTION(BlueprintCallable, Category = "Storage")
static void UnsetStorageVariable(const FString &name = FString(TEXT("KeyName")));
UFUNCTION(BlueprintPure, Category = "Storage")
static FString GetStorageVariable(const FString &name = FString(TEXT("KeyName")));
UFUNCTION(BlueprintCallable, Category = "Time")
static FString GetLocalDate(const int32 TimeStamp);
UFUNCTION(BlueprintCallable, Category = "Time")
static FString GetLocalTime(const int32 TimeStamp);
UFUNCTION(BlueprintCallable, Category = "Time")
static int32 GetLocalTimestamp();
UFUNCTION(BlueprintPure, Category = "Time")
static void StringToLocalTimestamp(bool &Success, int32 &Timestamp, const FString &Input = FString(TEXT("200
0-01-01 00:00:00")));
UFUNCTION(BlueprintPure, Category = "Time")
static FLocalTime ConvertLocalTimestamp(const int32 TimeStamp);
UFUNCTION(BlueprintPure, Category = "Time")
static int32 ConvertLocalTime(const FLocalTime &time);
UFUNCTION(BlueprintPure, Category = "Time")
static void BreakLocalTime(const FLocalTime &time, int32 &year, int32 &month, int32 &day, int32 &hour, int32
&minute, int32 &second, int32 &dayOfWeek);
UFUNCTION(BlueprintPure, Category = "Time")
static FLocalTime MakeLocalTime(int32 Year, int32 Month, int32 Day, int32 Hour, int32 Minute, int32 Second);
};
// Copyright 2015 Jon Watte
#include "TabletPuzzleOne.h"
#include "LocalStorage.h"
#if defined(_MSC_VER)
#pragma warning(disable: 4996)
#endif
#include <time.h>
#include "Runtime/Core/Public/Misc/CoreMisc.h"
struct vars {
vars() { next = 0; }
FString name;
FString value;
vars *next;
};
static vars ** vtop_;
static size_t nvars_;
static uint32 hashval(FString const &f)
{
TCHAR const *tch = *f;
TCHAR const *end = tch + f.Len();
uint32 h = 0;
while (tch != end) {
h = h * 15485863 + 32452843 + *tch;
tch++;
}
return h;
}
static void add(FString &fs, FString const &src)
{
TCHAR const *ptr = *src;
TCHAR const *end = ptr + src.Len();
while (ptr != end) {
switch (*ptr) {
case '\n':
fs += TEXT("\\n");
break;
case '\\':
fs += TEXT("\\\\");
break;
case '=':
fs += TEXT("\\=");
break;
default:
fs += *ptr;
}
++ptr;
}
}
bool ULocalStorage::LoadStorageFrom(FString const &name)
{
FString fp = FPaths::GameSavedDir() + TEXT("/") + name;
ClearStorage();
FString buf;
if (!FFileHelper::LoadFileToString(buf, *fp, 0)) {
return false;
}
if (!vtop_) {
nvars_ = 64;
vtop_ = new vars *[64];
memset(vtop_, 0, sizeof(*vtop_)*nvars_);
}
TCHAR const *tch = *buf;
TCHAR const *end = tch + buf.Len();
while (tch != end) {
vars *v = new vars();
bool quote = false;
while (tch != end) {
if (quote) {
switch (*tch) {
case 'n':
v->name += TEXT("\n");
break;
default:
v->name += *tch;
break;
}
quote = false;
} else if (*tch == '\\') {
quote = true;
} else if (*tch == '=') {
break;
} else if (*tch == '\n') {
UE_LOG(LogTemp, Warning, TEXT("Premature end of line"));
break;
} else {
v->name += *tch;
}
++tch;
}
if (tch == end) {
UE_LOG(LogTemp, Warning, TEXT("Premature end of file"));
break;
}
quote = false;
// skip equals
++tch;
while (tch != end) {
if (quote) {
switch (*tch) {
case 'n':
v->value += TEXT("\n");
break;
default:
v->value += *tch;
break;
}
quote = false;
}
else if (*tch == '\\') {
quote = true;
}
else if (*tch == '=') {
UE_LOG(LogTemp, Warning, TEXT("Unexpected '=' in value"));
v->value += *tch;
}
else if (*tch == '\n') {
break;
}
else {
v->value += *tch;
}
++tch;
}
uint32 h = hashval(v->name) & (nvars_ - 1);
vars **vp = &vtop_[h];
v->next = *vp;
*vp = v;
if (tch != end) {
// skip newline
++tch;
}
}
return true;
}
bool ULocalStorage::SaveStorageTo(FString const &name)
{
FString fp = FPaths::GameSavedDir() + TEXT("/") + name;
if (!vtop_) {
return false;
}
FString fs;
for (size_t i = 0; i != nvars_; ++i) {
vars *vp = vtop_[i];
while (vp) {
add(fs, vp->name);
fs += TEXT("=");
add(fs, vp->value);
fs += TEXT("\n");
vp = vp->next;
}
}
/* let's do a safe-save */
FString fp2 = fp + ".t";
bool s = FFileHelper::SaveStringToFile(fs, *fp2);
if (s) {
s = IFileManager::Get().Move(*fp, *fp2, true, true, true, false);
}
return s;
}
void ULocalStorage::ClearStorage()
{
if (vtop_) {
for (size_t i = 0; i != nvars_; ++i) {
vars *vp = vtop_[i];
while (vp) {
vars *d = vp;
vp = vp->next;
delete d;
}
}
delete[] vtop_;
}
vtop_ = nullptr;
nvars_ = 0;
}
void ULocalStorage::SetStorageVariable(FString const &name, FString const &value)
{
if (!vtop_) {
vtop_ = new vars *[64];
nvars_ = 64;
memset(vtop_, 0, sizeof(*vtop_)*nvars_);
}
uint32 h = hashval(name) & (nvars_ - 1);
vars *vp = vtop_[h];
while (vp) {
if (vp->name == name) {
vp->value = value;
return;
}
vp = vp->next;
}
vars *v = new vars();
v->name = name;
v->value = value;
v->next = vtop_[h];
vtop_[h] = v;
}
void ULocalStorage::UnsetStorageVariable(FString const &name)
{
if (!vtop_) {
return;
}
uint32 h = hashval(name) & (nvars_ - 1);
vars **vp = &vtop_[h];
while (*vp) {
if ((*vp)->name == name) {
vars *d = *vp;
*vp = (*vp)->next;
delete d;
return;
}
vp = &(*vp)->next;
}
}
FString ULocalStorage::GetStorageVariable(FString const &name)
{
if (!vtop_) {
return FString();
}
uint32 h = hashval(name) & (nvars_ - 1);
vars *vp = vtop_[h];
while (vp) {
if (vp->name == name) {
return vp->value;
}
vp = vp->next;
}
return FString();
}
FString ULocalStorage::GetLocalDate(int32 TimeStamp)
{
char buf[50];
time_t t = (time_t)(uint32)TimeStamp;
if (!t) {
time(&t);
}
strftime(buf, 50, "%Y-%m-%d", localtime(&t));
return FString(buf);
}
FString ULocalStorage::GetLocalTime(int32 TimeStamp)
{
char buf[50];
time_t t = (time_t)(uint32)TimeStamp;
if (!t) {
time(&t);
}
strftime(buf, 50, "%H:%M:%S", localtime(&t));
return FString(buf);
}
void ULocalStorage::StringToLocalTimestamp(bool &Success, int32 &Timestamp, const FString &Input)
{
struct tm tt = { 0 };
int n = swscanf(*Input, TEXT(" %d - %d - %d %d : %d : %d"), &tt.tm_year, &tt.tm_mon, &tt.tm_mday, &tt.tm_hour, &tt.t
m_min, &tt.tm_sec);
if (tt.tm_year > 0) {
tt.tm_year -= 1900;
}
if (tt.tm_mon > 0) {
tt.tm_mon -= 1;
}
Timestamp = (int32)(uint32)mktime(&tt);
Success = (n == 6);
}
int32 ULocalStorage::GetLocalTimestamp()
{
time_t t = 0;
time(&t);
return (int32)(uint32)t;
}
FLocalTime ULocalStorage::ConvertLocalTimestamp(const int32 TimeStamp)
{
time_t t = (uint32)TimeStamp;
struct tm tt = *localtime(&t);
FLocalTime ret;
ret.Year = tt.tm_year+1900;
ret.Month = tt.tm_mon+1;
ret.Day = tt.tm_mday;
ret.Hour = tt.tm_hour;
ret.Minute = tt.tm_min;
ret.Second = tt.tm_sec;
ret.DayOfWeek = tt.tm_wday;
return ret;
}
int32 ULocalStorage::ConvertLocalTime(const FLocalTime &time)
{
struct tm tt;
memset(&tt, 0, sizeof(tt));
tt.tm_hour = time.Hour;
tt.tm_min = time.Minute;
tt.tm_sec = time.Second;
tt.tm_year = time.Year-1900;
tt.tm_mon = time.Month-1;
tt.tm_mday = time.Day;
return (int32)(uint32)mktime(&tt);
}
void ULocalStorage::BreakLocalTime(const FLocalTime &Time, int &Year, int &Month, int &Day, int &Hour, int &Minute, int
&Second, int &DayOfWeek)
{
Year = Time.Year;
Month = Time.Month;
Day = Time.Day;
Hour = Time.Hour;
Minute = Time.Minute;
Second = Time.Second;
DayOfWeek = Time.DayOfWeek;
}
FLocalTime ULocalStorage::MakeLocalTime(int Year, int Month, int Day, int Hour, int Minute, int Second)
{
FLocalTime Time;
Time.Year = Year;
Time.Month = Month;
Time.Day = Day;
Time.Hour = Hour;
Time.Minute = Minute;
Time.Second = Second;
return ConvertLocalTimestamp(ConvertLocalTime(Time));
}