Skip to content

Conversation

@pepone
Copy link
Member

@pepone pepone commented Nov 3, 2025

Fix #4547

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR addresses a potential null pointer dereference in the updateRevision method by adding a null check for _desc before accessing it. The change recognizes that _desc can be nullptr if the server's initial load has not completed yet.

Key changes:

  • Added null check guard for _desc before updating uuid and revision
  • Introduced local variable desc to avoid repeated member access
  • Applied the same pattern to the _load path for consistency

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

{
os << "#" << endl;
os << "# This server belongs to the application '" << _desc->application << "'" << endl;
os << "# This server belongs to the application '" << desc->application << "'" << endl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite following. Can't desc be null here still?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just inside updateRevision writing the revision file, if it was null before, it will still be null. This method doesn't update _desc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it _load is false, then desc will be nullptr. This deference will crash.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_desc is set if already loaded.
_load is set if loading.

We don't call this method if neither is set, I will add an assert.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see:

    auto d = _load ? _load->getInternalServerDescriptor() : _desc;
    if (d && (replicaName != "Master" || d->sessionId == desc->sessionId) && !descriptorUpdated(d, desc))
    {
        if (d->revision != desc->revision)
        {
            updateRevision(desc->uuid, desc->revision);
        }

The if (d && ensures either _load or _desc is set.

Next call is:

_load->addCallback(response, exception); // Must be called before startRuntimePropertiesUpdate!
updateRevision(desc->uuid, desc->revision);

Here _load is set.

The third call hasppens inside updateImpl and both are set in this case:

void
ServerI::updateImpl(const shared_ptr<InternalServerDescriptor>& descriptor)
{
    assert(_load && descriptor);

    _desc = descriptor;
    _waitForReplication = true;

    // Remember if the server was just released by a session, this will be used later to not update the configuration
    // on the disk (as an optimization and to allow users to review the configuration file after allocating a server --
    // that's useful if the server configuration is bogus and the session server can't start).
    bool serverSessionReleased = _desc && _desc->activation == "session" && _desc->revision == descriptor->revision &&
                                 !_desc->sessionId.empty() && descriptor->sessionId.empty();

assert(_desc || _load);

// _desc can be nullptr if the server initial load didn't complete yet.
shared_ptr<InternalServerDescriptor> desc = _desc;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this helper desc (a shared_ptr) pretty confusing. You're still updating _desc when it's not null.
And when _load is set, you are updating load's internal server descriptor (not the greatest API).

What about avoiding this desc helper and writing instead something like:

string application;

if (_desc)
{
    _desc->uuid = uuid;
    _desc->revision = revision;
    application = _desc->application;
}

if (_load)
{
    _load->getInternalServerDescriptor()->uuid = uuid;
    _load->getInternalServerDescriptor()->revision = revision;
  
    // When both _desc and _load are not null, this one prevails.
    application = _load->getInternalServerDescriptor()->application;
}

and then use application, uuid and revision in the code below?

@pepone pepone merged commit 6ca1222 into zeroc-ice:main Nov 12, 2025
30 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IceGrid/update test failure (Windows)

3 participants