What are the different ways we can break a singleton pattern in Java
Asked Answered
P

13

14

What are the different ways we can break a singleton pattern in Java. I know one way i.e. if we do not synchronize the method in singleton , then we can create more than an instance of the class. So synchronization is applied. Is there a way to break singleton java class.

public class Singleton {
    private static Singleton singleInstance;

    private Singleton() {
    }

    public static Singleton getSingleInstance() {
        if (singleInstance == null) {
            synchronized (Singleton.class) {
                if (singleInstance == null) {
                    singleInstance = new Singleton();
                }
            }
        }
        return singleInstance;
    }
}
Plumbum answered 6/12, 2013 at 10:44 Comment(5)
actually this code is wrong, the uninitialized Singleton may be assigned to singleInstance before the constructor finishesEmbolism
removed ee tag as there is nothing ee-specific about this questionCaine
@ratchetfreak you mean private static Singleton singleInstance= new Singleton() ?Laurettalaurette
@sᴜʀᴇsʜᴀᴛᴛᴀ no I mean that the allocated object is stored in singleInstance before the constructor runs, this means that another thread may access the uninitialized singleton which can lead to errorsEmbolism
@ratchetfreak we'd need to use volatile here, then?Schoenberg
F
14

Starting with your given code, "Double-Checked Locking" can be broken at some environment, When run on a system using the Symantec JIT, it doesn't work. In particular, the Symantec JIT compiles

singletons[i].reference = new Singleton();

to the following (note that the Symantec JIT using a handle-based object allocation system).

0206106A   mov         eax,0F97E78h
0206106F   call        01F6B210                  ; allocate space for
                                                 ; Singleton, return result in eax
02061074   mov         dword ptr [ebp],eax       ; EBP is &singletons[i].reference 
                                                ; store the unconstructed object here.
02061077   mov         ecx,dword ptr [eax]       ; dereference the handle to
                                                 ; get the raw pointer
02061079   mov         dword ptr [ecx],100h      ; Next 4 lines are
0206107F   mov         dword ptr [ecx+4],200h    ; Singleton's inlined constructor
02061086   mov         dword ptr [ecx+8],400h
0206108D   mov         dword ptr [ecx+0Ch],0F84030h

As you can see, the assignment to singletons[i].reference is performed before the constructor for Singleton is called. This is completely legal under the existing Java memory model, and also legal in C and C++ (since neither of them have a memory model).

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

Apart from that

  1. It can break if the class is Serializable
  2. It can break if its 'Clonable`
  3. You can break by Reflection (I believe)
  4. it can break ff multiple classloaders are loaded the class

*How do you solve rule breakers?

  1. It is much safer to do eager initialization
  2. To prevent deserializing to create new object you may override readResolve() method in your class and throw exception
  3. To prevent cloning, you may overrride clone() and throw CloneNotSupported exception
  4. To escape for reflective instantion, we can add check in the constructor and throw exception.

Example

public class Singleton {
 
    private static final Singleton INSTANCE = new Singleton();
 
    private Singleton() {
        // Check if we already have an instance
        if (INSTANCE != null) {
           throw new IllegalStateException("Singleton" +
             " instance already created.");
        }
    }
    public static final Singleton getInstance() {
        return INSTANCE;
    }
    private Object readResolve() throws ObjectStreamException         {
            return INSTANCE;
    }
    private Object writeReplace() throws ObjectStreamException {
            return INSTANCE;
    }
    public Object clone() throws CloneNotSupportedException {
        // return INSTANCE
        throw new CloneNotSupportedException();
    }
}

After all I would suggest to use Enum as the safest way for Singleton (Since java5 the best way to do it is to use an enum)

public static enum SingletonFactory {
    INSTANCE;
    public static SingletonFactory getInstance() {
        return INSTANCE;
    }
}
Factious answered 6/12, 2013 at 10:49 Comment(3)
you can by doing a if(singleInstance!=null)throw new RuntimeError(); in the constructorEmbolism
@ratchetfreak: You can still break it using the reflection, in case someone uses reflection before the instance is created.Kozak
Is the Symantec JIT still a thing? was it still a thing in 2013? Last I heard of it was in the 20th century.Dual
G
4

One way is Serialization. If you do not implement readResolve then reading a singleton with ObjectInputStream.readObject() will return a new instance of this singleton.

Gullet answered 6/12, 2013 at 10:50 Comment(0)
C
3

Actually a safe version without the need for synchronization is the version with a nested holder class:

public final class Singleton{

  public static final Singleton getInstance(){
    // no need for synchronization since the classloader guarantees to initialize
    // Holder.INSTANCE exactly once before handing out a reference to it
    return Holder.INSTANCE;
  }
  private Singleton();
  private static class Holder{
    private static final Singleton INSTANCE = new Singleton();
  }
}

