VNX-667: Improper locking: shared String/boxed monitor or Lock released outside finally
Reports Java synchronized blocks on interned Strings or boxed values, and Lock.lock() calls with no finally block that unlocks the same lock.
| Field | Value |
|---|---|
| Rule ID | VNX-667 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | Java |
| CWE | CWE-667 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | improper-locking cwe-667 java concurrency |
| Source | internal/sast/rules/vnx-667.rego |
Overview
VNX-667 maps to CWE-667: Improper Locking. It reports two Java locking mistakes that compile, look correct and still fail:
- A shared monitor.
synchronizedon a String literal, an.intern()ed string,Boolean.TRUE/FALSE, avalueOf(...)box, or a field, variable or method parameter the file declares asString,Boolean,Integer,Long,Short,ByteorCharacter. Interned strings and cached boxes are the same object everywhere in the JVM, so unrelated code (another library, another tenant) contends on, or deadlocks with, your lock. A boxed field reassigned inside the block (generation++) changes the monitor while it is held. - A lock with no finally. A statement
lock.lock()orlockInterruptibly()(alsorw.readLock().lock()) with nofinallyin the next 60 lines that calls the same receiver’sunlock(). An exception in the critical section leaves the lock held forever.
What Gets Flagged
private static final String LOCK = "LOCK";
synchronized (LOCK) { n++; } // FLAGGED: interned literal
synchronized (tenant.intern()) { ... } // FLAGGED
synchronized (Boolean.TRUE) { ... } // FLAGGED
lock.lock(); // FLAGGED: unlock() is skipped if this throws
if (amount > balance) throw new IllegalStateException();
balance -= amount;
lock.unlock();
What Is Not Flagged
synchronized (this),synchronized (Foo.class), or a privateObjectfield.lock.lock(); try { ... } finally { lock.unlock(); }, andtry { lock.lock(); ... } finally { lock.unlock(); }.tryLock(),FileChannel.lock()assignments, methods that are themselves namedlock/acquire(wrappers).- Test files (for the Lock shape), comments and string literals.
Remediation
private final Object lock = new Object();
synchronized (lock) { ... }
lock.lock();
try {
...
} finally {
lock.unlock();
}
References
- CWE-667: Improper Locking
- SEI CERT LCK01-J: Do not synchronize on objects that may be reused
- SEI CERT LCK08-J: Ensure actively held locks are released on exceptional conditions
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-667
// nosec vnx-667
Or record an ignore rule: vulnetix ignore add --rule vnx-667 --reason "...". See Suppressing findings.