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

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 // No overflow check needed since overflowing str_length implies that we take
111 // the branch to FromDecimalCString() which contains a check itself.
112 const intptr_t str_length = strlen(str);
110 if ((str_length > 2) && 113 if ((str_length > 2) &&
111 (str[0] == '0') && 114 (str[0] == '0') &&
112 ((str[1] == 'x') || (str[1] == 'X'))) { 115 ((str[1] == 'x') || (str[1] == 'X'))) {
113 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space)); 116 const Bigint& result = Bigint::Handle(FromHexCString(&str[2], space));
114 ASSERT(IsClamped(result)); 117 ASSERT(IsClamped(result));
115 return result.raw(); 118 return result.raw();
116 } else { 119 } else {
117 return FromDecimalCString(str, space); 120 return FromDecimalCString(str, space);
118 } 121 }
119 } 122 }
120 123
121 124
122 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) { 125 intptr_t BigintOperations::ComputeChunkLength(const char* hex_string) {
123 ASSERT(kDigitBitSize % 4 == 0); 126 ASSERT(kDigitBitSize % 4 == 0);
124 intptr_t hex_length = strlen(hex_string); 127 const intptr_t hex_length = strlen(hex_string);
128 if (hex_length < 0) {
129 FATAL("Fatal error in BigintOperations::ComputeChunkLength: "
130 "string too long");
131 }
125 // Round up. 132 // Round up.
126 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1; 133 intptr_t bigint_length = ((hex_length - 1) / kHexCharsPerDigit) + 1;
127 return bigint_length; 134 return bigint_length;
128 } 135 }
129 136
130 137
131 RawBigint* BigintOperations::FromHexCString(const char* hex_string, 138 RawBigint* BigintOperations::FromHexCString(const char* hex_string,
132 Heap::Space space) { 139 Heap::Space space) {
133 // If the string starts with '-' recursively restart the whole operation 140 // If the string starts with '-' recursively restart the whole operation
134 // without the character and then toggle the sign. 141 // without the character and then toggle the sign.
(...skipping 16 matching lines...) Expand all
151 158
152 159
153 RawBigint* BigintOperations::FromDecimalCString(const char* str, 160 RawBigint* BigintOperations::FromDecimalCString(const char* str,
154 Heap::Space space) { 161 Heap::Space space) {
155 Isolate* isolate = Isolate::Current(); 162 Isolate* isolate = Isolate::Current();
156 // Read 8 digits a time. 10^8 < 2^27. 163 // Read 8 digits a time. 10^8 < 2^27.
157 const int kDigitsPerIteration = 8; 164 const int kDigitsPerIteration = 8;
158 const Chunk kTenMultiplier = 100000000; 165 const Chunk kTenMultiplier = 100000000;
159 ASSERT(kDigitBitSize >= 27); 166 ASSERT(kDigitBitSize >= 27);
160 167
161 intptr_t str_length = strlen(str); 168 const intptr_t str_length = strlen(str);
169 if (str_length < 0) {
170 FATAL("Fatal error in BigintOperations::FromDecimalCString: "
171 "string too long");
172 }
162 intptr_t str_pos = 0; 173 intptr_t str_pos = 0;
163 174
164 // Read first digit separately. This avoids a multiplication and addition. 175 // Read first digit separately. This avoids a multiplication and addition.
165 // The first digit might also not have kDigitsPerIteration decimal digits. 176 // The first digit might also not have kDigitsPerIteration decimal digits.
166 int first_digit_decimal_digits = str_length % kDigitsPerIteration; 177 int first_digit_decimal_digits = str_length % kDigitsPerIteration;
167 Chunk digit = 0; 178 Chunk digit = 0;
168 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { 179 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) {
169 char c = str[str_pos++]; 180 char c = str[str_pos++];
170 ASSERT(('0' <= c) && (c <= '9')); 181 ASSERT(('0' <= c) && (c <= '9'));
171 digit = digit * 10 + c - '0'; 182 digit = digit * 10 + c - '0';
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 251
241 252
242 const char* BigintOperations::ToHexCString(intptr_t length, 253 const char* BigintOperations::ToHexCString(intptr_t length,
243 bool is_negative, 254 bool is_negative,
244 void* data, 255 void* data,
245 uword (*allocator)(intptr_t size)) { 256 uword (*allocator)(intptr_t size)) {
246 NoGCScope no_gc; 257 NoGCScope no_gc;
247 258
248 ASSERT(kDigitBitSize % 4 == 0); 259 ASSERT(kDigitBitSize % 4 == 0);
249 260
250 intptr_t chunk_length = length; 261 // Conservative maximum chunk length.
262 const intptr_t kMaxChunkLen =
263 (kIntptrMax - 2 /* 0x */
264 - 1 /* trailing '\0' */
265 - 1 /* leading '-' */) / kHexCharsPerDigit;
266 const intptr_t chunk_length = length;
267 // Conservative check assuming leading bigint-digit also takes up
268 // kHexCharsPerDigit.
269 if (chunk_length > kMaxChunkLen) {
270 FATAL("Fatal error in BigintOperations::ToHexCString: string too long");
271 }
251 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); 272 Chunk* chunk_data = reinterpret_cast<Chunk*>(data);
252 if (length == 0) { 273 if (length == 0) {
253 const char* zero = "0x0"; 274 const char* zero = "0x0";
254 const int kLength = strlen(zero); 275 const intptr_t kLength = strlen(zero);
255 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); 276 char* result = reinterpret_cast<char*>(allocator(kLength + 1));
256 ASSERT(result != NULL); 277 ASSERT(result != NULL);
257 memmove(result, zero, kLength); 278 memmove(result, zero, kLength);
258 result[kLength] = '\0'; 279 result[kLength] = '\0';
259 return result; 280 return result;
260 } 281 }
261 ASSERT(chunk_data != NULL); 282 ASSERT(chunk_data != NULL);
262 283
263 // Compute the number of hex-digits that are needed to represent the 284 // Compute the number of hex-digits that are needed to represent the
264 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit 285 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 const char* BigintOperations::ToDecimalCString( 344 const char* BigintOperations::ToDecimalCString(
324 const Bigint& bigint, uword (*allocator)(intptr_t size)) { 345 const Bigint& bigint, uword (*allocator)(intptr_t size)) {
325 // log10(2) ~= 0.30102999566398114. 346 // log10(2) ~= 0.30102999566398114.
326 const intptr_t kLog2Dividend = 30103; 347 const intptr_t kLog2Dividend = 30103;
327 const intptr_t kLog2Divisor = 100000; 348 const intptr_t kLog2Divisor = 100000;
328 // We remove a small constant for rounding imprecision, the \0 character and 349 // We remove a small constant for rounding imprecision, the \0 character and
329 // the negative sign. 350 // the negative sign.
330 const intptr_t kMaxAllowedDigitLength = 351 const intptr_t kMaxAllowedDigitLength =
331 (kIntptrMax - 10) / kLog2Dividend / kDigitBitSize * kLog2Divisor; 352 (kIntptrMax - 10) / kLog2Dividend / kDigitBitSize * kLog2Divisor;
332 353
333 intptr_t length = bigint.Length(); 354 const intptr_t length = bigint.Length();
334 Isolate* isolate = Isolate::Current(); 355 Isolate* isolate = Isolate::Current();
335 if (length >= kMaxAllowedDigitLength) { 356 if (length >= kMaxAllowedDigitLength) {
336 // Use the preallocated out of memory exception to avoid calling 357 // Use the preallocated out of memory exception to avoid calling
337 // into dart code or allocating any code. 358 // into dart code or allocating any code.
338 const Instance& exception = 359 const Instance& exception =
339 Instance::Handle(isolate->object_store()->out_of_memory()); 360 Instance::Handle(isolate->object_store()->out_of_memory());
340 Exceptions::Throw(exception); 361 Exceptions::Throw(exception);
341 UNREACHABLE(); 362 UNREACHABLE();
342 } 363 }
343 364
(...skipping 990 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 1355
1335 1356
1336 void BigintOperations::FromHexCString(const char* hex_string, 1357 void BigintOperations::FromHexCString(const char* hex_string,
1337 const Bigint& value) { 1358 const Bigint& value) {
1338 ASSERT(hex_string[0] != '-'); 1359 ASSERT(hex_string[0] != '-');
1339 intptr_t bigint_length = ComputeChunkLength(hex_string); 1360 intptr_t bigint_length = ComputeChunkLength(hex_string);
1340 // The bigint's least significant digit (lsd) is at position 0, whereas the 1361 // The bigint's least significant digit (lsd) is at position 0, whereas the
1341 // given string has it's lsd at the last position. 1362 // given string has it's lsd at the last position.
1342 // The hex_i index, pointing into the string, starts therefore at the end, 1363 // The hex_i index, pointing into the string, starts therefore at the end,
1343 // whereas the bigint-index (i) starts at 0. 1364 // whereas the bigint-index (i) starts at 0.
1344 intptr_t hex_length = strlen(hex_string); 1365 const intptr_t hex_length = strlen(hex_string);
1366 if (hex_length < 0) {
1367 FATAL("Fatal error in BigintOperations::FromHexCString: string too long");
1368 }
1345 intptr_t hex_i = hex_length - 1; 1369 intptr_t hex_i = hex_length - 1;
1346 for (intptr_t i = 0; i < bigint_length; i++) { 1370 for (intptr_t i = 0; i < bigint_length; i++) {
1347 Chunk digit = 0; 1371 Chunk digit = 0;
1348 int shift = 0; 1372 int shift = 0;
1349 for (int j = 0; j < kHexCharsPerDigit; j++) { 1373 for (int j = 0; j < kHexCharsPerDigit; j++) {
1350 // Reads a block of hexadecimal digits and stores it in 'digit'. 1374 // Reads a block of hexadecimal digits and stores it in 'digit'.
1351 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". 1375 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456".
1352 if (hex_i < 0) { 1376 if (hex_i < 0) {
1353 break; 1377 break;
1354 } 1378 }
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
1748 int BigintOperations::CountBits(Chunk digit) { 1772 int BigintOperations::CountBits(Chunk digit) {
1749 int result = 0; 1773 int result = 0;
1750 while (digit != 0) { 1774 while (digit != 0) {
1751 digit >>= 1; 1775 digit >>= 1;
1752 result++; 1776 result++;
1753 } 1777 }
1754 return result; 1778 return result;
1755 } 1779 }
1756 1780
1757 } // namespace dart 1781 } // 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