Crash on null pointer trying to open Project Settings

I was happily editing a blueprint project (using stock 4.7.5 with a small amount of additional C++ code) when it crashed on a null pointer. I couldn’t get visual studio to make the engine send a crash report, so here’s my report.
I had just opened the Project Settings panel (to check what name I gave a particular Android achievement.)

UE4Editor-PropertyEditor.dll!TSet<TPair<TSharedRef<IDetailTreeNode,0>,FSparseItemInfo>,TDefaultMapKeyFuncs<TSharedRef<IDetailTreeNode,0>,FSparseItemInfo,0>,FDefaultSetAllocator>::FindId(const TSharedRef<IDetailTreeNode,0> & Key) Line 507C++
UE4Editor-PropertyEditor.dll!STreeView<TSharedRef<IDetailTreeNode,0> >::Private_IsItemExpanded(const TSharedRef<IDetailTreeNode,0> & TheItem) Line 272C++
>UE4Editor-PropertyEditor.dll!STableRow<TSharedPtr<IDetailTreeNode,0> >::IsItemExpanded() Line 674C++
UE4Editor-Slate.dll!SExpanderArrow::GetExpanderImage() Line 67C++
UE4Editor-Slate.dll!TBaseSPMethodDelegateInstance<1,SExpanderArrow,0,FSlateBrush const * __ptr64 __cdecl(void)>::Execute() Line 282C++
UE4Editor-Slate.dll!SImage::ComputeDesiredSize() Line 66C++
UE4Editor-SlateCore.dll!SWidget::CacheDesiredSize() Line 392C++
UE4Editor-SlateCore.dll!SWidget::SlatePrepass() Line 380C++
UE4Editor-SlateCore.dll!SWidget::SlatePrepass() Line 380C++
UE4Editor-SlateCore.dll!SWidget::SlatePrepass() Line 380C++
UE4Editor-SlateCore.dll!SWidget::SlatePrepass() Line 380C++
UE4Editor-SlateCore.dll!SWidget::SlatePrepass() Line 380C++
UE4Editor-SlateCore.dll!SWidget::SlatePrepass() Line 380C++
UE4Editor-PropertyEditor.dll!SListView<TSharedRef<IDetailTreeNode,0> >::ScrollBy(const FGeometry & MyGeometry, float ScrollByAmountInSlateUnits, EAllowOverscroll InAllowOverscroll) Line 1216C++
UE4Editor-Slate.dll!STableViewBase::OnMouseWheel(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) Line 411C++
UE4Editor-Slate.dll!FSlateApplication::ProcessMouseWheelOrGestureEvent::__l12::<lambda>(const FArrangedWidget & CurWidget, const FPointerEvent & Event) Line 4107C++
UE4Editor-Slate.dll!FEventRouter::Route<FReply,FEventRouter::FBubblePolicy,FPointerEvent,FReply <lambda>(const FArrangedWidget &, const FPointerEvent &) >(FSlateApplication * ThisApplication, FEventRouter::FBubblePolicy RoutingPolicy, FPointerEvent EventCopy, const FSlateApplication::ProcessMouseWheelOrGestureEvent::__l12::FReply <lambda>(const FArrangedWidget &, const FPointerEvent &) & Lambda) Line 202C++
UE4Editor-Slate.dll!FSlateApplication::ProcessMouseWheelOrGestureEvent(FPointerEvent & InWheelEvent, const FPointerEvent * InGestureEvent) Line 4111C++
UE4Editor-Slate.dll!FSlateApplication::OnMouseWheel(const float Delta) Line 4071C++
UE4Editor-Core.dll!FWindowsApplication::ProcessDeferredMessage(const FDeferredWindowsMessage & DeferredMessage) Line 1432C++
UE4Editor-Core.dll!FWindowsApplication::ProcessDeferredEvents(const float TimeDelta) Line 1694C++
UE4Editor-Slate.dll!FSlateApplication::Tick() Line 1219C++
UE4Editor.exe!FEngineLoop::Tick() Line 2284C++
UE4Editor.exe!GuardedMain(const wchar_t * CmdLine, HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, int nCmdShow) Line 142C++
UE4Editor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow) Line 191C++
UE4Editor.exe!__tmainCRTStartup() Line 618C
kernel32.dll!BaseThreadInitThunk()Unknown
ntdll.dll!RtlUserThreadStart()Unknown

The “Key” is NULL because the “MyItem” is NULL in IsItemExpanded().
So, apparently, Private_MyItemFromWidget(this) can return NULL; presumably when called right during/after construction.

lHey -

There are a few questions I’d like to ask to help me understand and reproduce this issue. Does the crash happen in a new project with no additional content? Does the crash occur when only running the editor rather than running it through Visual Studio? How is MyItemFromWidget() written? If possible could you post the header and source files for the code you added to the project? Let us know if you think of any additional information that may help.

Cheers

,

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));
}

see below for answers

Hey -

Thanks for the added info and code used. I’m still having trouble reproducing this crash and wanted to verify that it occurred when opening the Project Settings window from the Edit menu. Were you in the main viewport or opening from another window such as Blueprints or Persona? Were you working with your code at the time of the crash (fresh compile or adding a class to the project)? Have you experienced this crash in 4.7.6? Are you able to reproduce the crash in a new empty project with no additional content? Additionally, if you are still experiencing this crash can you also attach the log files from the crash?

Hey -

Would it be possible for you to send us a sample project where this issue is occuring? If you’re able to upload the project to dropbox you can then send me a private message on the forms with the link to the dropbox.

Thanks

Hey -

We’ve not heard from you in a few days, so we are marking this post as resolved for tracking purposes. If the project is still crashing when attempting to open the Project Settings menu, please feel free to reopen this post by posting a comment along with the a sample project where the crash is occurring for us to investigate.

Cheers