Other safe versions are:

  • Eager initialization

    public final class Singleton{
        public static final Singleton getInstance(){
            return INSTANCE;
        }
        private Singleton();
        private static final Singleton INSTANCE = new Singleton();
    }
    
  • Enum Singleton

    public enum Singleton{
        INSTANCE;
    }
    

All of these versions have pros and cons, but none of them needs explicit synchronization since they all rely on the ClassLoader and its built-in Thread safety.

As the others have written, you can break some of these patterns through Deserialization. Read Effective Java by Joshua Bloch (Items 74 to 78) about preventing such attacks (the enum singleton pattern is safe against such attacks out of the box).

Caine answered 6/12, 2013 at 10:52 Comment(4)
or just eager initialization full stop and let class-loading semantics handle the lazynessEmbolism
@ratchetfreak yes, exactlyCaine
can we use static block instead of static class ?Plumbum
@Plumbum yes, but then we have eager initialization. But of course ratchet_freaks's comment applies here, tooCaine
V
2

There are mainly 3 concepts that can break the singleton property of a class.

1. Reflection: Reflection can be caused to destroy the singleton property of the singleton class.

2. Serialization:- Serialization can also cause breakage of singleton property of singleton classes.

3. Cloning: Cloning is a concept to create duplicate objects. Using clone we can create a copy of an object.***
Valerie answered 30/5, 2022 at 8:26 Comment(0)
E
1

AFAIK, there are two ways it could be broken

  • Using Reflection

  • When there are custom classloaders, more than one (i.e. parent class loader).all singletons should be loaded by common parent classloader.

Entertainer answered 6/12, 2013 at 10:48 Comment(3)
Could you please provide reflection code for breaking singleton ?Plumbum
@Entertainer the link is brokenOverstrung
updated it. thanks codippa.com/how-to-break-singleton-in-javaEntertainer
T
1
import java.io.Serializable;

public class Singleton implements Serializable,Cloneable{

private static final long serialVersionUID = 1L;

private static Singleton singleton=null;
private Singleton(){

}

public static Singleton getInstance(){
    if(singleton==null){
        singleton=new Singleton();
    }
    return singleton;   
}

@Override
public Object clone() throws CloneNotSupportedException{
    return super.clone();
}
}

** Singleton Test **

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/***
 * 
 * Ways to break Singleton
 */
public class Main {

private static ObjectInputStream inputStream;

public static void main(String[] args) throws Exception {
    Singleton orginalSingletonObject = Singleton.getInstance();

    /***
     * Singleton is broken by using Reflection
     */
    breakSingletonByReflection(orginalSingletonObject);

    /***
     * By Serialization/De-Serialization break Singleton We need
     * Serialization interface in a class nedds to be serialized like
     * Singleton.java
     */
    breakSingletonByserialization(orginalSingletonObject);

    /***
     * By Cloning break Singleton
     * We need to implement Cloneable interface
     */
    breakSingletonByCloning(orginalSingletonObject);


    /***
     * Break Singleton By thread
     * This scenario is related to multi-threading environment
     * 
     */

    breakSingletonByThreading(orginalSingletonObject);
}

private static void breakSingletonByThreading(Singleton orginalSingletonObject) {

    ExecutorService executorService=Executors.newFixedThreadPool(2);
    /**
     * Run this code snippet after commenting the other code for better understanding
     * Run it repeatly to create a condition when 2 threads enter the method getInstance() of Singleton class at a same time 
     * When 2 threads enter the getInstance method at same time they will get the singleton object as null (private static Singleton singleton in Singleton.java)
     * Then they will create two different objects ( have different hashcode) in this case singleton pattern will break.
     */
    executorService.submit(Main::useSingleton); // JAVA 8 syntax it will get the singleton instance
    executorService.submit(Main::useSingleton);
    executorService.shutdown();
}

public static void useSingleton(){
    Singleton singleton=Singleton.getInstance();
    printSingletonData("By Threading", singleton);

}


private static void breakSingletonByCloning(Singleton orginalSingletonObject) throws CloneNotSupportedException {
    Singleton clonedSingletonObject=(Singleton) orginalSingletonObject.clone();
    printSingletonData("By Cloning", orginalSingletonObject, clonedSingletonObject);
}

private static void breakSingletonByReflection(Singleton orginalsingleton)
        throws ClassNotFoundException, NoSuchMethodException,
        InstantiationException, IllegalAccessException,
        InvocationTargetException {

    Class<?> singletonClass = Class.forName("SingletonTest.Singleton");
    @SuppressWarnings("unchecked")
    Constructor<Singleton> constructor = (Constructor<Singleton>) singletonClass
            .getDeclaredConstructor();
    constructor.setAccessible(true);
    Singleton s = constructor.newInstance();
    printSingletonData("By Reflection", orginalsingleton, s);
}

private static void breakSingletonByserialization(Singleton orginalsingleton)
        throws FileNotFoundException, IOException, ClassNotFoundException {

    /**
     * Serialization
     */
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("E:\\Singleton.ser"));
    outputStream.writeObject(orginalsingleton);
    outputStream.close();

