@@ -158,7 +158,7 @@ library Strings {
158
158
* NOTE: This function will revert if the result does not fit in a `uint256`.
159
159
*/
160
160
function tryParseUint (string memory input ) internal pure returns (bool success , uint256 value ) {
161
- return tryParseUint (input, 0 , bytes (input).length );
161
+ return _tryParseUintUncheckedBounds (input, 0 , bytes (input).length );
162
162
}
163
163
164
164
/**
@@ -172,6 +172,18 @@ library Strings {
172
172
uint256 begin ,
173
173
uint256 end
174
174
) internal pure returns (bool success , uint256 value ) {
175
+ if (end > bytes (input).length || begin > end) return (false , 0 );
176
+ return _tryParseUintUncheckedBounds (input, begin, end);
177
+ }
178
+
179
+ /**
180
+ * @dev Variant of {tryParseUint} that does not check bounds and returns (true, 0) if they are invalid.
181
+ */
182
+ function _tryParseUintUncheckedBounds (
183
+ string memory input ,
184
+ uint256 begin ,
185
+ uint256 end
186
+ ) private pure returns (bool success , uint256 value ) {
175
187
bytes memory buffer = bytes (input);
176
188
177
189
uint256 result = 0 ;
@@ -216,7 +228,7 @@ library Strings {
216
228
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
217
229
*/
218
230
function tryParseInt (string memory input ) internal pure returns (bool success , int256 value ) {
219
- return tryParseInt (input, 0 , bytes (input).length );
231
+ return _tryParseIntUncheckedBounds (input, 0 , bytes (input).length );
220
232
}
221
233
222
234
uint256 private constant ABS_MIN_INT256 = 2 ** 255 ;
@@ -232,10 +244,22 @@ library Strings {
232
244
uint256 begin ,
233
245
uint256 end
234
246
) internal pure returns (bool success , int256 value ) {
247
+ if (end > bytes (input).length || begin > end) return (false , 0 );
248
+ return _tryParseIntUncheckedBounds (input, begin, end);
249
+ }
250
+
251
+ /**
252
+ * @dev Variant of {tryParseInt} that does not check bounds and returns (true, 0) if they are invalid.
253
+ */
254
+ function _tryParseIntUncheckedBounds (
255
+ string memory input ,
256
+ uint256 begin ,
257
+ uint256 end
258
+ ) private pure returns (bool success , int256 value ) {
235
259
bytes memory buffer = bytes (input);
236
260
237
261
// Check presence of a negative sign.
238
- bytes1 sign = bytes1 (_unsafeReadBytesOffset (buffer, begin));
262
+ bytes1 sign = begin == end ? bytes1 (0 ) : bytes1 ( _unsafeReadBytesOffset (buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
239
263
bool positiveSign = sign == bytes1 ("+ " );
240
264
bool negativeSign = sign == bytes1 ("- " );
241
265
uint256 offset = (positiveSign || negativeSign).toUint ();
@@ -280,7 +304,7 @@ library Strings {
280
304
* NOTE: This function will revert if the result does not fit in a `uint256`.
281
305
*/
282
306
function tryParseHexUint (string memory input ) internal pure returns (bool success , uint256 value ) {
283
- return tryParseHexUint (input, 0 , bytes (input).length );
307
+ return _tryParseHexUintUncheckedBounds (input, 0 , bytes (input).length );
284
308
}
285
309
286
310
/**
@@ -294,10 +318,22 @@ library Strings {
294
318
uint256 begin ,
295
319
uint256 end
296
320
) internal pure returns (bool success , uint256 value ) {
321
+ if (end > bytes (input).length || begin > end) return (false , 0 );
322
+ return _tryParseHexUintUncheckedBounds (input, begin, end);
323
+ }
324
+
325
+ /**
326
+ * @dev Variant of {tryParseHexUint} that does not check bounds and returns (true, 0) if they are invalid.
327
+ */
328
+ function _tryParseHexUintUncheckedBounds (
329
+ string memory input ,
330
+ uint256 begin ,
331
+ uint256 end
332
+ ) private pure returns (bool success , uint256 value ) {
297
333
bytes memory buffer = bytes (input);
298
334
299
335
// skip 0x prefix if present
300
- bool hasPrefix = bytes2 (_unsafeReadBytesOffset (buffer, begin)) == bytes2 ("0x " );
336
+ bool hasPrefix = (begin < end + 1 ) && bytes2 (_unsafeReadBytesOffset (buffer, begin)) == bytes2 ("0x " ); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
301
337
uint256 offset = hasPrefix.toUint () * 2 ;
302
338
303
339
uint256 result = 0 ;
@@ -355,12 +391,13 @@ library Strings {
355
391
uint256 end
356
392
) internal pure returns (bool success , address value ) {
357
393
// check that input is the correct length
358
- bool hasPrefix = bytes2 (_unsafeReadBytesOffset (bytes (input), begin)) == bytes2 ("0x " );
394
+ bool hasPrefix = (begin < end + 1 ) && bytes2 (_unsafeReadBytesOffset (bytes (input), begin)) == bytes2 ("0x " ); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
395
+
359
396
uint256 expectedLength = 40 + hasPrefix.toUint () * 2 ;
360
397
361
- if (end - begin == expectedLength) {
398
+ if (end - begin == expectedLength && end <= bytes (input). length ) {
362
399
// length guarantees that this does not overflow, and value is at most type(uint160).max
363
- (bool s , uint256 v ) = tryParseHexUint (input, begin, end);
400
+ (bool s , uint256 v ) = _tryParseHexUintUncheckedBounds (input, begin, end);
364
401
return (s, address (uint160 (v)));
365
402
} else {
366
403
return (false , address (0 ));
0 commit comments