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

Not synchronized com.mysema.query.types.TemplateFactory cache #341

Closed
IonPrimer opened this Issue Feb 11, 2013 · 2 comments

Comments

Projects
None yet
2 participants
@IonPrimer

In class

com.mysema.query.types.TemplateFactory

we have static factory: TemplateFactory DEFAULT with cache in Map:

private final Map<String,Template> cache = new HashMap<String,Template>();

By calling:

TemplateFactory.DEFAULT.create(name);

we can create infinite loop in HashMap, because HashMap cache is not synchronized. Instead default HashMap we should use ConcurrentHashMap.

We can try to reproduce this error by running app:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.mysema.query.types.TemplateFactory;

public class TermplateInfiniteLoop {

static String templates[] = createTemplates();

public static void main( String[] args ) {
    ExecutorService executorService = Executors.newFixedThreadPool( 3 );
    executorService.execute( new Runner() );
    executorService.execute( new Runner() );
    executorService.execute( new Runner() );
    executorService.shutdown();
}

private static class Runner implements Runnable{
    public void run() {
        for( int i = 0; i < 100000; i++ ){
            TemplateFactory.DEFAULT.create(templates[i%templates.length]);
        }
    }
}

/**
 * Generates array of strings: "\0a", "\0\0a", "\0\0\0a" etc. all with the same hashCode
 * @return
 */
private static String[] createTemplates() {
    String tab[] = new String[10000];
    StringBuilder builder = new StringBuilder();
    for( int i = 0; i < tab.length; i++ ){
        builder.append( '\0' );
        tab[i] = builder.toString() + 'a';
    }
    return tab;
}
}

Important is that all strings have the same hashCode, so they will be stored in the same HashMap bucket. Infinite loop stack trace:

at java.util.HashMap.getEntry(HashMap.java:448) at java.util.HashMap.containsKey(HashMap.java:434) at com.mysema.query.types.TemplateFactory.create(TemplateFactory.java:52) at TermplateInfiniteLoop$Runner.run(TermplateInfiniteLoop.java:23) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:722)

Tested on several versions of querydsl-code, and java versions 1.6.x

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Feb 12, 2013

Member

Thanks for the bug report. Fixed as suggested.

Member

timowest commented Feb 12, 2013

Thanks for the bug report. Fixed as suggested.

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Feb 20, 2013

Member

Released in 3.0.0.BETA2

Member

timowest commented Feb 20, 2013

Released in 3.0.0.BETA2

@timowest timowest closed this Feb 20, 2013

@timowest timowest added this to the 3.0.0 milestone Apr 14, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment