Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(296)

Side by Side Diff: runtime/vm/bigint_operations.cc

Issue 23754006: Catch potential integer overflows in bigint operations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 Google Inc. All Rights Reserved.
2 2
3 #include "vm/bigint_operations.h" 3 #include "vm/bigint_operations.h"
4 4
5 #include "platform/assert.h"
5 #include "platform/utils.h" 6 #include "platform/utils.h"
6 7
7 #include "vm/double_internals.h" 8 #include "vm/double_internals.h"
8 #include "vm/exceptions.h" 9 #include "vm/exceptions.h"
9 #include "vm/object_store.h" 10 #include "vm/object_store.h"
10 #include "vm/zone.h" 11 #include "vm/zone.h"
11 12
12 namespace dart { 13 namespace dart {
13 14
14 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { 15 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 // recursive call is not negative. 100 // recursive call is not negative.
100 // We don't catch leading '-'s for zero. Ex: "--0", or "---". 101 // We don't catch leading '-'s for zero. Ex: "--0", or "---".
101 if (str[0] == '-') { 102 if (str[0] == '-') {
102 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space)); 103 const Bigint& result = Bigint::Handle(NewFromCString(&str[1], space));
103 result.ToggleSign(); 104 result.ToggleSign();
104 ASSERT(result.IsZero() || result.IsNegative()); 105 ASSERT(result.IsZero() || result.IsNegative());
105 ASSERT(IsClamped(result)); 106 ASSERT(IsClamped(result));
106 return result.raw(); 107 return result.raw();
107 } 108 }
108 109
109 intptr_t str_length = strlen(str); 110 const intptr_t str_length = strlen(str);
111 if (str_length < 0) {
112 FATAL("Fatal error in BigintOperations::NewFromCString: string too long");
113 }
110 if ((str_length > 2) && 114 if ((str_length > 2) &&
111 (str[0] == '0') && 115 (str[0] == '0') &&
112 ((str[1] == 'x') || (str[1] == 'X'))) { 116 ((str[1] == 'x') || (str[1] == 'X'))) {
113 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); 117 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space));
114 ASSERT(IsClamped(result)); 118 ASSERT(IsClamped(result));
115 return result.raw(); 119 return result.raw();
116 } else { 120 } else {
117 return FromDecimalCString(str, space); 121 return FromDecimalCString(str, space);
118 } 122 }
119 } 123 }
120 124
121 125
122 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) { 126 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) {
123 ASSERT(kDigitBitSize % 4 == 0); 127 ASSERT(kDigitBitSize % 4 == 0);
124 intptr_t hex_length = strlen(hex_string); 128 const intptr_t hex_length = strlen(hex_string);
129 if (hex_length < 0) {
130 FATAL("Fatal error in BigintOperations::ComputeChunkLength: "
131 "string too long");
132 }
125 // Round up. 133 // Round up.
126 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; 134 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1;
127 return bigint_length; 135 return bigint_length;
128 } 136 }
129 137
130 138
131 RawBigint* BigintOperations::FromHexCString(const char* hex_string, 139 RawBigint* BigintOperations::FromHexCString(const char* hex_string,
132 Heap::Space space) { 140 Heap::Space space) {
133 // If the string starts with '-' recursively restart the whole operation 141 // If the string starts with '-' recursively restart the whole operation
134 // without the character and then toggle the sign. 142 // without the character and then toggle the sign.
(...skipping 16 matching lines...) Expand all
151 159
152 160
153 RawBigint* BigintOperations::FromDecimalCString(const char* str, 161 RawBigint* BigintOperations::FromDecimalCString(const char* str,
154 Heap::Space space) { 162 Heap::Space space) {
155 Isolate* isolate = Isolate::Current(); 163 Isolate* isolate = Isolate::Current();
156 // Read 8 digits a time. 10^8 < 2^27. 164 // Read 8 digits a time. 10^8 < 2^27.
157 const int kDigitsPerIteration = 8; 165 const int kDigitsPerIteration = 8;
158 const Chunk kTenMultiplier = 100000000; 166 const Chunk kTenMultiplier = 100000000;
159 ASSERT(kDigitBitSize >= 27); 167 ASSERT(kDigitBitSize >= 27);
160 168
161 intptr_t str_length = strlen(str); 169 const intptr_t str_length = strlen(str);
170 if (str_length < 0) {
171 FATAL("Fatal error in BigintOperations::FromDecimalCString: "
172 "string too long");
173 }
162 intptr_t str_pos = 0; 174 intptr_t str_pos = 0;
163 175
164 // Read first digit separately. This avoids a multiplication and addition. 176 // Read first digit separately. This avoids a multiplication and addition.
165 // The first digit might also not have kDigitsPerIteration decimal digits. 177 // The first digit might also not have kDigitsPerIteration decimal digits.
166 int first_digit_decimal_digits = str_length % kDigitsPerIteration; 178 int first_digit_decimal_digits = str_length % kDigitsPerIteration;
167 Chunk digit = 0; 179 Chunk digit = 0;
168 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { 180 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) {
169 char c = str[str_pos++]; 181 char c = str[str_pos++];
170 ASSERT(('0' <= c) && (c <= '9')); 182 ASSERT(('0' <= c) && (c <= '9'));
171 digit = digit * 10 + c - '0'; 183 digit = digit * 10 + c - '0';
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 void* data, 256 void* data,
245 uword (*allocator)(intptr_t size)) { 257 uword (*allocator)(intptr_t size)) {
246 NoGCScope no_gc; 258 NoGCScope no_gc;
247 259
248 ASSERT(kDigitBitSize % 4 == 0); 260 ASSERT(kDigitBitSize % 4 == 0);
249 261
250 intptr_t chunk_length = length; 262 intptr_t chunk_length = length;
251 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); 263 Chunk* chunk_data = reinterpret_cast<Chunk*>(data);
252 if (length == 0) { 264 if (length == 0) {
253 const char* zero = "0x0"; 265 const char* zero = "0x0";
254 const int kLength = strlen(zero); 266 const intptr_t kLength = strlen(zero);
255 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); 267 char* result = reinterpret_cast<char*>(allocator(kLength + 1));
256 ASSERT(result != NULL); 268 ASSERT(result != NULL);
257 memmove(result, zero, kLength); 269 memmove(result, zero, kLength);
258 result[kLength] = '\0'; 270 result[kLength] = '\0';
259 return result; 271 return result;
260 } 272 }
261 ASSERT(chunk_data != NULL); 273 ASSERT(chunk_data != NULL);
262 274
263 // Compute the number of hex-digits that are needed to represent the 275 // Compute the number of hex-digits that are needed to represent the
264 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit 276 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit
265 // characters. 277 // characters.
266 int leading_hex_digits = 0; 278 int leading_hex_digits = 0;
267 Chunk leading_digit = chunk_data[chunk_length - 1]; 279 Chunk leading_digit = chunk_data[chunk_length - 1];
268 while (leading_digit != 0) { 280 while (leading_digit != 0) {
269 leading_hex_digits++; 281 leading_hex_digits++;
270 leading_digit >>= 4; 282 leading_digit >>= 4;
271 } 283 }
272 // Sum up the space that is needed for the string-representation. 284 // Sum up the space that is needed for the string-representation.
273 intptr_t required_size = 0; 285 intptr_t required_size = 0;
274 if (is_negative) { 286 if (is_negative) {
275 required_size++; // For the leading "-". 287 required_size++; // For the leading "-".
276 } 288 }
277 required_size += 2; // For the "0x". 289 required_size += 2; // For the "0x".
278 required_size += leading_hex_digits; 290 required_size += leading_hex_digits;
279 required_size += (chunk_length - 1) * kHexCharsPerDigit; 291 required_size += (chunk_length - 1) * kHexCharsPerDigit;
280 required_size++; // For the trailing '\0'. 292 required_size++; // For the trailing '\0'.
293 if (required_size < 0) {
294 FATAL("Fatal error in BigintOperations::ToHexCString: string too long");
295 }
siva 2013/09/17 00:19:52 As discussed offline the overflow could happen bef
Michael Lippautz (Google) 2013/09/17 03:36:50 Done.
281 char* result = reinterpret_cast<char*>(allocator(required_size)); 296 char* result = reinterpret_cast<char*>(allocator(required_size));
282 // Print the number into the string. 297 // Print the number into the string.
283 // Start from the last position. 298 // Start from the last position.
284 intptr_t pos = required_size - 1; 299 intptr_t pos = required_size - 1;
285 result[pos--] = '\0'; 300 result[pos--] = '\0';
286 for (intptr_t i = 0; i < (chunk_length - 1); i++) { 301 for (intptr_t i = 0; i < (chunk_length - 1); i++) {
287 // Print all non-leading characters (which are printed with 302 // Print all non-leading characters (which are printed with
288 // kHexCharsPerDigit characters. 303 // kHexCharsPerDigit characters.
289 Chunk digit = chunk_data[i]; 304 Chunk digit = chunk_data[i];
290 for (int j = 0; j < kHexCharsPerDigit; j++) { 305 for (int j = 0; j < kHexCharsPerDigit; j++) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 // Approximate the size of the resulting string. We prefer overestimating 359 // Approximate the size of the resulting string. We prefer overestimating
345 // to not allocating enough. 360 // to not allocating enough.
346 int64_t bit_length = length * kDigitBitSize; 361 int64_t bit_length = length * kDigitBitSize;
347 ASSERT(bit_length > length); 362 ASSERT(bit_length > length);
348 int64_t decimal_length = (bit_length * kLog2Dividend / kLog2Divisor) + 1; 363 int64_t decimal_length = (bit_length * kLog2Dividend / kLog2Divisor) + 1;
349 // Add one byte for the trailing \0 character. 364 // Add one byte for the trailing \0 character.
350 int64_t required_size = decimal_length + 1; 365 int64_t required_size = decimal_length + 1;
351 if (bigint.IsNegative()) { 366 if (bigint.IsNegative()) {
352 required_size++; 367 required_size++;
353 } 368 }
354 ASSERT(required_size == static_cast<intptr_t>(required_size)); 369 if (required_size != static_cast<intptr_t>(required_size)) {
siva 2013/09/17 00:19:52 Ditto comment here too.
Michael Lippautz (Google) 2013/09/17 03:36:50 Removed the check, because it's already there (as
370 FATAL("Fatal error in BigintOperations::ToDecimalCString: "
371 "string too long");
372 }
355 // We will fill the result in the inverse order and then exchange at the end. 373 // We will fill the result in the inverse order and then exchange at the end.
356 char* result = 374 char* result =
357 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); 375 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size)));
358 ASSERT(result != NULL); 376 ASSERT(result != NULL);
359 int result_pos = 0; 377 int result_pos = 0;
360 378
361 // We divide the input into pieces of ~27 bits which can be efficiently 379 // We divide the input into pieces of ~27 bits which can be efficiently
362 // handled. 380 // handled.
363 const intptr_t kChunkDivisor = 100000000; 381 const intptr_t kChunkDivisor = 100000000;
364 const int kChunkDigits = 8; 382 const int kChunkDigits = 8;
(...skipping 969 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 1352
1335 1353
1336 void BigintOperations::FromHexCString(const char* hex_string, 1354 void BigintOperations::FromHexCString(const char* hex_string,
1337 const Bigint& value) { 1355 const Bigint& value) {
1338 ASSERT(hex_string[0] != '-'); 1356 ASSERT(hex_string[0] != '-');
1339 intptr_t bigint_length = ComputeChunkLength(hex_string); 1357 intptr_t bigint_length = ComputeChunkLength(hex_string);
1340 // The bigint's least significant digit (lsd) is at position 0, whereas the 1358 // The bigint's least significant digit (lsd) is at position 0, whereas the
1341 // given string has it's lsd at the last position. 1359 // given string has it's lsd at the last position.
1342 // The hex_i index, pointing into the string, starts therefore at the end, 1360 // The hex_i index, pointing into the string, starts therefore at the end,
1343 // whereas the bigint-index (i) starts at 0. 1361 // whereas the bigint-index (i) starts at 0.
1344 intptr_t hex_length = strlen(hex_string); 1362 const intptr_t hex_length = strlen(hex_string);
1363 if (hex_length < 0) {
1364 FATAL("Fatal error in BigintOperations::FromHexCString: string too long");
1365 }
1345 intptr_t hex_i = hex_length - 1; 1366 intptr_t hex_i = hex_length - 1;
1346 for (intptr_t i = 0; i < bigint_length; i++) { 1367 for (intptr_t i = 0; i < bigint_length; i++) {
1347 Chunk digit = 0; 1368 Chunk digit = 0;
1348 int shift = 0; 1369 int shift = 0;
1349 for (int j = 0; j < kHexCharsPerDigit; j++) { 1370 for (int j = 0; j < kHexCharsPerDigit; j++) {
1350 // Reads a block of hexadecimal digits and stores it in 'digit'. 1371 // Reads a block of hexadecimal digits and stores it in 'digit'.
1351 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". 1372 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456".
1352 if (hex_i < 0) { 1373 if (hex_i < 0) {
1353 break; 1374 break;
1354 } 1375 }
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
1748 int BigintOperations::CountBits(Chunk digit) { 1769 int BigintOperations::CountBits(Chunk digit) {
1749 int result = 0; 1770 int result = 0;
1750 while (digit != 0) { 1771 while (digit != 0) {
1751 digit >>= 1; 1772 digit >>= 1;
1752 result++; 1773 result++;
1753 } 1774 }
1754 return result; 1775 return result;
1755 } 1776 }
1756 1777
1757 } // namespace dart 1778 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698