[NETVIRT-39] Synchronization block on Mac String that is created in local scope Created: 04/Jul/16  Updated: 19/Oct/17  Resolved: 03/Apr/17

Status: Resolved
Project: netvirt
Component/s: General
Affects Version/s: Boron
Fix Version/s: None

Type: Bug
Reporter: Guy Sela Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Operating System: All
Platform: All


External issue ID: 6147

 Description   

In ElanPacketInHandler.onPacketReceived():
byte[] srcMac = res.getSourceMACAddress();
// You create a new String here
String macAddress = NWUtil.toStringMacAddress(srcMac);

// You call setupMacFlows with the new created String
ElanUtils.setupMacFlows(…., macAddress)

In ElanUtils.setupMacFlows():
synchronized (macAddress) {
...
}

The macAddress String that the synchronized block is using as a mutex was created locally. If the same mac value will be used in a different place or by a different thread, it will have its own reference, thus not locking anything.

A naive solution will be to use String.intern() but this is a very bad practice, as illustrated here: http://stackoverflow.com/questions/461896/what-is-the-most-frequent-concurrency-issue-youve-encountered-in-java/463437#463437.

My suggested solution is to hold a map between macAddress to Object() and synchronized on the Object.
Map will be created like this:
CacheBuilder.newBuilder().weakValues()
To obtain the lock, you will use:
Object lock = Cache.asMap().putIfAbsent(mac, new Object());

Because we are using weakValues(), there is no need to remove the entries from the map, as they will be garbage collected if there is no live reference to them.



 Comments   
Comment by Alon Kochba [ 30/Aug/16 ]

I think this can wait for Carbon unless Guy has objections as the problem is theoretical and exact implications are unknown

Comment by Guy Sela [ 30/Aug/16 ]

First of all the problem isn't theoretical. Maybe you meant to say that it has low probability to happen because it's a timing issue, and not deterministic (as all concurrency problems are by nature).
I think that in order to decide what to do with this bug's priority, you need to answer the following questions:
1) Why are there synchronized blocks there in the first place? What are the risks of removing them? Right now the code acts like there are no synchronized block (putting memory barriers aside), because the mutex is local, but still "everything works".
2) If there is a real reason behind the synchronized blocks, we can consider to do FOR NOW the dirty bad practice solution, and just replace every:
synchronized (macAddress) {
...
}

With:
synchronized (macAddress.intern()) {
...
}

Comment by Sam Hague [ 03/Apr/17 ]

https://git.opendaylight.org/gerrit/#/c/50370/

Generated at Wed Feb 07 20:20:32 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.