Correct a concurrency bug discovered by mibby. FIXES #39.
It's another lazy initialization problem. I only check a single field before initializing two related fields, which can cause problems when two threads execute handleLogin() concurrently. If thread A detects that PACKET_LOGIN_CLIENT is null, it updates both it and LOGIN_GAME_PROFILE. However, thread B may only see the PACKET_LOGIN_CLIENT update, and still believe LOGIN_GAME_PROFILE is NULL. Hence why it causes a NullPointerException in issue #39.
Dieser Commit ist enthalten in:
Ursprung
ea7b550bda
Commit
9ef9475b61
@ -320,15 +320,22 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
|||||||
* @param packet - the packet.
|
* @param packet - the packet.
|
||||||
*/
|
*/
|
||||||
protected void handleLogin(Class<?> packetClass, Object packet) {
|
protected void handleLogin(Class<?> packetClass, Object packet) {
|
||||||
// Initialize packet class
|
Class<?> loginClass = PACKET_LOGIN_CLIENT;
|
||||||
if (PACKET_LOGIN_CLIENT == null) {
|
FieldAccessor loginClient = LOGIN_GAME_PROFILE;
|
||||||
PACKET_LOGIN_CLIENT = PacketType.Login.Client.START.getPacketClass();
|
|
||||||
LOGIN_GAME_PROFILE = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, GameProfile.class, true);
|
// Initialize packet class and login
|
||||||
|
if (loginClass == null) {
|
||||||
|
loginClass = PacketType.Login.Client.START.getPacketClass();
|
||||||
|
PACKET_LOGIN_CLIENT = loginClass;
|
||||||
|
}
|
||||||
|
if (loginClient == null) {
|
||||||
|
loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, GameProfile.class, true);
|
||||||
|
LOGIN_GAME_PROFILE = loginClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we are dealing with the login packet
|
// See if we are dealing with the login packet
|
||||||
if (PACKET_LOGIN_CLIENT.equals(packetClass)) {
|
if (loginClass.equals(packetClass)) {
|
||||||
GameProfile profile = (GameProfile) LOGIN_GAME_PROFILE.get(packet);
|
GameProfile profile = (GameProfile) loginClient.get(packet);
|
||||||
|
|
||||||
// Save the channel injector
|
// Save the channel injector
|
||||||
factory.cacheInjector(profile.getName(), this);
|
factory.cacheInjector(profile.getName(), this);
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren