Introduction to Klocwork
Klocwork is a static code analysis tool that identifies security vulnerabilities, quality issues, and compliance violations in Java code. It provides deep code analysis with inter-procedural dataflow analysis and supports industry standards like CWE, OWASP, and CERT.
Klocwork Integration Setup
Maven Configuration
<properties>
<klocwork.version>2023.3</klocwork.version>
<klocwork.maven.plugin.version>1.5</klocwork.maven.plugin.version>
</properties>
<build>
<plugins>
<!-- Klocwork Maven Plugin -->
<plugin>
<groupId>com.klocwork</groupId>
<artifactId>klocwork-maven-plugin</artifactId>
<version>${klocwork.maven.plugin.version}</version>
<configuration>
<serverUrl>http://klocwork-server:8080</serverUrl>
<licenseHost>klocwork-license</licenseHost>
<project>MY_JAVA_PROJECT</project>
<additionalParams>
-j ${java.home} -J-Duser.language=en
</additionalParams>
<buildTimeout>3600</buildTimeout>
<strict>true</strict>
<skip>false</skip>
</configuration>
<executions>
<execution>
<id>klocwork-build</id>
<phase>compile</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
<execution>
<id>klocwork-analyze</id>
<phase>verify</phase>
<goals>
<goal>analyze</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>klocwork</id>
<build>
<plugins>
<plugin>
<groupId>com.klocwork</groupId>
<artifactId>klocwork-maven-plugin</artifactId>
<executions>
<execution>
<id>klocwork-ci</id>
<phase>verify</phase>
<goals>
<goal>ci</goal>
</goals>
<configuration>
<reportFile>${project.build.directory}/klocwork-report.xml</reportFile>
<breakOnSeverity>Review</breakOnSeverity>
<breakOnNewIssues>true</breakOnNewIssues>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Gradle Configuration
plugins {
id 'java'
id 'com.klocwork.gradle' version '1.5'
}
klocwork {
serverUrl = 'http://klocwork-server:8080'
licenseHost = 'klocwork-license'
project = 'MY_JAVA_PROJECT'
additionalParams = ['-j', "${System.getProperty('java.home')}", '-J-Duser.language=en']
buildTimeout = 3600
strict = true
skip = false
}
tasks.register('klocworkCi', com.klocwork.gradle.tasks.KlocworkCiTask) {
reportFile = file("${buildDir}/klocwork-report.xml")
breakOnSeverity = 'Review'
breakOnNewIssues = true
}
Security Vulnerability Prevention
Input Validation and Sanitization
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.constraints.Pattern;
/**
* Security-focused input validation to prevent common vulnerabilities.
*/
public class SecurityUtils {
private static final Logger logger = LoggerFactory.getLogger(SecurityUtils.class);
/**
* Validates and sanitizes user input to prevent SQL injection.
* Klocwork check: JAVA.SQL_INJECTION
*/
@NotNull
public static String sanitizeSqlInput(@NotNull String input) {
Objects.requireNonNull(input, "Input cannot be null");
// Remove potentially dangerous SQL characters
String sanitized = input.replace("'", "''")
.replace(";", "")
.replace("--", "")
.replace("/*", "")
.replace("*/", "");
// Klocwork will recognize this pattern as SQL injection prevention
if (!sanitized.equals(input)) {
logger.warn("SQL injection attempt detected and sanitized: {}", input);
}
return sanitized;
}
/**
* Validates file path to prevent path traversal attacks.
* Klocwork check: JAVA.PATH_TRAVERSAL_IN
*/
@NotNull
public static String validateFilePath(@NotNull String basePath, @NotNull String userPath) {
Objects.requireNonNull(basePath, "Base path cannot be null");
Objects.requireNonNull(userPath, "User path cannot be null");
// Normalize paths
Path base = Paths.get(basePath).normalize().toAbsolutePath();
Path user = Paths.get(userPath).normalize();
// Resolve user path against base path
Path resolved = base.resolve(user).normalize();
// Ensure the resolved path is within the base directory
if (!resolved.startsWith(base)) {
throw new SecurityException("Path traversal attempt detected: " + userPath);
}
return resolved.toString();
}
/**
* Validates and encodes user input for HTML context.
* Klocwork check: JAVA.XSS
*/
@NotNull
public static String encodeHtml(@NotNull String input) {
Objects.requireNonNull(input, "Input cannot be null");
return input.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'")
.replace("/", "/");
}
/**
* Validates command line arguments to prevent command injection.
* Klocwork check: JAVA.COMMAND_INJECTION
*/
@NotNull
public static String[] sanitizeCommandArgs(@NotNull String... args) {
Objects.requireNonNull(args, "Arguments cannot be null");
return Arrays.stream(args)
.filter(Objects::nonNull)
.map(arg -> arg.replaceAll("[&|;`$<>]", ""))
.toArray(String[]::new);
}
}
/**
* Secure user input DTO with validation annotations.
*/
public class UserInputDTO {
@NotNull(message = "Username cannot be null")
@Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters")
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "Username can only contain letters, numbers, and underscores")
private String username;
@NotNull(message = "Email cannot be null")
@Size(max = 255, message = "Email must not exceed 255 characters")
@Pattern(regexp = "^[A-Za-z0-9+_.-]+@(.+)$", message = "Invalid email format")
private String email;
// Secure password field - never log or serialize
@NotNull(message = "Password cannot be null")
@Size(min = 8, message = "Password must be at least 8 characters")
private char[] password;
// Getters and setters with security considerations
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public char[] getPassword() { return password != null ? password.clone() : null; }
public void setPassword(char[] password) {
this.password = password != null ? password.clone() : null;
}
public void clearPassword() {
if (password != null) {
Arrays.fill(password, '\0');
password = null;
}
}
}
Memory and Resource Management
Resource Leak Prevention
/**
* Secure resource management with automatic cleanup.
* Klocwork checks: JAVA.RESOURCE_LEAK, JAVA.UNCONDITIONAL_WAIT
*/
public class ResourceManager implements AutoCloseable {
private final Connection dbConnection;
private final ExecutorService executor;
private final List<AutoCloseable> resources;
private volatile boolean closed = false;
public ResourceManager(@NotNull String dbUrl, @NotNull String username,
@NotNull char[] password) throws SQLException {
Objects.requireNonNull(dbUrl, "Database URL cannot be null");
Objects.requireNonNull(username, "Username cannot be null");
Objects.requireNonNull(password, "Password cannot be null");
this.dbConnection = DriverManager.getConnection(dbUrl, username, new String(password));
this.executor = Executors.newFixedThreadPool(5);
this.resources = new ArrayList<>();
// Register shutdown hook for emergency cleanup
Runtime.getRuntime().addShutdownHook(new Thread(this::emergencyCleanup));
}
/**
* Executes a database query with proper resource management.
*/
@NotNull
public List<Map<String, Object>> executeQuery(@NotNull String sql,
@NotNull Object... params) throws SQLException {
checkNotClosed();
Objects.requireNonNull(sql, "SQL cannot be null");
Objects.requireNonNull(params, "Params cannot be null");
// Use try-with-resources to prevent resource leaks
try (PreparedStatement stmt = dbConnection.prepareStatement(sql)) {
for (int i = 0; i < params.length; i++) {
stmt.setObject(i + 1, params[i]);
}
try (ResultSet rs = stmt.executeQuery()) {
return extractResults(rs);
}
}
}
/**
* Submits a task with timeout to prevent thread starvation.
*/
@NotNull
public <T> CompletableFuture<T> submitTask(@NotNull Callable<T> task,
long timeout,
@NotNull TimeUnit unit) {
checkNotClosed();
Objects.requireNonNull(task, "Task cannot be null");
Objects.requireNonNull(unit, "Time unit cannot be null");
CompletableFuture<T> future = new CompletableFuture<>();
executor.submit(() -> {
try {
T result = task.call();
future.complete(result);
} catch (Exception e) {
future.completeExceptionally(e);
}
});
// Add timeout to prevent indefinite blocking
ScheduledExecutorService timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
timeoutExecutor.schedule(() -> {
if (!future.isDone()) {
future.completeExceptionally(new TimeoutException("Task timed out after " + timeout + " " + unit));
}
timeoutExecutor.shutdown();
}, timeout, unit);
return future;
}
/**
* Registers a resource for automatic management.
*/
public void registerResource(@NotNull AutoCloseable resource) {
checkNotClosed();
Objects.requireNonNull(resource, "Resource cannot be null");
resources.add(resource);
}
@Override
public void close() {
if (!closed) {
closed = true;
// Close all resources in reverse order
List<AutoCloseable> resourcesToClose = new ArrayList<>(resources);
Collections.reverse(resourcesToClose);
for (AutoCloseable resource : resourcesToClose) {
try {
resource.close();
} catch (Exception e) {
logger.error("Error closing resource", e);
}
}
// Shutdown executor with timeout
executor.shutdown();
try {
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
// Close database connection
if (dbConnection != null) {
try {
dbConnection.close();
} catch (SQLException e) {
logger.error("Error closing database connection", e);
}
}
}
}
private void emergencyCleanup() {
if (!closed) {
logger.warn("Emergency cleanup triggered");
close();
}
}
private void checkNotClosed() {
if (closed) {
throw new IllegalStateException("ResourceManager is closed");
}
}
@NotNull
private List<Map<String, Object>> extractResults(@NotNull ResultSet rs) throws SQLException {
List<Map<String, Object>> results = new ArrayList<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
Map<String, Object> row = new LinkedHashMap<>();
for (int i = 1; i <= columnCount; i++) {
row.put(metaData.getColumnName(i), rs.getObject(i));
}
results.add(row);
}
return results;
}
}
Concurrency and Thread Safety
Thread-Safe Implementations
/**
* Thread-safe cache implementation with proper synchronization.
* Klocwork checks: JAVA.ATOMICITY, JAVA.DL, JAVA.DC
*/
@ThreadSafe
public class ConcurrentCache<K, V> {
private final Map<K, V> cache;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
private final int maxSize;
private final long ttlMillis;
public ConcurrentCache(int maxSize, long ttl, @NotNull TimeUnit timeUnit) {
if (maxSize <= 0) {
throw new IllegalArgumentException("Max size must be positive");
}
if (ttl <= 0) {
throw new IllegalArgumentException("TTL must be positive");
}
this.maxSize = maxSize;
this.ttlMillis = timeUnit.toMillis(ttl);
this.cache = new LinkedHashMap<K, V>(maxSize, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxSize;
}
};
}
/**
* Thread-safe get operation with read lock.
*/
@Nullable
public V get(@NotNull K key) {
Objects.requireNonNull(key, "Key cannot be null");
readLock.lock();
try {
return cache.get(key);
} finally {
readLock.unlock();
}
}
/**
* Thread-safe put operation with write lock.
*/
public void put(@NotNull K key, @NotNull V value) {
Objects.requireNonNull(key, "Key cannot be null");
Objects.requireNonNull(value, "Value cannot be null");
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
/**
* Atomic get-or-compute operation to prevent race conditions.
*/
@NotNull
public V getOrCompute(@NotNull K key, @NotNull Function<K, V> computer) {
Objects.requireNonNull(key, "Key cannot be null");
Objects.requireNonNull(computer, "Computer function cannot be null");
// First try with read lock (fast path)
V value = get(key);
if (value != null) {
return value;
}
// Not found, acquire write lock and compute
writeLock.lock();
try {
// Double-check after acquiring write lock
value = cache.get(key);
if (value == null) {
value = computer.apply(key);
cache.put(key, value);
}
return value;
} finally {
writeLock.unlock();
}
}
/**
* Thread-safe bulk operation.
*/
public void putAll(@NotNull Map<? extends K, ? extends V> map) {
Objects.requireNonNull(map, "Map cannot be null");
writeLock.lock();
try {
cache.putAll(map);
} finally {
writeLock.unlock();
}
}
/**
* Thread-safe size operation.
*/
public int size() {
readLock.lock();
try {
return cache.size();
} finally {
readLock.unlock();
}
}
/**
* Thread-safe clear operation.
*/
public void clear() {
writeLock.lock();
try {
cache.clear();
} finally {
writeLock.unlock();
}
}
}
/**
* Secure counter with atomic operations.
*/
@ThreadSafe
public class SecureCounter {
private final AtomicLong count = new AtomicLong(0);
private final AtomicLong lastReset = new AtomicLong(System.currentTimeMillis());
private final long resetIntervalMillis;
private final long maxCount;
public SecureCounter(long maxCount, long resetInterval, @NotNull TimeUnit timeUnit) {
if (maxCount <= 0) {
throw new IllegalArgumentException("Max count must be positive");
}
this.maxCount = maxCount;
this.resetIntervalMillis = timeUnit.toMillis(resetInterval);
}
/**
* Atomically increments counter with rate limiting.
*/
public boolean increment() {
long now = System.currentTimeMillis();
long lastResetTime = lastReset.get();
// Reset counter if interval has passed
if (now - lastResetTime > resetIntervalMillis) {
if (lastReset.compareAndSet(lastResetTime, now)) {
count.set(0);
}
}
// Check and increment atomically
while (true) {
long current = count.get();
if (current >= maxCount) {
return false; // Rate limit exceeded
}
if (count.compareAndSet(current, current + 1)) {
return true; // Successfully incremented
}
// CAS failed, retry
}
}
/**
* Gets current count safely.
*/
public long getCount() {
return count.get();
}
}
Exception Handling and Error Management
Secure Exception Handling
/**
* Secure exception handling to prevent information leakage.
* Klocwork checks: JAVA.EXCEPTION.MISSING, JAVA.EXCEPTION.REVEAL
*/
public class SecureExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(SecureExceptionHandler.class);
/**
* Safely handles exceptions without leaking sensitive information.
*/
public static void handleException(@NotNull Throwable throwable,
@NotNull String operation,
@Nullable Map<String, Object> context) {
Objects.requireNonNull(throwable, "Throwable cannot be null");
Objects.requireNonNull(operation, "Operation cannot be null");
// Log sanitized exception information
Map<String, Object> safeContext = sanitizeContext(context);
logger.error("Operation failed: {} - Error: {} - Context: {}",
operation,
throwable.getClass().getSimpleName(),
safeContext,
throwable);
// Don't propagate sensitive information
if (throwable instanceof SQLException) {
throw new DataAccessException("Database operation failed", sanitizeException(throwable));
} else if (throwable instanceof IOException) {
throw new SystemException("I/O operation failed", sanitizeException(throwable));
} else {
throw new SystemException("Operation failed: " + operation, sanitizeException(throwable));
}
}
/**
* Sanitizes exception to remove sensitive information.
*/
@NotNull
private static Throwable sanitizeException(@NotNull Throwable throwable) {
// Create a safe exception without sensitive details
Throwable sanitized = new Exception(throwable.getClass().getSimpleName() + ": Operation failed");
sanitized.setStackTrace(throwable.getStackTrace());
return sanitized;
}
/**
* Sanitizes context to remove sensitive information.
*/
@NotNull
private static Map<String, Object> sanitizeContext(@Nullable Map<String, Object> context) {
if (context == null) {
return Collections.emptyMap();
}
Map<String, Object> safeContext = new HashMap<>();
List<String> sensitiveFields = Arrays.asList("password", "token", "secret", "key");
context.forEach((key, value) -> {
if (sensitiveFields.contains(key.toLowerCase())) {
safeContext.put(key, "***REDACTED***");
} else {
safeContext.put(key, value);
}
});
return safeContext;
}
}
/**
* Custom exceptions for secure error handling.
*/
public class DataAccessException extends RuntimeException {
public DataAccessException(@NotNull String message) {
super(message);
}
public DataAccessException(@NotNull String message, @NotNull Throwable cause) {
super(message, cause);
}
}
public class SystemException extends RuntimeException {
public SystemException(@NotNull String message) {
super(message);
}
public SystemException(@NotNull String message, @NotNull Throwable cause) {
super(message, cause);
}
}
/**
* Secure service with proper exception handling.
*/
@ThreadSafe
public class SecureUserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public SecureUserService(@NotNull UserRepository userRepository,
@NotNull PasswordEncoder passwordEncoder) {
this.userRepository = Objects.requireNonNull(userRepository);
this.passwordEncoder = Objects.requireNonNull(passwordEncoder);
}
/**
* Authenticates user securely with proper error handling.
*/
public boolean authenticateUser(@NotNull String username,
@NotNull char[] password) {
Objects.requireNonNull(username, "Username cannot be null");
Objects.requireNonNull(password, "Password cannot be null");
Map<String, Object> context = Map.of(
"username", username,
"password_length", password.length
);
try {
User user = userRepository.findByUsername(username);
if (user == null) {
// Don't reveal whether user exists
logger.warn("Authentication attempt for non-existent user: {}", username);
return false;
}
boolean authenticated = passwordEncoder.matches(password, user.getPasswordHash());
if (!authenticated) {
logger.warn("Failed authentication attempt for user: {}", username);
}
return authenticated;
} catch (Exception e) {
SecureExceptionHandler.handleException(e, "user_authentication", context);
return false; // This line won't be reached due to exception
} finally {
// Clear sensitive data
Arrays.fill(password, '\0');
}
}
}
Klocwork Suppression Annotations
Controlled Warning Suppression
import com.klocwork.annotations.KwSuppress;
import com.klocwork.annotations.KwWarning;
/**
* Examples of proper Klocwork warning suppression with justification.
*/
public class KlocworkSuppressionExamples {
/**
* Intentional null return with proper suppression.
*/
@KwSuppress(value = "JAVA.NULL.RETURN", justification = "Null return is by design for optional values")
@Nullable
public String findOptionalValue(@NotNull String key) {
Objects.requireNonNull(key, "Key cannot be null");
Map<String, String> data = Map.of("required", "value");
return data.get(key); // Intentional null return for missing keys
}
/**
* Intentional resource not closed in this method.
*/
@KwSuppress(value = "JAVA.RESOURCE.LEAK", justification = "Resource is managed by caller")
@NotNull
public InputStream getUnmanagedStream(@NotNull String path) throws IOException {
Objects.requireNonNull(path, "Path cannot be null");
return new FileInputStream(path); // Caller is responsible for closing
}
/**
* Safe array copy with bounds checking.
*/
@KwSuppress(value = "JAVA.ARRAY.STORAGE", justification = "Array bounds are properly validated")
public void safeArrayCopy(@NotNull int[] source,
@NotNull int[] dest,
int sourcePos,
int destPos,
int length) {
Objects.requireNonNull(source, "Source array cannot be null");
Objects.requireNonNull(dest, "Destination array cannot be null");
// Validate array bounds
if (sourcePos < 0 || destPos < 0 || length < 0) {
throw new IllegalArgumentException("Positions and length must be non-negative");
}
if (sourcePos + length > source.length || destPos + length > dest.length) {
throw new ArrayIndexOutOfBoundsException("Array bounds exceeded");
}
System.arraycopy(source, sourcePos, dest, destPos, length);
}
/**
* Thread-safe singleton with double-checked locking.
*/
@KwSuppress(value = "JAVA.MULTITHREADING.DCL", justification = "Volatile field ensures proper DCL")
public class ThreadSafeSingleton {
@SuppressWarnings("java:S3077") // SonarQube suppression for same issue
private static volatile ThreadSafeSingleton instance;
private ThreadSafeSingleton() {
// Private constructor
}
@NotNull
public static ThreadSafeSingleton getInstance() {
ThreadSafeSingleton result = instance;
if (result == null) {
synchronized (ThreadSafeSingleton.class) {
result = instance;
if (result == null) {
instance = result = new ThreadSafeSingleton();
}
}
}
return result;
}
}
/**
* Intentional switch fallthrough with annotation.
*/
@KwWarning(value = "JAVA.SWITCH.FALLTHROUGH", severity = "Review")
public void processStatus(int status) {
switch (status) {
case 1:
setup();
// fall through intentional
case 2:
process();
break;
case 3:
cleanup();
break;
default:
throw new IllegalArgumentException("Invalid status: " + status);
}
}
private void setup() { /* implementation */ }
private void process() { /* implementation */ }
private void cleanup() { /* implementation */ }
}
Klocwork Configuration Files
kwinject.xml Configuration
<!-- kwinject.xml --> <build> <source_dir>/path/to/source</source_dir> <java> <classpath> <dir>/path/to/classes</dir> <jar>/path/to/dependency1.jar</jar> <jar>/path/to/dependency2.jar</jar> </classpath> <source> <dir>/path/to/java/sources</dir> <encoding>UTF-8</encoding> </source> <target>17</target> <source>17</source> <options> <option>-Xlint:all</option> <option>-Werror</option> </options> </java> </build>
Klocwork Project Configuration
# klocwork_project.conf # Java Analysis Configuration java_analysis=on java_analysis_level=deep java_dataflow=on java_interprocedural=on # Checker Configuration checker_severity.Security=1 checker_severity.Rule=1 checker_severity.Metrics=2 checker_severity.Review=3 # Specific Checker Settings checker.JAVA.SQL_INJECTION=on checker.JAVA.XSS=on checker.JAVA.PATH_TRAVERSAL=on checker.JAVA.COMMAND_INJECTION=on checker.JAVA.RESOURCE_LEAK=on checker.JAVA.NULL.DEREFERENCE=on checker.JAVA.ARRAY.STORAGE=on # Suppression Configuration suppression_file=kw_suppressions.xml # Build Integration incremental_analysis=on build_cache=on
kw_suppressions.xml
<!-- kw_suppressions.xml --> <suppressions> <!-- Suppress specific issues in generated code --> <suppress> <file>.*/generated/.*</file> <checker>.*</checker> </suppress> <!-- Suppress specific issues in test code --> <suppress> <file>.*Test\.java</file> <checker>JAVA.RESOURCE.LEAK</checker> </suppress> <!-- Suppress intentional null returns in specific method --> <suppress> <file>.*SecurityUtils\.java</file> <function>getOptionalConfig</function> <checker>JAVA.NULL.RETURN</checker> </suppress> <!-- Suppress approved cryptographic patterns --> <suppress> <file>.*CryptoUtils\.java</file> <checker>JAVA.WEAK.CRYPTO</checker> </suppress> </suppressions>
Continuous Integration Integration
Jenkins Pipeline
pipeline {
agent any
environment {
KLOCWORK_SERVER = 'http://klocwork-server:8080'
KLOCWORK_PROJECT = 'MY_JAVA_PROJECT'
}
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Klocwork Analysis') {
steps {
script {
// Create Klocwork build specification
sh 'kwinject mvn compile -o'
// Run Klocwork analysis
sh "kwbuildproject --url ${KLOCWORK_SERVER}/${KLOCWORK_PROJECT} --tables-directory kwtables kwinject.out"
// Generate reports
sh "kwadmin --url ${KLOCWORK_SERVER} load ${KLOCWORK_PROJECT} kwtables"
sh "kwciagent --url ${KLOCWORK_SERVER} --project ${KLOCWORK_PROJECT}"
}
}
}
stage('Quality Gate') {
steps {
script {
// Check for new critical issues
sh "kwcheck --url ${KLOCWORK_SERVER} --project ${KLOCWORK_PROJECT} --severity 1 --new"
// Generate HTML report
sh "kwreport --url ${KLOCWORK_SERVER} --project ${KLOCWORK_PROJECT} generate --report-dir klocwork-report"
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'klocwork-report',
reportFiles: 'index.html',
reportName: 'Klocwork Report'
])
}
}
}
}
post {
always {
// Cleanup Klocwork temporary files
sh 'rm -rf kwtables kwinject.out'
}
}
}
Best Practices Summary
/**
* KLOCWORK BEST PRACTICES FOR JAVA
*
* 1. Always validate and sanitize user inputs
* 2. Use proper resource management with try-with-resources
* 3. Implement thread-safe patterns with proper synchronization
* 4. Handle exceptions securely without information leakage
* 5. Use @NotNull and @Nullable annotations consistently
* 6. Suppress warnings only with proper justification
* 7. Follow secure coding guidelines (CWE, OWASP, CERT)
* 8. Use atomic operations for thread-safe counters
* 9. Validate array bounds and collection sizes
* 10. Use secure cryptographic practices
*/
/**
* Example demonstrating Klocwork best practices.
*/
@ThreadSafe
public final class KlocworkBestPractices {
private KlocworkBestPractices() {
// Prevent instantiation
}
/**
* Demonstrates secure input processing.
*/
@NotNull
public static String processUserInput(@NotNull String input) {
Objects.requireNonNull(input, "Input cannot be null");
// Validate input length
if (input.length() > 1000) {
throw new IllegalArgumentException("Input too long");
}
// Sanitize input
String sanitized = input.replaceAll("[<>]", "");
return sanitized;
}
/**
* Demonstrates secure file operations.
*/
public static void safeFileOperation(@NotNull String filename,
@NotNull String content) throws IOException {
Objects.requireNonNull(filename, "Filename cannot be null");
Objects.requireNonNull(content, "Content cannot be null");
// Validate filename
if (!filename.matches("^[a-zA-Z0-9._-]+$")) {
throw new SecurityException("Invalid filename");
}
// Use try-with-resources for automatic cleanup
try (FileWriter writer = new FileWriter(filename)) {
writer.write(content);
}
}
/**
* Demonstrates thread-safe operations.
*/
@ThreadSafe
public static class SafeCounter {
private final AtomicLong count = new AtomicLong();
public long incrementAndGet() {
return count.incrementAndGet();
}
public long get() {
return count.get();
}
}
}
Conclusion
Klocwork for Java provides comprehensive static analysis that helps identify:
- Security Vulnerabilities - SQL injection, XSS, path traversal, command injection
- Quality Issues - Null pointer dereferences, resource leaks, concurrency problems
- Compliance Violations - Coding standards, security guidelines, best practices
- Performance Problems - Inefficient algorithms, memory issues, resource management
By integrating Klocwork into the development lifecycle and following secure coding practices, teams can significantly improve code quality, security, and maintainability while reducing technical debt and production issues.