|
20 | 20 | */ |
21 | 21 | public interface ShapeDeserializer extends AutoCloseable { |
22 | 22 |
|
| 23 | + int CONTAINER_PRE_ALLOCATION_LIMIT = |
| 24 | + Integer.parseInt(System.getProperty("smithy.java.serde.container-pre-allocation-limit", "10000")); |
| 25 | + |
23 | 26 | @Override |
24 | 27 | default void close() {} |
25 | 28 |
|
@@ -155,6 +158,46 @@ default int containerSize() { |
155 | 158 | return -1; |
156 | 159 | } |
157 | 160 |
|
| 161 | + /** |
| 162 | + * Returns the maximum number of elements to pre-allocate when deserializing container types (lists and maps). |
| 163 | + * |
| 164 | + * <p>This method provides a safety limit to prevent memory exhaustion attacks when deserializing untrusted data. |
| 165 | + * When a deserializer encounters a container (list or map) that reports its size via {@link #containerSize()}, |
| 166 | + * the deserialization logic may attempt to pre-allocate space for all elements to improve performance. However, |
| 167 | + * if the reported size is maliciously large (e.g., a serialized value claims to contain billions of elements), |
| 168 | + * pre-allocating that much memory could cause an {@link OutOfMemoryError} or severe performance degradation. |
| 169 | + * |
| 170 | + * <p>This limit acts as a safeguard by capping the maximum pre-allocation size. If {@link #containerSize()} |
| 171 | + * returns a value greater than this limit, deserialization implementations should fall back to dynamic allocation |
| 172 | + * strategies (e.g., adding elements one at a time to a growable collection) rather than pre-allocating space |
| 173 | + * for the full reported size. |
| 174 | + * |
| 175 | + * |
| 176 | + * <p><b>Security Implications:</b> |
| 177 | + * Setting this limit too high may expose the application to denial-of-service attacks through memory exhaustion. |
| 178 | + * Setting it too low may reduce deserialization performance for legitimate large datasets. The default value |
| 179 | + * of 50,000 elements provides a reasonable balance for most use cases. |
| 180 | + * |
| 181 | + * <p><b>Configuration:</b> |
| 182 | + * The default implementation returns the value of {@link #CONTAINER_PRE_ALLOCATION_LIMIT}, which is controlled |
| 183 | + * by the {@code smithy.java.serde.container-pre-allocation-limit} system property (default: 10000). Implementations |
| 184 | + * may override this method to provide custom limits based on specific deserialization contexts or security requirements. |
| 185 | + * |
| 186 | + * <p><b>Relationship to {@link #containerSize()}:</b> |
| 187 | + * This method should be used in conjunction with {@link #containerSize()} when determining how much memory to |
| 188 | + * pre-allocate. While {@code containerSize()} reports the claimed size from the serialized data, this method |
| 189 | + * provides the trusted upper bound for pre-allocation decisions. |
| 190 | + * |
| 191 | + * @return the maximum number of elements to pre-allocate for container deserialization, must be non-negative. |
| 192 | + * A value of 0 indicates that pre-allocation should never be performed, forcing all containers to use |
| 193 | + * dynamic allocation strategies. |
| 194 | + * @see #containerSize() |
| 195 | + * @see #CONTAINER_PRE_ALLOCATION_LIMIT |
| 196 | + */ |
| 197 | + default int containerPreAllocationLimit() { |
| 198 | + return CONTAINER_PRE_ALLOCATION_LIMIT; |
| 199 | + } |
| 200 | + |
158 | 201 | /** |
159 | 202 | * Attempt to read a map value. |
160 | 203 | * |
|
0 commit comments