    /**
     * DeSerialization
     */
    inputStream = new ObjectInputStream(new FileInputStream("E:\\Singleton.ser"));

    Singleton deserializeObject = (Singleton) inputStream.readObject();
    deserializeObject.hashCode();
    printSingletonData("By Serialization", orginalsingleton, deserializeObject);


}

public static void printSingletonData(String operationName,
        Singleton orginalsingleton, Singleton reflectionSigletonObject) {

    System.out.println("------------------------------------------");
    System.out.println("New Operation");
    System.out.println(operationName);
    System.out.println("orginal Hashcode=" + orginalsingleton.hashCode());
    System.out.println("New Object hashcode="
            + reflectionSigletonObject.hashCode());
    Boolean value = orginalsingleton.hashCode() != reflectionSigletonObject.hashCode();
    System.out.println("These Object have different hascode. They are two different object Right = "
                    + value);
    System.out.println("As these are different Object this means Singleton Pattern is broken");
}


private static void printSingletonData(String operationName,Singleton singleton) {


    System.out.println("------------------------------------------");
    System.out.println("New Operation");
    System.out.println(operationName);
    System.out.println("Object hashcode="   + singleton.hashCode());

}
}
Tupler answered 5/3, 2016 at 5:54 Comment(0)
N
1

Class cls = Singleton.class;

    Constructor constructor = cls.getDeclaredConstructor();
    constructor.setAccessible(true);

    Singleton singleton = (Singleton) constructor.newInstance();
Nobody answered 3/8, 2017 at 5:31 Comment(0)
O
0

Multithreading is the biggest issue with singletons. You can avoid that by synchronizing or using eager initialisation.

Another way would be to use singleton where you're not supposed to. By using the singleton pattern you might apply it in a way that obstructs your program in later development. (E.G, creating a singleton "player" in a game, because you assume it's a singleplayer game. Next step in development "add co-op functionality").

The singleton pattern has it's advantages, but don't use it without carefull consideration.

Oblivion answered 6/12, 2013 at 10:47 Comment(0)
F
0

A note first: It would be better in this case, mainly for readability, to make the whole getSingleInstance() { } synchronized:

public synchronized static Singleton getSingleInstance() {
    if (singleInstance == null) {
        singleInstance = new Singleton();
    }
    return singleInstance;
}

Other than that, I don't think it is easy to break the code. Of course if you add recursive calls then it is possible to break it, like this:

  • Call the constructor of some other class inside this Singleton's constructor.
  • In the constructor of that class, try to obtain this Singleton instance.

But that's the only thing I can think about, and you cannot protect yourself from that in the Singleton class.

Federica answered 6/12, 2013 at 10:49 Comment(0)
C
0

The synchronized approach will work, but will also slow down every access to the singleton to protect something that only ever happens in the first access.

The simplest and safest way is just to do eager initialization, that is always safe as Java guarantees all member variables are set before it lets anyone access them.

public class Singleton {
    private static Singleton singleInstance = new Singleton();

    private Singleton() {
    }

    public static Singleton getSingleInstance() {
        return singleInstance;
    }
}

Your current approach is actually broken even with your synchronized loop - because double-check locking is broken. You need to mark the singleton variable as volatile if you are going to use it for double-check locking since otherwise there are still ways for threads to access an incompletely-initialized object. See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java for more details.

Casandra answered 6/12, 2013 at 11:0 Comment(0)
U
0

Suppose you have implemented Singleton class as "SingletonPattern" as below. package com.example.pattern;

public class SingletonPattern
{
  private static SingletonPattern pattern;

  public static SingletonPattern getInstance()
  {
    if (pattern == null)
    {
      synchronized (SingletonPattern.class)
      {
        if (pattern == null)
        {
          pattern = new SingletonPattern();
        }
      }
    }
    return pattern;
  }
}

Now you can break you the Singleton behavior of this class by using following approach.

Class c = Class.forName("com.example.pattern.SingletonPattern");
System.out.println((SingltonPattern) c.newInstance());
Usn answered 8/9, 2015 at 14:4 Comment(0)
T
0

You can go through this link, there are different ways to break and prevent the singleton class:

Ways to break/prevent singleton class

Tousle answered 27/2, 2020 at 7:26 Comment(0)
M
0

There are few ways to break the singleton design pattern as mentioned below:

  1. Break By Reflection
  2. Serialization & Deserialization
  3. With help of Cloning
  4. Break in Multi-threaded Environment
  5. Break due to Multiple Class-loader
  6. Break due to Garbage Collection

You can go through this article, it has discussed this topic in detail, compiled all the possible ways in which a singleton class can break and provided the fix. This article also explains other Robust ways to create singleton.

Mothball answered 30/1 at 3:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.