Hi Openfire Devs!
I have a bug report which is causing some issues with MUC usage in our installation. We’re seeing NullPointerExceptions like the following:
- 2017.08.03 15:02:57 org.jivesoftware.openfire.muc.spi.MultiUserChatServiceImpl - Internal server error
- java.lang.NullPointerException
- at org.jivesoftware.openfire.group.ConcurrentGroupMap.includesKey(ConcurrentGroupMap.java:49)
- at org.jivesoftware.openfire.muc.spi.LocalMUCRoom.joinRoom(LocalMUCRoom.java:642)
- at org.jivesoftware.openfire.muc.spi.LocalMUCUser.process(LocalMUCUser.java:471)
- at org.jivesoftware.openfire.muc.spi.LocalMUCUser.process(LocalMUCUser.java:177)
- at org.jivesoftware.openfire.muc.spi.MultiUserChatServiceImpl.processPacket(MultiUserChatServiceImpl.java:366)
- at org.jivesoftware.openfire.component.InternalComponentManager$RoutableComponents.process(InternalComponentManager.java:606)
This is caused because (as best as I can figure) ConcurrentGroupMap.includesKey calls iterator.next().isUser(target); but iterator.next() can return NULL, and that isn’t checked for: iterator is created from getGroupsFromKeys() which calls Group.resolveFrom that can return null:
/**
- Attempt to resolve the given object into a Group.
- @param proxy Presumably a Group, a Group name, or a JID that represents a Group
-
@return The corresponding group, or null if the proxy cannot be resolved as a group
*/
public static Group resolveFrom(Object proxy) {
Group result = null;
try {
GroupManager groupManger = GroupManager.getInstance();
if (proxy instanceof JID) {
result = groupManger.getGroup((JID)proxy);
} else if (proxy instanceof String) {
result = groupManger.getGroup((String)proxy);
} else if (proxy instanceof Group) {
result = (Group) proxy;
}
} catch (GroupNotFoundException gnfe) {
// ignore
}
return result;
}
/**
- Returns the groups that are implied (resolvable) from the keys in the map.
-
@return A Set containing the groups among the keys
*/
@Override
public synchronized Set getGroupsFromKeys() {
Set result = new HashSet<>();
for(String groupName : getKnownGroupNamesFromKeys()) {
result.add(Group.resolveFrom(groupName));
}
return result;
}
The fix is a simple check for NULL before using the result of iterator.next at line 48 of ConcurrentGroupMap.java:
while (!found && iterator.hasNext()) {
found = iterator.next().isUser(target); // check for NULL first here
}