-
Notifications
You must be signed in to change notification settings - Fork 602
Fix segfault accessing null pointer in IceGrid node updateRevision #4623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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
_descbefore updating uuid and revision - Introduced local variable
descto avoid repeated member access - Applied the same pattern to the
_loadpath for consistency
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| string idFilePath = _serverDir + "/revision"; | ||
| ofstream os(IceInternal::streamFilename(idFilePath).c_str()); // idFilePath is a UTF-8 string | ||
| if (os.good()) | ||
| { | ||
| os << "#" << endl; | ||
| os << "# This server belongs to the application '" << _desc->application << "'" << endl; | ||
| os << "# This server belongs to the application '" << desc->application << "'" << endl; | ||
| os << "#" << endl; | ||
| os << "uuid: " << _desc->uuid << endl; | ||
| os << "revision: " << _desc->revision << endl; | ||
| os << "uuid: " << desc->uuid << endl; | ||
| os << "revision: " << desc->revision << endl; | ||
| } |
Copilot
AI
Nov 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential null pointer dereference. The variable desc could be nullptr if both _desc is nullptr and _load is also nullptr (or if the initial _desc is nullptr and we skip the if (_load) block). Before accessing desc->application, desc->uuid, and desc->revision at lines 2464-2467, a null check should be added to prevent undefined behavior.
| { | ||
| os << "#" << endl; | ||
| os << "# This server belongs to the application '" << _desc->application << "'" << endl; | ||
| os << "# This server belongs to the application '" << desc->application << "'" << endl; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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();
Fix #4547