View Issue Details

IDProjectCategoryView StatusLast Update
0002131NoesisGUIC++ SDKpublic2021-12-06 17:06
Reportersteveh Assigned Tojsantos  
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
Target Version3.1.2Fixed in Version3.1.2 
Summary0002131: 100KB of stack space used for parsing property paths
DescriptionHi guys, we're getting crashes on PS4 due to runing out of stack space when parsing a path, I've attached the callstack from where the issue begins.

So the issue starts when we invoke the following:

bool PropertyPath::UpdatePathItems() const
{
    if (!mPath.Empty() && mPathItems.Empty())
    {
        Parser<> parser(mPath.Str());
        PE::PropertyPathExpr expr;
        ParseResult pr = parser.TryParseFull(expr);

mPath.Str() is "(UIElement.Opacity)"

At this point, sizeof(expr) is 7072 bytes, which primarily consists of 2320 bytes of CollectionPath and 4752 bytes of CombinedPath.

This then gets tripled in CombinedPath::TryParse


    template<class SkipExpr>
    ParseResult TryParse(const ParserSource<SkipExpr>& input)
    {
        typedef Seq5<AnyIdentifier, Ch<':'>, AnyIdentifier, Ch<'.'>, AnyIdentifier>
            PropertyWithPrefix;
        typedef Seq3<AnyIdentifier, Ch<'.'>, List<AnyIdentifier, Ch<'.'>, 12>>
            PropertyWithNamespaces;
        typedef Seq3<Ch<'('>, Or<PropertyWithPrefix, PropertyWithNamespaces>, Ch<')'>>
            QualifiedProperty;
        typedef Or<AnyIdentifier, QualifiedProperty> Property;

        List<Or<Indexer, Seq<Property, Opt<Indexer>>>, Ch<'.'>, NumItems> expr;


sizeof(expr) is now 24,080 bytes. This then gets quadrupled in List::TryParse

struct List
{
    template<class SkipExpr>
    ParseResult TryParse(const ParserSource<SkipExpr>& input)
    {
        Seq<Item, Star<Seq<Separator, Item>>> expr;


sizeof(expr) is now 99,536 bytes.


This blows up our stack and we run out of space. We've recently reduced our stack from 1MB to 384KB and this issue has arisen. We can temporarily patch this up by reducing the numbers somewhat so PropertyPath isn't 7kB to begin with which is what I think we're going to try.

Is there any way you could look at the usage of stack space so we don't require so much space? That would be much appreciated. Alternatively, can you suggest any workaround for the time being? Do you think it's safe to tweak the static counts in the CombinedPath and CollectionPath structs? Are there any hard limits to adhere to the WPF standards, or are these numbers ones you found worked well?

Cheers,

-Steven
TagsNo tags attached.
PlatformAny

Activities

steveh

steveh

2021-09-24 15:55

reporter  

callstack.txt (10,086 bytes)   
 	Game_PS4.elf!Noesis::PE::AnyIdentifier::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 1827 + 10 bytes	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Parser<Noesis::DefaultSkip>::TryParse<Noesis::PE::AnyIdentifier>(Noesis::PE::AnyIdentifier& expr) Line 256	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 197	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 622	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Parser<Noesis::DefaultSkip>::TryParse<Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>>(Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>& expr) Line 256	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 200	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 622	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Parser<Noesis::DefaultSkip>::TryParse<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>>(Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>& expr) Line 256	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>,Noesis::PE::Opt<Noesis::PE::Indexer>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 165	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Or<Noesis::PE::Indexer,Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>,Noesis::PE::Opt<Noesis::PE::Indexer>>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 622	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Parser<Noesis::DefaultSkip>::TryParse<Noesis::PE::Or<Noesis::PE::Indexer,Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>,Noesis::PE::Opt<Noesis::PE::Indexer>>>>(Noesis::PE::Or<Noesis::PE::Indexer,Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>,Noesis::PE::Opt<Noesis::PE::Indexer>>>& expr) Line 256	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::Indexer,Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>,Noesis::PE::Opt<Noesis::PE::Indexer>>>,Noesis::PE::Star<Noesis::PE::Seq<Noesis::PE::Ch<46>,Noesis::PE::Or<Noesis::PE::Indexer,Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>,Noesis::PE::Opt<Noesis::PE::Indexer>>>>,32u>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 165	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::List<Noesis::PE::Or<Noesis::PE::Indexer,Noesis::PE::Seq<Noesis::PE::Or<Noesis::PE::AnyIdentifier,Noesis::PE::Seq3<Noesis::PE::Ch<40>,Noesis::PE::Or<Noesis::PE::Seq5<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<58>,Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::AnyIdentifier>,Noesis::PE::Seq3<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,Noesis::PE::List<Noesis::PE::AnyIdentifier,Noesis::PE::Ch<46>,12u>>>,Noesis::PE::Ch<41>>>,Noesis::PE::Opt<Noesis::PE::Indexer>>>,Noesis::PE::Ch<46>,8u>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 1933	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::CombinedPath::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 121	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::Or3<Noesis::PE::Ch<46>,Noesis::PE::CollectionPath,Noesis::PE::CombinedPath>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 662	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Parser<Noesis::DefaultSkip>::TryParse<Noesis::PE::Or3<Noesis::PE::Ch<46>,Noesis::PE::CollectionPath,Noesis::PE::CombinedPath>>(Noesis::PE::Or3<Noesis::PE::Ch<46>,Noesis::PE::CollectionPath,Noesis::PE::CombinedPath>& expr) Line 256	C++	Symbols loaded.
 	Game_PS4.elf![Inline Function] Noesis::PE::Opt<Noesis::PE::Or3<Noesis::PE::Ch<46>,Noesis::PE::CollectionPath,Noesis::PE::CombinedPath>>::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input, const Noesis::ParserSource<Noesis::DefaultSkip>& __formal0) Line 1426	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PE::PropertyPathExpr::TryParse<Noesis::DefaultSkip>(const Noesis::ParserSource<Noesis::DefaultSkip>& input) Line 330	C++	Symbols loaded.
>	Game_PS4.elf!Noesis::Parser<Noesis::DefaultSkip>::TryParse<Noesis::PE::PropertyPathExpr>(Noesis::PE::PropertyPathExpr& expr) Line 256	C++	Symbols loaded.
 	Game_PS4.elf![Inline Function] Noesis::Parser<Noesis::DefaultSkip>::TryParseFull<Noesis::PE::PropertyPathExpr>(Noesis::PE::PropertyPathExpr& expr, Noesis::PE::PropertyPathExpr& __formal0) Line 275	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PropertyPath::UpdatePathItems() Line 441	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::PropertyPath::EnumPathElements(Noesis::BaseComponent* source_, bool enumLastValue, const Noesis::PropertyPath::EnumPathElementsDelegate& delegate, void* context) Line 128 + 5 bytes	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Storyboard::ResolveTarget(Noesis::Timeline* timeline, Noesis::FrameworkElement* fe, Noesis::FrameworkElement* ns) Line 629 + 5 bytes	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Storyboard::ResolveTargets(Noesis::FrameworkElement* fe, Noesis::FrameworkElement* ns, Noesis::Clock* clock, Noesis::Storyboard::Animations& targets) Line 537	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Storyboard::ResolveTargets(Noesis::FrameworkElement* fe, Noesis::FrameworkElement* ns, Noesis::Clock* clock, Noesis::Storyboard::Animations& targets) Line 528	C++	Symbols loaded.
 	Game_PS4.elf!Noesis::Storyboard::InternalBegin(Noesis::FrameworkElement* target, Noesis::FrameworkElement* nameScope, enum Noesis::HandoffBehavior handoffBehavior, bool isControllable) Line 361	C++	Symbols loaded.
callstack.txt (10,086 bytes)   
jsantos

jsantos

2021-09-27 14:13

manager   ~0007481

For efficiency purposes we are abusing the stack in many places but 100KB is too much. :) We will fix the expression.

Thanks!
jsantos

jsantos

2021-12-06 17:05

manager   ~0007654

The CombinedPath was taking 137776 bytes (7072 --> 7088 --> 24080 -> 99536).

We fixed this to have both paths under 10 Kb (6832 -> 2464 [CombinedPath] and 6832 -> 4152 [CollectionPath]).

This also brings performance optimizations as extra copies are avoided.

I consider this fixed, please reopen if necessary.

Issue History

Date Modified Username Field Change
2021-09-24 15:55 steveh New Issue
2021-09-24 15:55 steveh File Added: callstack.txt
2021-09-27 14:12 jsantos Assigned To => jsantos
2021-09-27 14:12 jsantos Status new => assigned
2021-09-27 14:13 jsantos Target Version => 3.1.2
2021-09-27 14:13 jsantos Description Updated
2021-09-27 14:13 jsantos Note Added: 0007481
2021-12-06 17:05 jsantos Status assigned => resolved
2021-12-06 17:05 jsantos Resolution open => fixed
2021-12-06 17:05 jsantos Note Added: 0007654
2021-12-06 17:06 jsantos Fixed in Version => 3.1.2