Skip to content

VNX-414: Missing Lock Check

Reports a non-blocking lock attempt whose result is discarded, so the shared resource is touched whether or not the lock is held: pthread_mutex_trylock, sem_trywait, flock with LOCK_NB, lockf F_TLOCK, fcntl F_SETLK, C++ try_lock and unchecked std::try_to_lock, Go TryLock, Java tryLock, Python acquire(False). Checked results, explicit discards, blocking locks and test code are not reported.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-414
Severity Low
SARIF level note
Kind sast
Languages C, C++, Go, Java, Python
CWE CWE-414
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 missing-lock-check concurrency race-condition cwe-414
Source internal/sast/rules/vnx-414.rego

Overview

VNX-414 maps to CWE-414: Missing Lock Check. A lock call that can fail without blocking tells the caller whether it got the lock. When that answer is thrown away, the code that follows runs whether or not the lock is held, and two threads or processes update the same state at once.

The rule reports the attempt when it is a whole statement, its result not assigned, returned, tested or passed on:

Language Calls
C, C++ pthread_mutex_trylock, pthread_rwlock_tryrdlock/trywrlock, pthread_spin_trylock, mtx_trylock, sem_trywait, pthread_mutex_timedlock, sem_timedwait, flock(fd, LOCK_EX/LOCK_SH | LOCK_NB), lockf(fd, F_TLOCK, ...), fcntl(fd, F_SETLK, ...)
C++ m.try_lock(), try_lock_for, try_lock_until, std::try_lock(a, b); a std::unique_lock built with std::try_to_lock whose owns_lock() (or the lock itself) is not tested in the next 10 lines
Go mu.TryLock(), rw.TryRLock()
Java lock.tryLock(...), channel.tryLock(...)
Python lock.acquire(False), acquire(blocking=False), acquire(block=False) (multiprocessing), acquire with a finite timeout (a negative or None timeout waits forever and is not reported)

What Gets Flagged

pthread_mutex_trylock(&stats_lock);   // FLAGGED: may not hold the lock
s->hits++;
c.mu.TryLock()                        // FLAGGED
c.data[k] = v
self.lock.acquire(blocking=False)     # FLAGGED
self.active += 1

What Is Not Flagged

  • Results that are tested, assigned or returned: if (pthread_mutex_trylock(&m) != 0) return;, if !mu.TryLock() {, got = lock.acquire(False).
  • An explicit discard: (void)pthread_mutex_trylock(&m) in C, _ = mu.TryLock() in Go.
  • Blocking locks (pthread_mutex_lock, flock without LOCK_NB, fcntl(F_SETLKW), Lock()), unlocks (LOCK_UN), test files, comments and string literals.

Remediation

Proceed only when the attempt succeeded:

if (pthread_mutex_trylock(&stats_lock) != 0)
    return;     /* busy: try again later */
s->hits++;
pthread_mutex_unlock(&stats_lock);

References

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-414
// nosec vnx-414

Or record an ignore rule: vulnetix ignore add --rule vnx-414 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-414.rego, cli/internal/sast/docs/vnx-414.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.