Crash in cloned gradient Shader



  • On 10/10/2017 at 04:55, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:    
    Platform:      Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    Hi!

    One of our shaders is used as a "reference shader" where you can link a shader from anywhere else
    in the document (in this case, the shader sits on a BaseObject) and reproduce it. On InitRender(), this
    referenced shader is cloned and inserted into a temporary branch to ensure that the shader is available
    to the document.

    In case it matters, this "reference shader" sits on the very same object, too.

    Unfortunately, a crash appears quite frequently when we copy the BaseObject that hosts both shaders.
    This crash is only reproducible when the source shader is a Gradient Shader. It appears to happen only
    when the object is copied multiple times at once or in a short period of time. Also, I wasn't able to
    reproduce this issue on Windows.

    Is there anything special about the Gradient shader that could prevent it from being sampled this way?

    > INITRENDERRESULT ReferenceShader::InitRender(
    >
    > BaseShader* shader, const InitRenderStruct& irs)
    >
    > {
    >
    > BaseContainer* bc = (shader ? shader->GetDataInstance() : nullptr);
    >
    > if (!shader || !bc) return INITRENDERRESULT_UNKNOWNERROR;
    >
    > if (!m_head) return INITRENDERRESULT_OUTOFMEMORY;
    >
    >
    >
    >
    > // We pass nullptr for the document because we do actually want to allow
    >
    > // retrieving a shader from another document (for the shader preview).
    >
    > m_subShader = (BaseShader*) bc->GetLink(FIXTURESHADER_SUBSHADER, nullptr, Xbase);
    >
    > if (m_subShader) {
    >
    > // Check if the shader is in the hierarchy.
    >
    > Bool needsClone = true;
    >
    > for (BaseShader* curr = shader->GetDown(); curr; curr = curr->GetNext()) {
    >
    > if (curr == m_subShader) {
    >
    > needsClone = false;
    >
    > break;
    >
    > }
    >
    > }
    >
    >
    >
    >
    > m_subShaderCloned = needsClone;
    >
    > if (needsClone) {
    >
    > m_subShader = (BaseShader*) m_subShader->GetClone(COPYFLAGS_0, nullptr);
    >
    > if (!m_subShader) return INITRENDERRESULT_OUTOFMEMORY;
    >
    > m_head->InsertLast(m_subShader); // Needs to be removed and deallocated in FreeRender()
    >
    > }
    >
    >
    >
    >
    > auto res = m_subShader->InitRender(irs);
    >
    > if (res != INITRENDERRESULT_OK) {
    >
    > if (m_subShaderCloned) BaseShader::Free(m_subShader);
    >
    > m_subShader = nullptr;
    >
    > return res;
    >
    > }
    >
    > }
    >
    >
    >
    >
    > // ...
    >
    > return INITRENDERRESULT_OK;
    >
    > }
    >
    >
    >
    >
    >
    > void ReferenceShader::FreeRender(BaseShader* shader)
    >
    > {
    >
    > if (m_subShader) {
    >
    > m_subShader->FreeRender();
    >
    > if (m_subShaderCloned) {
    >
    > m_subShader->Remove();
    >
    > BaseShader::Free(m_subShader);
    >
    > }
    >
    > m_subShader = nullptr;
    >
    > }
    >
    >
    >
    >
    > // ...
    >
    > }
    >
    >
    >
    >
    >
    > Vector ReferenceShader::Output(BaseShader* shader, ChannelData* cd) {
    >
    > // ...
    >
    >
    >
    >
    > Float u, v = ...;
    >
    >
    >
    >
    > if (m_subShader) {
    >
    > ChannelData data = *cd;
    >
    > data.p = Vector(u, v, 0);
    >
    > return m_subShader->Sample(&data) * m_sampling.brightness; // << CRASH when m_subShader is a Gradient Shader
    >
    > }
    >
    >
    >
    >
    > // ...
    >
    > return Vector();
    >
    > }
    >
    > Int32 ReferenceShader::GetBranchInfo(
    >
    > GeListNode* node, BranchInfo* branches,
    >
    > Int32 max, GETBRANCHINFO flags)
    >
    > {
    >
    > Int32 count = 0;
    >
    > if (count < max) {
    >
    > branches[count].head = m_head;
    >
    > branches[count].name = nullptr;
    >
    > branches[count].id = Xbase;
    >
    > branches[count].flags = BRANCHINFOFLAGS_HIDEINTIMELINE;
    >
    > count++;
    >
    > }
    >
    > return count;
    >
    > }

    Tips or hints are also appreciated, of course. :)

    Thanks,
    -Niklas



  • On 11/10/2017 at 01:26, xxxxxxxx wrote:

    Hi Niklas,

    we are not aware of any peculiarities of the gradient shader.
    Can you provide us with a crash report (e.g. via email)? Another option could be to provide us with your plugin, so we could dig into the crash.



  • On 18/10/2017 at 06:06, xxxxxxxx wrote:

    Thanks to the SDK support team, they figured out that ChannelData::texflag was set so that
    GET_TEX_CHANNEL() would return CHANNEL_BUMP, which in turn requires ChannelData::vd
    to be not-nullptr. The issue on my side was a bit further up the call stack, where I created a
    new ChannelData on the stack without initializing the texflag member (the ChannelData
    constructor only sets vd = nullptr, leaving texflag at a random value).

    > /* Returns an empty ChannelData object. The default constructor only explicitly initializes
    >
    > * the #ChannelData::vd member, leaving #ChannelData::texflag and others at a random value.
    >
    > * This random value for texflag can be especially problematic when it results in
    >
    > * #GET_TEX_CHANNEL() to return #CHANNEL_BUMP, which requires #ChannelData::vd to be set,
    >
    > * leading to crashes in for example the C4D gradient shader.
    >
    > */
    >
    > inline ChannelData GetEmptyChannelData() {
    >
    > ChannelData r;
    >
    > r.t = 0.0;
    >
    > r.texflag = 0;
    >
    > r.off = 0.0;
    >
    > r.scale = 0.0;
    >
    > return r;
    >
    > }

    Cheers,


Log in to reply