1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! Memory safety and security utilities for the lipgloss library.
//!
//! This module provides protection against memory exhaustion attacks and ensures
//! safe allocation patterns when processing untrusted input.
/// Maximum allowed dimension value for width, height, padding, margin, and tab width.
/// This prevents excessive memory allocation from malicious or erroneous input.
///
/// Set to 10,000 which allows for reasonable terminal layouts while preventing
/// multi-gigabyte allocations from dimension values.
pub const MAX_DIMENSION: i32 = 10_000;
/// Maximum allowed string repetition count to prevent memory exhaustion.
/// This is used by safe_repeat and other allocation functions.
pub const MAX_REPEAT_COUNT: usize = MAX_DIMENSION as usize;
/// Maximum total memory budget for a single render operation (in bytes).
/// This provides an additional safety net against cumulative allocations.
pub const MAX_RENDER_MEMORY_BUDGET: usize = 50_000_000; // 50MB
/// Maximum number of bytes to scan when parsing a single ANSI escape sequence.
/// This prevents unbounded scanning in the presence of malformed or unterminated
/// sequences (e.g., an ESC without a terminating byte), mitigating potential DoS.
pub const MAX_ANSI_SEQ_LEN: usize = 64;
/// Validates that a dimension value is within safe bounds.
///
/// # Arguments
///
/// * `value` - The dimension value to validate
/// * `name` - Name of the dimension for error messages
///
/// # Returns
///
/// The validated value, clamped to safe bounds.
///
/// # Examples
///
/// ```rust
/// use lipgloss::security::validate_dimension;
///
/// assert_eq!(validate_dimension(100, "width"), 100);
/// assert_eq!(validate_dimension(20000, "width"), 10000); // Clamped to MAX_DIMENSION
/// assert_eq!(validate_dimension(-5, "padding"), 0); // Negative values become 0
/// ```
/// Validates tab width allowing the special sentinel -1 (keep tabs as-is).
///
/// Values are clamped as follows:
/// - `-1` exactly -> `-1` (keep tabs)
/// - Other negative values -> `0` (for safety)
/// - `0` -> remove tabs
/// - `1..=MAX_DIMENSION` -> unchanged (limit enforced)
/// Safely repeats a character with bounds checking to prevent memory exhaustion.
///
/// This function provides a safe alternative to `String::repeat()` that prevents
/// excessive memory allocation from large repeat counts.
///
/// # Arguments
///
/// * `ch` - The character to repeat
/// * `count` - The number of repetitions (will be clamped to MAX_REPEAT_COUNT)
///
/// # Returns
///
/// A string containing the repeated character, or empty string if count is 0.
///
/// # Examples
///
/// ```rust
/// use lipgloss::security::safe_repeat;
///
/// assert_eq!(safe_repeat(' ', 5), " ");
/// assert_eq!(safe_repeat('=', 0), "");
///
/// // Large values are safely clamped
/// let result = safe_repeat('-', 50000);
/// assert_eq!(result.len(), 10000); // Clamped to MAX_REPEAT_COUNT
/// ```
/// Safely repeats a string with bounds checking to prevent memory exhaustion.
///
/// This function provides a safe alternative to `str.repeat()` that prevents
/// excessive memory allocation from large repeat counts.
///
/// # Arguments
///
/// * `s` - The string to repeat
/// * `count` - The number of repetitions (will be clamped based on string length)
///
/// # Returns
///
/// A string containing the repeated content, with total length capped.
///
/// # Examples
///
/// ```rust
/// use lipgloss::security::safe_str_repeat;
///
/// assert_eq!(safe_str_repeat("ab", 3), "ababab");
/// assert_eq!(safe_str_repeat("test", 0), "");
///
/// // Large values are safely clamped based on total output size
/// let result = safe_str_repeat("x", 50000);
/// assert!(result.len() <= 10000);
/// ```
/// Checks if a memory allocation of the given size would exceed safe limits.
///
/// # Arguments
///
/// * `size` - The proposed allocation size in bytes
///
/// # Returns
///
/// `true` if the allocation is safe, `false` if it would exceed limits.