Login Page - Create Account

Support Board


Date/Time: Wed, 15 May 2024 21:16:50 +0000



[Programming Help] - ACSIL Using Pointers on Subgraph arrays raises CPU exception

View Count: 123

[2024-03-29 04:10:10]
User43 - Posts: 88
This is not a programming question, it is a report of an error in SC.
Knowing the problem now, I can work around it in my project, but hopefully you will be able to fix it.

Following sample code raises a CPU exception on the message log when entering the "Add Custom Study" dialog.
See the comments in the code block.

Interestingly the issue occurs only on the Subgraph array. The Input array is not showing this problem although both use the same c_ArrayWrapper.

Using a pointer via
&sc.Subgraph.ElementAt(0)
is ok.

Problem: When using a pointer via
&sc.Subgraph.GetAt(0)
or
sc.Subgraph.GetPointer()
and accessing the element will cause a CPU exception.

2024-03-28 23:18:42.151 | Loading DLL: C:\SierraChart\Data\scPointerProblem.dll (scPointerProblem_64.dll). Handle: 7ff958470000
2024-03-28 23:18:42.151 | Warning: The Custom DLL study "scPointerProblem.scsf_SC_Subgraph_Pointer_Issue" has just caused a CPU exception.
2024-03-28 23:18:42.151 | Warning: This Custom DLL study may cause Sierra Chart to be unstable until you remove the study from the chart and restart Sierra Chart.


// The top of every source code file must include this line
#include "sierrachart.h"

// For reference, refer to this page:
// Advanced Custom Study Interface and Language (ACSIL)

// This line is required. Change the text within the quote
// marks to what you want to name your group of custom studies.
SCDLLName("SC Subgraph Pointer Issue")


SCSFExport scsf_SC_Subgraph_Pointer_Issue(SCStudyInterfaceRef sc)
{
// Set configuration variables
if (sc.SetDefaults)
{
// Set the configuration and defaults
sc.GraphName = "Subgraph Pointer issue test";
sc.StudyDescription = "Setting subgraphs using pointers does not work.";
    
// Set the region to draw the graph in. Region zero is the main
// price graph region.
sc.AutoLoop = 0; // Manual Looping
sc.GraphRegion = 0;
sc.ValueFormat = 0;
sc.UpdateAlways = 0;


SCSubgraphRef subg = sc.Subgraph[0];
subg.Name = "Chart Scale";
subg.LineWidth = 3;
subg.DrawStyle = DRAWSTYLE_LINE;
subg.PrimaryColor = RGB(0, 128, 255); //Blue
subg.SecondaryColor = RGB(0, 0, 0); //black
subg.SecondaryColorUsed = true;
subg.DisplayNameValueInWindowsFlags = 1;

// ---->> THIS IS RAISING AN EXCEPTION WHEN USING GetAt
// WHEN USING ElementAt is used no exception is raised
// s_SCSubgraph_260* subgP = &sc.Subgraph.ElementAt(0);
s_SCSubgraph_260* subgP = &sc.Subgraph.GetAt(0);
subgP++;
subgP->Name = "Set via pointer from sc.Subgraph.GetPointer()";
subgP->LineWidth = 3;
subgP->DrawStyle = DRAWSTYLE_LINE;
subgP->PrimaryColor = RGB(128, 128, 255);
subgP->SecondaryColor = RGB(0, 0, 0); //black
subgP->SecondaryColorUsed = false;
subgP->DisplayNameValueInWindowsFlags = 1;


SCInputRef inp = sc.Input[0];
inp.Name = "Input via sc.Inpput[0]";
inp.SetInt(55);

// ---->> THIS IS NOT RAISING AN EXCEPTION
// s_SCInput_145* inpP = &sc.Input.ElementAt(0);
s_SCInput_145* inpP = &sc.Input.GetAt(0);
inpP++;
inpP->Name = "Input via pointer from GetAt()";
inpP->SetInt(99);

// Must return before doing any data processing if sc.SetDefaults is set
return;
}  
}

I'm on SC 2625.
[2024-03-29 04:41:00]
Sierra_Chart Engineering - Posts: 14359
This does not make any sense.

