Incorrect Use of Autoboxing and Unboxing for Performance Critical Operations
Description
Incorrect Use of Autoboxing and Unboxing for Performance Critical Operations occurs when code uses boxed primitives, which may introduce inefficiencies into performance-critical operations. Languages like Java and C# automatically convert primitive types to corresponding wrapper classes (autoboxing) and vice versa (unboxing). While this simplifies code, using boxed primitives in performance-sensitive contexts creates significant overhead including object allocation, garbage collection pressure, and cache inefficiency.
Risk
Autoboxing in performance-critical code has significant implications. CPU resources may be consumed excessively. Memory allocation overhead increases. Garbage collection pauses may occur. Cache efficiency is reduced. Response times may be degraded. Resource exhaustion may be possible. Denial of service conditions may arise. System availability may be impacted.
Solution
Use primitive types instead of boxed types in performance-critical code. Limit boxed primitives to situations requiring typed parameters. Avoid autoboxing in loops or frequently-called methods. Use specialized collections like IntStream instead of Stream
Common Consequences
| Impact | Details |
|---|---|
| Availability | Scope: Availability DoS: Resource Consumption (CPU/Memory) - Autoboxing/unboxing in performance-critical code causes reduced performance and potential resource exhaustion, impacting system availability. |
Example Code
Vulnerable Code
// Vulnerable: Using boxed primitives in performance-critical loop
public class VulnerableAutoboxing {
// VULNERABLE: Long instead of long causes massive autoboxing
public long vulnerableSum() {
Long count = 0L; // Boxed Long
for (long i = 0; i < Integer.MAX_VALUE; i++) {
count += i; // Autoboxing on every iteration!
// This creates a new Long object each time
}
return count;
}
// VULNERABLE: Using Integer in collection causes boxing on insert/retrieve
public int vulnerableCollectionSum(List<Integer> numbers) {
Integer sum = 0; // Boxed Integer
for (Integer num : numbers) {
sum += num; // Unbox num, add, then autobox result
}
return sum;
}
// VULNERABLE: Method signature forces autoboxing
public Integer vulnerableAdd(Integer a, Integer b) {
return a + b; // Unbox both, add, autobox result
}
// VULNERABLE: HashMap with primitive-like keys
public void vulnerableMap() {
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 1000000; i++) {
map.put(i, "value" + i); // Autobox i to Integer
}
for (int i = 0; i < 1000000; i++) {
String value = map.get(i); // Autobox i to Integer
}
}
// VULNERABLE: Conditional causing repeated boxing
public void vulnerableConditional(List<Integer> numbers) {
for (int i = 0; i < numbers.size(); i++) {
// Comparing int to Integer causes unboxing
if (numbers.get(i) == i) { // Unbox for comparison
process(numbers.get(i)); // Additional get and unbox
}
}
}
}
// Vulnerable: C# autoboxing issues
public class VulnerableBoxingCSharp
{
// VULNERABLE: Object parameter forces boxing
public void VulnerableLog(object value)
{
Console.WriteLine(value.ToString());
}
public void VulnerableLoop()
{
for (int i = 0; i < 1000000; i++)
{
VulnerableLog(i); // Boxing on every call!
}
}
// VULNERABLE: Using ArrayList instead of List<int>
public int VulnerableArrayList()
{
ArrayList list = new ArrayList();
for (int i = 0; i < 100000; i++)
{
list.Add(i); // Boxing
}
int sum = 0;
foreach (object item in list)
{
sum += (int)item; // Unboxing
}
return sum;
}
// VULNERABLE: Struct boxing through interface
public interface IValue
{
int GetValue();
}
public struct ValueStruct : IValue
{
public int Value;
public int GetValue() => Value;
}
public void VulnerableInterface()
{
IValue value = new ValueStruct { Value = 42 }; // Boxing!
int result = value.GetValue();
}
}
// Vulnerable: Kotlin nullable types cause boxing
class VulnerableKotlin {
// VULNERABLE: Int? is boxed, Int is primitive
fun vulnerableSum(numbers: List<Int?>): Int {
var sum: Int? = 0 // Nullable = boxed
for (num in numbers) {
sum = sum!! + (num ?: 0) // Multiple boxing operations
}
return sum!!
}
// VULNERABLE: Using java.lang.Integer explicitly
fun vulnerableExplicit(): Long {
var count: java.lang.Long = 0L
for (i in 0 until Int.MAX_VALUE) {
count += i // Autoboxing
}
return count
}
}
Fixed Code
// Fixed: Using primitive types in performance-critical code
public class SecurePrimitiveUsage {
// FIXED: Using primitive long
public long efficientSum() {
long count = 0L; // Primitive long
for (long i = 0; i < Integer.MAX_VALUE; i++) {
count += i; // No autoboxing!
}
return count;
}
// FIXED: Using primitive for accumulation
public int efficientCollectionSum(List<Integer> numbers) {
int sum = 0; // Primitive int
for (int i = 0; i < numbers.size(); i++) {
sum += numbers.get(i); // Single unbox per element
}
return sum;
}
// FIXED: Using IntStream for better performance
public int streamSum(List<Integer> numbers) {
return numbers.stream()
.mapToInt(Integer::intValue) // Convert to IntStream
.sum(); // Primitive operations
}
// FIXED: Method signature uses primitives
public int efficientAdd(int a, int b) {
return a + b; // Pure primitive operation
}
// FIXED: Using specialized primitive collections
public void efficientMap() {
// Using primitive collection library (e.g., Trove, Eclipse Collections)
// TIntObjectHashMap<String> or IntObjectHashMap<String>
// Avoids boxing for integer keys
// Or for Android:
// SparseArray<String> map = new SparseArray<>();
// Standard Java alternative: use array if keys are sequential
String[] values = new String[1000000];
for (int i = 0; i < values.length; i++) {
values[i] = "value" + i;
}
}
// FIXED: Efficient conditional with primitives
public void efficientConditional(List<Integer> numbers) {
for (int i = 0; i < numbers.size(); i++) {
int value = numbers.get(i); // Single unbox
if (value == i) {
process(value); // Reuse unboxed value
}
}
}
// FIXED: Using primitive arrays when possible
public int[] processEfficiently(int[] input) {
int[] result = new int[input.length];
for (int i = 0; i < input.length; i++) {
result[i] = input[i] * 2; // All primitive operations
}
return result;
}
}
// Fixed: C# avoiding boxing
public class SecureBoxingCSharp
{
// FIXED: Generic parameter avoids boxing
public void EfficientLog<T>(T value)
{
Console.WriteLine(value?.ToString());
}
public void EfficientLoop()
{
for (int i = 0; i < 1000000; i++)
{
EfficientLog(i); // No boxing with generic
}
}
// FIXED: Using generic List<int>
public int EfficientList()
{
List<int> list = new List<int>();
for (int i = 0; i < 100000; i++)
{
list.Add(i); // No boxing
}
int sum = 0;
foreach (int item in list)
{
sum += item; // No unboxing
}
return sum;
}
// FIXED: Using Span<T> for high-performance scenarios
public int ProcessSpan(Span<int> data)
{
int sum = 0;
for (int i = 0; i < data.Length; i++)
{
sum += data[i];
}
return sum;
}
// FIXED: Avoid interface boxing for structs
public struct ValueStruct
{
public int Value;
public int GetValue() => Value;
}
public void EfficientStruct()
{
ValueStruct value = new ValueStruct { Value = 42 };
int result = value.GetValue(); // No boxing - direct call
}
// FIXED: Use generic constraints to avoid boxing
public T Max<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b) > 0 ? a : b;
}
}
// Fixed: Kotlin using non-nullable types
class SecureKotlin {
// FIXED: Non-nullable Int is primitive
fun efficientSum(numbers: List<Int>): Int {
var sum = 0 // Primitive int
for (num in numbers) {
sum += num
}
return sum
}
// FIXED: Using primitive long
fun efficientLong(): Long {
var count = 0L // Primitive long
for (i in 0 until Int.MAX_VALUE) {
count += i
}
return count
}
// FIXED: Using primitive arrays
fun processArray(input: IntArray): IntArray {
val result = IntArray(input.size)
for (i in input.indices) {
result[i] = input[i] * 2
}
return result
}
// FIXED: Using sequences for lazy evaluation
fun efficientSequence(numbers: List<Int>): Int {
return numbers.asSequence()
.filter { it > 0 }
.map { it * 2 }
.sum()
}
}
CVE Examples
Autoboxing performance issues have been identified in various applications where tight loops with boxed primitives caused denial of service or degraded performance.
Related CWEs
- CWE-400: Uncontrolled Resource Consumption (parent)
- CWE-1006: Bad Coding Practices (category member)
References
- MITRE Corporation. "CWE-1235: Incorrect Use of Autoboxing and Unboxing for Performance Critical Operations." https://cwe.mitre.org/data/definitions/1235.html
- Oracle Java Documentation on Autoboxing
- SEI CERT Oracle Coding Standard for Java (EXP04-J)
- ISA/IEC 62443 Part 4-1 (Req SI-2)