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

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: addressed comments 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) {
sra1 2013/09/17 05:32:31 I don't understand the purpose of this test. If s
Michael Lippautz (Google) 2013/09/17 17:10:35 Replaced with a comment saying why we don't need a
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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 252
241 253
242 const char* BigintOperations::ToHexCString(intptr_t length, 254 const char* BigintOperations::ToHexCString(intptr_t length,
243 bool is_negative, 255 bool is_negative,
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 // Conservative maximum chunk length.
263 const intptr_t kMaxChunkLen =
264 (kIntptrMax - 2 /* 0x */
265 - 1 /* trailing '\0' */
266 - 1 /* leading '-' */) / kHexCharsPerDigit;
267 const intptr_t chunk_length = length;
268 // Conservative check assuming leading bigint-digit also takes up
269 // kHexCharsPerDigit.
270 if (chunk_length > kMaxChunkLen) {
271 FATAL("Fatal error in BigintOperations::ToHexCString: string too long");
272 }
251 Chunk* chunk_data = reinterpret_cast<Chunk*>(data); 273 Chunk* chunk_data = reinterpret_cast<Chunk*>(data);
252 if (length == 0) { 274 if (length == 0) {
253 const char* zero = "0x0"; 275 const char* zero = "0x0";
254 const int kLength = strlen(zero); 276 const intptr_t kLength = strlen(zero);
255 char* result = reinterpret_cast<char*>(allocator(kLength + 1)); 277 char* result = reinterpret_cast<char*>(allocator(kLength + 1));
256 ASSERT(result != NULL); 278 ASSERT(result != NULL);
257 memmove(result, zero, kLength); 279 memmove(result, zero, kLength);
258 result[kLength] = '\0'; 280 result[kLength] = '\0';
259 return result; 281 return result;
260 } 282 }
261 ASSERT(chunk_data != NULL); 283 ASSERT(chunk_data != NULL);
262 284
263 // Compute the number of hex-digits that are needed to represent the 285 // Compute the number of hex-digits that are needed to represent the
264 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit 286 // 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( 345 const char* BigintOperations::ToDecimalCString(
324 const Bigint& bigint, uword (*allocator)(intptr_t size)) { 346 const Bigint& bigint, uword (*allocator)(intptr_t size)) {
325 // log10(2) ~= 0.30102999566398114. 347 // log10(2) ~= 0.30102999566398114.
326 const intptr_t kLog2Dividend = 30103; 348 const intptr_t kLog2Dividend = 30103;
327 const intptr_t kLog2Divisor = 100000; 349 const intptr_t kLog2Divisor = 100000;
328 // We remove a small constant for rounding imprecision, the \0 character and 350 // We remove a small constant for rounding imprecision, the \0 character and
329 // the negative sign. 351 // the negative sign.
330 const intptr_t kMaxAllowedDigitLength = 352 const intptr_t kMaxAllowedDigitLength =
331 (kIntptrMax - 10) / kLog2Dividend / kDigitBitSize * kLog2Divisor; 353 (kIntptrMax - 10) / kLog2Dividend / kDigitBitSize * kLog2Divisor;
332 354
333 intptr_t length = bigint.Length(); 355 const intptr_t length = bigint.Length();
334 Isolate* isolate = Isolate::Current(); 356 Isolate* isolate = Isolate::Current();
335 if (length >= kMaxAllowedDigitLength) { 357 if (length >= kMaxAllowedDigitLength) {
336 // Use the preallocated out of memory exception to avoid calling 358 // Use the preallocated out of memory exception to avoid calling
337 // into dart code or allocating any code. 359 // into dart code or allocating any code.
338 const Instance& exception = 360 const Instance& exception =
339 Instance::Handle(isolate->object_store()->out_of_memory()); 361 Instance::Handle(isolate->object_store()->out_of_memory());
340 Exceptions::Throw(exception); 362 Exceptions::Throw(exception);
341 UNREACHABLE(); 363 UNREACHABLE();
342 } 364 }
343 365
(...skipping 990 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 1356
1335 1357
1336 void BigintOperations::FromHexCString(const char* hex_string, 1358 void BigintOperations::FromHexCString(const char* hex_string,
1337 const Bigint& value) { 1359 const Bigint& value) {
1338 ASSERT(hex_string[0] != '-'); 1360 ASSERT(hex_string[0] != '-');
1339 intptr_t bigint_length = ComputeChunkLength(hex_string); 1361 intptr_t bigint_length = ComputeChunkLength(hex_string);
1340 // The bigint's least significant digit (lsd) is at position 0, whereas the 1362 // The bigint's least significant digit (lsd) is at position 0, whereas the
1341 // given string has it's lsd at the last position. 1363 // given string has it's lsd at the last position.
1342 // The hex_i index, pointing into the string, starts therefore at the end, 1364 // The hex_i index, pointing into the string, starts therefore at the end,
1343 // whereas the bigint-index (i) starts at 0. 1365 // whereas the bigint-index (i) starts at 0.
1344 intptr_t hex_length = strlen(hex_string); 1366 const intptr_t hex_length = strlen(hex_string);
1367 if (hex_length < 0) {
1368 FATAL("Fatal error in BigintOperations::FromHexCString: string too long");
1369 }
1345 intptr_t hex_i = hex_length - 1; 1370 intptr_t hex_i = hex_length - 1;
1346 for (intptr_t i = 0; i < bigint_length; i++) { 1371 for (intptr_t i = 0; i < bigint_length; i++) {
1347 Chunk digit = 0; 1372 Chunk digit = 0;
1348 int shift = 0; 1373 int shift = 0;
1349 for (int j = 0; j < kHexCharsPerDigit; j++) { 1374 for (int j = 0; j < kHexCharsPerDigit; j++) {
1350 // Reads a block of hexadecimal digits and stores it in 'digit'. 1375 // Reads a block of hexadecimal digits and stores it in 'digit'.
1351 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456". 1376 // Ex: "0123456" with kHexCharsPerDigit == 3, hex_i == 6, reads "456".
1352 if (hex_i < 0) { 1377 if (hex_i < 0) {
1353 break; 1378 break;
1354 } 1379 }
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
1748 int BigintOperations::CountBits(Chunk digit) { 1773 int BigintOperations::CountBits(Chunk digit) {
1749 int result = 0; 1774 int result = 0;
1750 while (digit != 0) { 1775 while (digit != 0) {
1751 digit >>= 1; 1776 digit >>= 1;
1752 result++; 1777 result++;
1753 } 1778 }
1754 return result; 1779 return result;
1755 } 1780 }
1756 1781
1757 } // namespace dart 1782 } // 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