It is your own code which is causing the exception. It is specifically what you are doing is where the problem is. There is inherently no valid concept, where the problem could be on the Sierra Chart side.

Taking the addresses like you are is never considered safe and you can see it is leading to a problem.

It would take significant amount of time for us to understand what is happening and explain the issue and this is definitely not within the scope of our support.
Sierra Chart Support - Engineering Level

Your definitive source for support. Other responses are from users. Try to keep your questions brief and to the point. Be aware of support policy:
https://www.sierrachart.com/index.php?l=PostingInformation.php#GeneralInformation

For the most reliable, advanced, and zero cost futures order routing, use the Teton service:
Sierra Chart Teton Futures Order Routing
Date Time Of Last Edit: 2024-03-29 04:41:37
[2024-03-29 05:06:57]
User43 - Posts: 88
What is then the purpose of the GetAt or GetPointer functions?

When I get a pointer to a Subgraph I should be able to dereference it and set or read its values.

That is common practice in C/C++.
Using pointer arithmetic and iterators would quite simplify the coding on my project to manage inputs and subgraphs.

Why does it work with the InputArray and not with the SubgraphArray? Both are based on the same wrapper class !
Both array types as well as the wrapper class are SC provided entities. So it is not a problem with my code, rather the one provided by SC.

I don't ask for support, I just point out a flaw in your software, hoping that eventually an explanation or ideally a fix is provided.

Aren't you even a bit curious what is wrong with it?
My provided simple test study is not hard to understand and can be quickly compiled and installed.
[2024-03-29 12:42:46]
User43 - Posts: 88
By the way within your C wrapper class you use pointers too.

Just to be clear I know that
sc.Subgraph.ElementAt(0)
is the same as
sc.Subgraph[0]

From your c_ArrayWrapper (see below) I know that m_Data is a pointer to the associated first element with in the array.
The ElementAt(index) member function does some additional checks on the status of the array and provided index, which
obviously make the difference.

Why are these checks needed on a s_SCSubgraph_260 element structure but not on a s_SCInput_145 element structure?

template <typename T>
class c_ArrayWrapper
{
  private:
    T* m_Data; //<<<----- POINTER TO ARRAY ELEMENT
    int m_NumElements;

    fp_SCDLLOnArrayUsed m_fp_OnArrayUsed;
    int m_OnArrayUsedParam;

    int m_NumExtendedElements;
    int m_TotalNumElements;

    T m_DefaultElement;

  public:
    c_ArrayWrapper()
    {
      ResetMembers();
    }

...
    T& operator [] (int Index) //<<<---- OPERATOR OVERLOADING from [index] to ElementAt(index)
    {
      return ElementAt(Index);
    }

    const T& operator [] (int Index) const
    {
      return ElementAt(Index);
    }

    T& ElementAt(int Index) //<<<--- ElementAt IS VERY SIMILAR TO GetAt BUT CHECKS IN ADDITION THE STATUS OF THE index AND m_Data
    {
      if (m_Data == NULL)
      {
        if (m_fp_OnArrayUsed != NULL)
        {
          // This will allocate and set up the array if it can
          m_fp_OnArrayUsed(m_OnArrayUsedParam);
        }

        if (m_Data == NULL)
          return m_DefaultElement;
      }

      if (m_TotalNumElements == 0)
        return m_DefaultElement;

      if (Index < 0)
        Index = 0;

      if (Index >= m_TotalNumElements)
        Index = m_TotalNumElements - 1;

      return m_Data[Index]; //<<<--- THIS IS JUST A DIFFERENT WRITING OF *(m_data + Index) RETURNING A REFERENCE TO INDEX ELEMENT
}

    T& GetAt(int Index)
    {
      return m_Data[Index]; //<<<--- THIS IS JUST A DIFFERENT WRITING OF *(m_data + Index) RETURNING A REFERENCE TO INDEX ELEMENT
    }

    }


    // This should only be used when absolutely necessary and you know what
    // you are doing with it.
    T* GetPointer()
    {
      //Returns non-constant data pointer which can be used for rapidly setting blocks of data
      return m_Data;
    }


To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account