Thread: MSVSC++ program works incorrectly when inline function optimization is turned on.

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Sep 2020
    Posts
    15

    MSVSC++ program works incorrectly when inline function optimization is turned on.

    The program works fine in debug mode. It doesn't in release mode with optimizations enabled, more specifically "Inline Function Expansion" enabled. Disabling inline expansion (/0b0) which is on by default and keeping the rest of optimizations at their default value, makes the program behave correctly again.

    In my experience, these sort of problems arise when I resort to undefined behavior. So I'm posting a snippet of code that showcases the specific section of the code that is misbehaving plus the required extra information to give clarity to the pertinent section, in hopes someone can spot a glaring mistake of which I am unaware.

    Header file with t_item_data definition:
    Code:
    namespace CraftingUtils
    {
    #define UINTX_T UInt64
    
    struct                        t_item_data
    {
        union                    details
        {
            EnchantmentItem*    enchantment;
            float                temperval;
    
            explicit            details(float);
            explicit            details (EnchantmentItem*);
            //~details(void);
        };
        typedef                    std::vector<std::pair<details, unsigned> > t_stats;
        t_stats                    stats;
        unsigned                count;
        unsigned                created;
        bool                    processed;
    
        explicit                t_item_data(void);
        explicit                t_item_data(t_stats*);
        t_item_data(const t_item_data&) = delete;
        t_item_data &operator = (const t_item_data&) = delete;
        //~t_item_data(void);
    };
    ...
    ...
    ...
    Source file, problematic function plus helper functions:
    Code:
    static std::pair<t_item_data::details, unsigned> *find_stat(
        t_item_data::t_stats *list, const t_item_data::details *stat)
    {
        t_item_data::t_stats::iterator element = (*list).begin();
    
        for (unsigned i = (*list).size(); i; --i)
        {   if (*(UINTX_T*)&(*element).first == *(UINTX_T*)stat)
                return (&*element);
            ++element;
        }
        return (nullptr);
    }
    
    static bool get_item_enchantments(InventoryEntryData* invdata, t_item_data::t_stats *stats)
    {
        ExtendDataList::Iterator    list = (*(*invdata).extendDataList).Begin();
        BaseExtraList                *extra_data;
        bool                        retval = false;
    
        while ((extra_data = list.Get() ) )
        {   ExtraEnchantment* extra_ench =
                DYNAMIC_CAST((*extra_data).GetByType(kExtraData_Enchantment), BSExtraData, ExtraEnchantment);
    
            if (extra_ench)
            {   std::pair<t_item_data::details, unsigned>    *match;
                t_item_data::details                        enchantment((*extra_ench).enchant);
    
                if (!(match = find_stat(stats, &enchantment) ) )
                    (*stats).emplace_back(enchantment, 1);
                else ++(*match).second;
                retval = true;
            }
            ++list;
        }
        return (retval);
    }
    
    static bool get_item_temperstats(InventoryEntryData *invdata, t_item_data::t_stats *stats)
    {
        ExtendDataList::Iterator    list = (*(*invdata).extendDataList).Begin();
        BaseExtraList                *extra_data;
        bool                        retval = false;
    
        while ((extra_data = list.Get() ) )
        {   ExtraHealth *extra_health =
                DYNAMIC_CAST((*extra_data).GetByType(kExtraData_Health), BSExtraData, ExtraHealth);
    
            if (extra_health)
            {   std::pair<t_item_data::details, unsigned>    *match;
                t_item_data::details                        temperval((*extra_health).health);
    
                if (!(match = find_stat(stats, &temperval) ) )
                    (*stats).emplace_back(temperval, 1);
                else ++(*match).second;
                retval = true;
            }
            ++list;
        }
        return (retval);
    }
    
    //__declspec(noinline)
    static void detect_item_changes(void)
    {
        std::vector<std::pair<t_item_data::details, unsigned> >    statlist;
        std::vector<std::pair<t_item_data::details, unsigned> >    created;
        std::map<TESForm*, t_item_data>::iterator                items = records.begin();
        InventoryEntryData                                        *invdata;
        bool (*get_stats)(InventoryEntryData*, t_item_data::t_stats*) = nullptr;
    
        switch (service.type)
        {
        case t_service::temper:
            get_stats = &get_item_temperstats;
            break ;
        case t_service::enchant:
            get_stats = &get_item_enchantments;
            break ;
        }
        for (std::map<TESForm*, t_item_data>::const_iterator end = records.cend(); items != end; ++items)
        {   invdata = get_pcinvdata_for_item((*items).first);
            if (!get_stats)
            {   if (invdata && (signed)(*items).second.count < (*invdata).countDelta)
                    (*items).second.created = (unsigned)(*invdata).countDelta - (*items).second.count;
                continue;
            }
            if ((*items).second.processed)
                continue;
            if (get_stats(invdata, &statlist) )
            {   const std::pair<t_item_data::details, unsigned>    *cachedstat;
                t_item_data::t_stats::iterator                    newstat = statlist.begin();
    
                for (unsigned i = statlist.size(); i; --i)
                {   cachedstat = find_stat(&(*items).second.stats, &(*newstat).first); //THis call always fails, i.e find_stat returns a nullptr meaning it didn't find the requested stat in the stats list. But it is there!
                    const unsigned new_count = (cachedstat && (*newstat).second > (*cachedstat).second) ?
                                               (*cachedstat).second : 0;
    
                    if (new_count || !cachedstat)
                    {   (*items).second.created += (*newstat).second - new_count;
                        created.emplace_back((*newstat).first, 0);
                    }
                    ++newstat;
                }
                statlist.clear();
            }
            if (created.size() )
            {   (*items).second.stats = created;
                (*items).second.processed = true;
                created.clear();
            }
        }
    }
    Last edited by Exosomes; 07-03-2021 at 05:09 PM. Reason: Code format

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 05-10-2015, 03:40 PM
  2. Program running slower after optimization?
    By kkk in forum C Programming
    Replies: 2
    Last Post: 01-21-2012, 12:13 AM
  3. Program optimization
    By a.mlw.walker in forum C Programming
    Replies: 1
    Last Post: 03-27-2009, 06:12 AM
  4. Inline function
    By Bargi in forum C++ Programming
    Replies: 9
    Last Post: 07-18-2008, 08:02 AM
  5. Virtual function optimization
    By C+/- in forum C++ Programming
    Replies: 1
    Last Post: 11-15-2007, 10:04 AM

Tags for this Thread