this repo has no description
at trunk 626 lines 23 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <cstdarg> 3 4#include "cpython-data.h" 5#include "cpython-func.h" 6 7#include "api-handle.h" 8#include "bytearray-builtins.h" 9#include "bytes-builtins.h" 10#include "byteslike.h" 11#include "bytesobject-utils.h" 12#include "runtime.h" 13#include "utils.h" 14 15namespace py { 16 17PY_EXPORT PyTypeObject* PyBytesIter_Type_Ptr() { 18 Runtime* runtime = Thread::current()->runtime(); 19 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference( 20 runtime, runtime->typeAt(LayoutId::kBytesIterator))); 21} 22 23PY_EXPORT int PyBytes_CheckExact_Func(PyObject* obj) { 24 return ApiHandle::asObject(ApiHandle::fromPyObject(obj)).isBytes(); 25} 26 27PY_EXPORT int PyBytes_Check_Func(PyObject* obj) { 28 return Thread::current()->runtime()->isInstanceOfBytes( 29 ApiHandle::asObject(ApiHandle::fromPyObject(obj))); 30} 31 32char* bytesAsString(Runtime* runtime, ApiHandle* handle, const Bytes& bytes) { 33 if (void* cache = ApiHandle::cache(runtime, handle)) return static_cast<char*>(cache); 34 word len = bytes.length(); 35 auto cache = static_cast<byte*>(std::malloc(len + 1)); 36 bytes.copyTo(cache, len); 37 cache[len] = '\0'; 38 ApiHandle::setCache(runtime, handle, cache); 39 ApiHandle::setBorrowedNoImmediate(handle); 40 return reinterpret_cast<char*>(cache); 41} 42 43PY_EXPORT char* PyBytes_AsString(PyObject* pyobj) { 44 Thread* thread = Thread::current(); 45 HandleScope scope(thread); 46 ApiHandle* handle = ApiHandle::fromPyObject(pyobj); 47 Object obj(&scope, ApiHandle::asObject(handle)); 48 Runtime* runtime = thread->runtime(); 49 if (!runtime->isInstanceOfBytes(*obj)) { 50 thread->raiseBadArgument(); 51 return nullptr; 52 } 53 Bytes bytes(&scope, bytesUnderlying(*obj)); 54 return bytesAsString(runtime, handle, bytes); 55} 56 57PY_EXPORT int PyBytes_AsStringAndSize(PyObject* pybytes, char** buffer, 58 Py_ssize_t* length) { 59 Thread* thread = Thread::current(); 60 if (buffer == nullptr) { 61 thread->raiseBadInternalCall(); 62 return -1; 63 } 64 65 HandleScope scope(thread); 66 ApiHandle* handle = ApiHandle::fromPyObject(pybytes); 67 Object obj(&scope, ApiHandle::asObject(handle)); 68 Runtime* runtime = thread->runtime(); 69 if (!runtime->isInstanceOfBytes(*obj)) { 70 thread->raiseBadArgument(); 71 return -1; 72 } 73 74 Bytes bytes(&scope, bytesUnderlying(*obj)); 75 char* str = bytesAsString(runtime, handle, bytes); 76 77 if (length != nullptr) { 78 *length = bytes.length(); 79 } else if (std::strlen(str) != static_cast<size_t>(bytes.length())) { 80 thread->raiseWithFmt(LayoutId::kValueError, "embedded null byte"); 81 return -1; 82 } 83 *buffer = str; 84 return 0; 85} 86 87PY_EXPORT void PyBytes_Concat(PyObject** pyobj, PyObject* newpart) { 88 CHECK(pyobj != nullptr, "reference to bytes object must be non-null"); 89 if (*pyobj == nullptr) return; 90 if (newpart == nullptr) { 91 PyObject* tmp = *pyobj; 92 *pyobj = nullptr; 93 Py_DECREF(tmp); 94 return; 95 } 96 97 Thread* thread = Thread::current(); 98 HandleScope scope(thread); 99 ApiHandle* obj_handle = ApiHandle::fromPyObject(*pyobj); 100 Object obj(&scope, ApiHandle::asObject(obj_handle)); 101 Object newpart_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(newpart))); 102 Runtime* runtime = thread->runtime(); 103 if (!runtime->isInstanceOfBytes(*obj) || 104 !runtime->isInstanceOfBytes(*newpart_obj)) { 105 thread->raiseBadArgument(); 106 *pyobj = nullptr; 107 ApiHandle::decref(obj_handle); 108 return; 109 } 110 111 Bytes self(&scope, bytesUnderlying(*obj)); 112 Bytes other(&scope, bytesUnderlying(*newpart_obj)); 113 *pyobj = ApiHandle::newReference(runtime, 114 runtime->bytesConcat(thread, self, other)); 115 ApiHandle::decref(obj_handle); 116} 117 118PY_EXPORT void PyBytes_ConcatAndDel(PyObject** pyobj, PyObject* newpart) { 119 PyBytes_Concat(pyobj, newpart); 120 Py_XDECREF(newpart); 121} 122 123PY_EXPORT PyObject* PyBytes_DecodeEscape(const char* c_str, Py_ssize_t size, 124 const char* errors, Py_ssize_t unicode, 125 const char* recode_encoding) { 126 const char* first_invalid_escape; 127 PyObject* result = _PyBytes_DecodeEscape( 128 c_str, size, errors, unicode, recode_encoding, &first_invalid_escape); 129 if (result == nullptr) return nullptr; 130 if (first_invalid_escape != nullptr) { 131 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, 132 "invalid escape sequence '\\%c'", 133 static_cast<byte>(*first_invalid_escape)) < 0) { 134 Py_DECREF(result); 135 return nullptr; 136 } 137 } 138 return result; 139} 140 141PY_EXPORT PyObject* _PyBytes_DecodeEscape(const char* c_str, Py_ssize_t size, 142 const char* errors, 143 Py_ssize_t /* unicode */, 144 const char* recode_encoding, 145 const char** first_invalid_escape) { 146 DCHECK(c_str != nullptr, "c_str cannot be null"); 147 DCHECK(first_invalid_escape != nullptr, 148 "first_invalid_escape cannot be null"); 149 150 // So we can remember if we've seen an invalid escape char or not 151 *first_invalid_escape = nullptr; 152 153 Thread* thread = Thread::current(); 154 Runtime* runtime = thread->runtime(); 155 HandleScope scope(thread); 156 Object bytes(&scope, runtime->newBytesWithAll(View<byte>( 157 reinterpret_cast<const byte*>(c_str), size))); 158 Object recode_obj(&scope, recode_encoding == nullptr 159 ? Str::empty() 160 : runtime->newStrFromCStr(recode_encoding)); 161 Object errors_obj(&scope, Str::empty()); 162 Symbols* symbols = runtime->symbols(); 163 if (errors == nullptr || std::strcmp(errors, "strict") == 0) { 164 errors_obj = symbols->at(ID(strict)); 165 } else if (std::strcmp(errors, "ignore") == 0) { 166 errors_obj = symbols->at(ID(ignore)); 167 } else if (std::strcmp(errors, "replace") == 0) { 168 errors_obj = symbols->at(ID(replace)); 169 } 170 Object result_obj( 171 &scope, thread->invokeFunction3(ID(_codecs), ID(_escape_decode_stateful), 172 bytes, errors_obj, recode_obj)); 173 if (result_obj.isError()) { 174 if (result_obj.isErrorNotFound()) { 175 thread->raiseWithFmt(LayoutId::kSystemError, 176 "could not call _codecs.unicode_escape_decode"); 177 } 178 return nullptr; 179 } 180 Tuple result(&scope, *result_obj); 181 Int first_invalid_index(&scope, result.at(2)); 182 word invalid_index = first_invalid_index.asWord(); 183 if (invalid_index > -1) { 184 *first_invalid_escape = c_str + invalid_index; 185 } 186 return ApiHandle::newReference(runtime, result.at(0)); 187} 188 189PY_EXPORT PyObject* PyBytes_FromFormat(const char* format, ...) { 190 va_list vargs; 191 va_start(vargs, format); 192 PyObject* result = PyBytes_FromFormatV(format, vargs); 193 va_end(vargs); 194 return result; 195} 196 197static void writeBytes(Thread* thread, Runtime* runtime, 198 const Bytearray& writer, const char* buffer) { 199 View<byte> array(reinterpret_cast<const byte*>(buffer), std::strlen(buffer)); 200 runtime->bytearrayExtend(thread, writer, array); 201} 202 203static const char* writeArg(Thread* thread, Runtime* runtime, 204 const Bytearray& writer, const char* start, 205 va_list vargs) { 206 DCHECK(*start == '%', "index is not at a format specifier"); 207 const char* current = start + 1; 208 209 // ignore the width (ex: 10 in "%10s") 210 while (Py_ISDIGIT(*current)) current++; 211 212 // parse the precision (ex: 10 in "%.10s") 213 word precision = 0; 214 if (*current == '.') { 215 current++; 216 for (; Py_ISDIGIT(*current); current++) { 217 precision = precision * 10 + (*current - '0'); 218 } 219 } 220 221 // scan forward to the conversion specifier or the end of the string 222 while (*current != '\0' && *current != '%' && !Py_ISALPHA(*current)) { 223 current++; 224 } 225 226 // Handle the long flag ('l'), but only for %ld and %lu. 227 // Others can be added when necessary. 228 bool long_flag = false; 229 if (*current == 'l' && (current[1] == 'd' || current[1] == 'u')) { 230 long_flag = true; 231 current++; 232 } 233 234 // Handle the size_t flag ('z'), but only for %zd and %zu. 235 bool size_t_flag = false; 236 if (*current == 'z' && (current[1] == 'd' || current[1] == 'u')) { 237 size_t_flag = true; 238 ++current; 239 } 240 241 // Longest 64-bit formatted numbers: 242 // - "18446744073709551615\0" (21 bytes) 243 // - "-9223372036854775808\0" (21 bytes) 244 // Decimal takes the most space (it isn't enough for octal). 245 // Longest 64-bit pointer representation: "0xffffffffffffffff\0" (19 bytes). 246 char buffer[21]; 247 switch (*current) { 248 case 'c': { 249 int c = va_arg(vargs, int); 250 if (c < 0 || c > 255) { 251 thread->raiseWithFmt(LayoutId::kOverflowError, 252 "PyBytes_FromFormatV(): " 253 "%%c format expects an integer in [0,255]"); 254 return nullptr; 255 } 256 bytearrayAdd(thread, runtime, writer, static_cast<byte>(c)); 257 return current + 1; 258 } 259 case 'd': 260 if (long_flag) { 261 std::sprintf(buffer, "%ld", va_arg(vargs, long)); 262 } else if (size_t_flag) { 263 std::sprintf(buffer, "%" PY_FORMAT_SIZE_T "d", 264 va_arg(vargs, Py_ssize_t)); 265 } else { 266 std::sprintf(buffer, "%d", va_arg(vargs, int)); 267 } 268 writeBytes(thread, runtime, writer, buffer); 269 return current + 1; 270 case 'u': 271 if (long_flag) { 272 std::sprintf(buffer, "%lu", va_arg(vargs, unsigned long)); 273 } else if (size_t_flag) { 274 std::sprintf(buffer, "%" PY_FORMAT_SIZE_T "u", va_arg(vargs, size_t)); 275 } else { 276 std::sprintf(buffer, "%u", va_arg(vargs, unsigned int)); 277 } 278 writeBytes(thread, runtime, writer, buffer); 279 return current + 1; 280 case 'i': 281 std::sprintf(buffer, "%i", va_arg(vargs, int)); 282 writeBytes(thread, runtime, writer, buffer); 283 return current + 1; 284 case 'x': 285 std::sprintf(buffer, "%x", va_arg(vargs, int)); 286 writeBytes(thread, runtime, writer, buffer); 287 return current + 1; 288 case 's': { 289 const char* arg = va_arg(vargs, const char*); 290 word len = std::strlen(arg); 291 if (precision > 0 && len > precision) { 292 len = precision; 293 } 294 View<byte> array(reinterpret_cast<const byte*>(arg), len); 295 runtime->bytearrayExtend(thread, writer, array); 296 return current + 1; 297 } 298 case 'p': 299 std::sprintf(buffer, "%p", va_arg(vargs, void*)); 300 // %p is ill-defined, ensure leading 0x 301 if (buffer[1] == 'X') { 302 buffer[1] = 'x'; 303 } else if (buffer[1] != 'x') { 304 // missing 0x prefix, shift right and prepend 305 std::memmove(buffer + 2, buffer, std::strlen(buffer) + 1); 306 buffer[0] = '0'; 307 buffer[1] = 'x'; 308 } 309 writeBytes(thread, runtime, writer, buffer); 310 return current + 1; 311 case '%': 312 bytearrayAdd(thread, runtime, writer, '%'); 313 return current + 1; 314 default: 315 word len = static_cast<word>(std::strlen(start)); 316 View<byte> array(reinterpret_cast<const byte*>(start), len); 317 runtime->bytearrayExtend(thread, writer, array); 318 return start + len; 319 } 320} 321 322PY_EXPORT PyObject* PyBytes_FromFormatV(const char* format, va_list vargs) { 323 Thread* thread = Thread::current(); 324 Runtime* runtime = thread->runtime(); 325 HandleScope scope(thread); 326 Bytearray writer(&scope, runtime->newBytearray()); 327 runtime->bytearrayEnsureCapacity(thread, writer, std::strlen(format)); 328 while (*format) { 329 if (*format == '%') { 330 format = writeArg(thread, runtime, writer, format, vargs); 331 if (format == nullptr) return nullptr; 332 } else { 333 const char* next = format + 1; 334 while (*next && *next != '%') next++; 335 View<byte> view(reinterpret_cast<const byte*>(format), next - format); 336 runtime->bytearrayExtend(thread, writer, view); 337 format = next; 338 } 339 } 340 return ApiHandle::newReference(runtime, bytearrayAsBytes(thread, writer)); 341} 342 343PY_EXPORT PyObject* PyBytes_FromObject(PyObject* pyobj) { 344 Thread* thread = Thread::current(); 345 if (pyobj == nullptr) { 346 thread->raiseBadInternalCall(); 347 return nullptr; 348 } 349 350 HandleScope scope(thread); 351 ApiHandle* handle = ApiHandle::fromPyObject(pyobj); 352 Object obj(&scope, ApiHandle::asObject(handle)); 353 if (obj.isBytes()) { 354 ApiHandle::incref(handle); 355 return pyobj; 356 } 357 358 Object result(&scope, 359 thread->invokeFunction1(ID(builtins), ID(_bytes_new), obj)); 360 if (result.isError()) return nullptr; 361 return ApiHandle::newReference(thread->runtime(), *result); 362} 363 364PY_EXPORT PyObject* PyBytes_FromStringAndSize(const char* str, 365 Py_ssize_t size) { 366 Thread* thread = Thread::current(); 367 if (size < 0) { 368 thread->raiseWithFmt(LayoutId::kSystemError, 369 "Negative size passed to PyBytes_FromStringAndSize"); 370 return nullptr; 371 } 372 if (str == nullptr && size > 0) { 373 UNIMPLEMENTED("mutable, uninitialized bytes"); 374 } 375 Runtime* runtime = thread->runtime(); 376 return ApiHandle::newReference( 377 runtime, 378 runtime->newBytesWithAll({reinterpret_cast<const byte*>(str), size})); 379} 380 381PY_EXPORT PyObject* PyBytes_FromString(const char* str) { 382 Thread* thread = Thread::current(); 383 DCHECK(str, "nullptr argument"); 384 uword size = std::strlen(str); 385 if (size > SmallInt::kMaxValue) { 386 thread->raiseWithFmt(LayoutId::kOverflowError, "byte string is too large"); 387 return nullptr; 388 } 389 390 Runtime* runtime = thread->runtime(); 391 return ApiHandle::newReference( 392 runtime, runtime->newBytesWithAll({reinterpret_cast<const byte*>(str), 393 static_cast<word>(size)})); 394} 395 396PY_EXPORT PyObject* PyBytes_Repr(PyObject* pyobj, int smartquotes) { 397 Thread* thread = Thread::current(); 398 HandleScope scope(thread); 399 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pyobj))); 400 Runtime* runtime = thread->runtime(); 401 if (!runtime->isInstanceOfBytes(*obj)) { 402 thread->raiseBadArgument(); 403 return nullptr; 404 } 405 if (smartquotes) { 406 Byteslike self_byteslike(&scope, thread, *obj); 407 Object result(&scope, byteslikeReprSmartQuotes(thread, self_byteslike)); 408 if (result.isError()) return nullptr; 409 return ApiHandle::newReference(runtime, *result); 410 } 411 Bytes self(&scope, bytesUnderlying(*obj)); 412 Object result(&scope, bytesReprSingleQuotes(thread, self)); 413 if (result.isError()) return nullptr; 414 return ApiHandle::newReference(runtime, *result); 415} 416 417PY_EXPORT Py_ssize_t PyBytes_Size(PyObject* obj) { 418 Thread* thread = Thread::current(); 419 Runtime* runtime = thread->runtime(); 420 HandleScope scope(thread); 421 422 Object bytes_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj))); 423 424 if (!runtime->isInstanceOfBytes(*bytes_obj)) { 425 thread->raiseWithFmt(LayoutId::kTypeError, "PyBytes_Size expected bytes"); 426 return -1; 427 } 428 429 Bytes bytes(&scope, bytesUnderlying(*bytes_obj)); 430 return bytes.length(); 431} 432 433PY_EXPORT PyTypeObject* PyBytes_Type_Ptr() { 434 Runtime* runtime = Thread::current()->runtime(); 435 return reinterpret_cast<PyTypeObject*>( 436 ApiHandle::borrowedReference(runtime, runtime->typeAt(LayoutId::kBytes))); 437} 438 439PY_EXPORT PyObject* _PyBytes_Join(PyObject* sep, PyObject* iter) { 440 DCHECK(sep != nullptr && iter != nullptr, "null argument to _PyBytes_Join"); 441 Thread* thread = Thread::current(); 442 HandleScope scope(thread); 443 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(sep))); 444 Runtime* runtime = thread->runtime(); 445 DCHECK(runtime->isInstanceOfBytes(*obj), 446 "non-bytes argument to _PyBytes_Join"); 447 Object iterable(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(iter))); 448 Object result(&scope, thread->invokeMethodStatic2(LayoutId::kBytes, ID(join), 449 obj, iterable)); 450 return result.isError() ? nullptr : ApiHandle::newReference(runtime, *result); 451} 452 453PY_EXPORT int _PyBytes_Resize(PyObject** pyobj, Py_ssize_t newsize) { 454 DCHECK(pyobj != nullptr, "_PyBytes_Resize given null argument"); 455 DCHECK(*pyobj != nullptr, "_PyBytes_Resize given pointer to null"); 456 Thread* thread = Thread::current(); 457 ApiHandle* handle = ApiHandle::fromPyObject(*pyobj); 458 HandleScope scope(thread); 459 Object obj(&scope, ApiHandle::asObject(handle)); 460 Runtime* runtime = thread->runtime(); 461 if (newsize < 0 || !runtime->isInstanceOfBytes(*obj)) { 462 *pyobj = nullptr; 463 ApiHandle::decref(handle); 464 thread->raiseBadInternalCall(); 465 return -1; 466 } 467 Bytes bytes(&scope, bytesUnderlying(*obj)); 468 if (bytes.length() == newsize) return 0; 469 // we don't check here that Py_REFCNT(*pyobj) == 1 470 *pyobj = ApiHandle::newReference( 471 runtime, runtime->bytesCopyWithSize(thread, bytes, newsize)); 472 ApiHandle::decref(handle); 473 return 0; 474} 475 476// _PyBytesWriter API 477 478// Returns the beginning of the buffer currently used for writing. 479static byte* writerBufferStart(_PyBytesWriter* writer) { 480 return writer->use_heap_buffer ? writer->heap_buffer : writer->stack_buffer; 481} 482 483// Checks internal consistency of the writer struct. This function should only 484// be called in a DCHECK. Always returns true, but does checks of its own. 485static bool writerIsConsistent(_PyBytesWriter* writer) { 486 if (writer->use_heap_buffer) { 487 CHECK(writer->heap_buffer, "heap buffer is not allocated"); 488 } else { 489 CHECK(!writer->heap_buffer, "heap buffer was allocated too early"); 490 } 491 if (writer->use_bytearray) { 492 CHECK(!writer->overallocate, "bytearray has its own overallocation scheme"); 493 } 494 CHECK(0 <= writer->allocated, "allocated size must be non-negative"); 495 CHECK_BOUND(writer->min_size, writer->allocated); 496 497 const byte* start = writerBufferStart(writer); 498 const byte* end = start + writer->allocated; 499 CHECK(*end == 0, "byte string must be null-terminated"); 500 CHECK(writer->ptr, "current pointer cannot be null"); 501 CHECK(start <= writer->ptr, "pointer is before the start of the buffer"); 502 CHECK(writer->ptr <= end, "pointer is past the end of the buffer"); 503 return true; 504} 505 506// Allocates the writer and prepares it to write the specified number of bytes. 507// Uses the small stack buffer if possible. 508PY_EXPORT void* _PyBytesWriter_Alloc(_PyBytesWriter* writer, Py_ssize_t size) { 509 DCHECK(writer->min_size == 0 && writer->heap_buffer == nullptr, 510 "writer has already been allocated"); 511 writer->allocated = sizeof(writer->stack_buffer) - 1; 512 return _PyBytesWriter_Prepare(writer, writer->stack_buffer, size); 513} 514 515// Frees the writer's heap-allocated buffer. 516PY_EXPORT void _PyBytesWriter_Dealloc(_PyBytesWriter* writer) { 517 if (writer->heap_buffer) { 518 std::free(writer->heap_buffer); 519 writer->heap_buffer = nullptr; 520 } 521} 522 523// Converts the memory written to the writer into a bytes or bytearray object. 524// Assumes that str points to the end of the written data. Frees all memory 525// that was allocated by malloc. 526PY_EXPORT PyObject* _PyBytesWriter_Finish(_PyBytesWriter* writer, void* str) { 527 writer->ptr = reinterpret_cast<byte*>(str); 528 DCHECK(writerIsConsistent(writer), "invariants broken"); 529 Thread* thread = Thread::current(); 530 Runtime* runtime = thread->runtime(); 531 const byte* start = writerBufferStart(writer); 532 word size = writer->ptr - start; 533 if (size == 0) { 534 _PyBytesWriter_Dealloc(writer); 535 return ApiHandle::newReference(runtime, writer->use_bytearray 536 ? runtime->newBytearray() 537 : Bytes::empty()); 538 } 539 if (writer->use_bytearray) { 540 HandleScope scope(thread); 541 Bytearray result(&scope, runtime->newBytearray()); 542 runtime->bytearrayExtend(thread, result, View<byte>{start, size}); 543 return ApiHandle::newReference(runtime, *result); 544 } 545 PyObject* result = ApiHandle::newReference( 546 runtime, runtime->newBytesWithAll(View<byte>{start, size})); 547 _PyBytesWriter_Dealloc(writer); 548 return result; 549} 550 551// Initializes the _PyBytesWriter struct. 552PY_EXPORT void _PyBytesWriter_Init(_PyBytesWriter* writer) { 553 // Unlike CPython, zero out the stack buffer as well. 554 std::memset(writer, 0, sizeof(*writer)); 555} 556 557// Prepares the writer for the specified number of bytes. Reallocates if the new 558// size exceeds the currently allocated buffer. Returns the current pointer into 559// the buffer if the allocation succeeds. Returns null with a MemoryError set 560// if growing would exceed SmallInt::kMaxValue. 561PY_EXPORT void* _PyBytesWriter_Prepare(_PyBytesWriter* writer, void* str, 562 Py_ssize_t growth) { 563 writer->ptr = reinterpret_cast<byte*>(str); 564 DCHECK(writerIsConsistent(writer), "invariants broken"); 565 if (growth == 0) return str; 566 DCHECK(growth > 0, "size must be non-negative"); 567 if (growth > SmallInt::kMaxValue - writer->min_size) { 568 PyErr_NoMemory(); 569 _PyBytesWriter_Dealloc(writer); 570 return nullptr; 571 } 572 word new_min_size = writer->min_size + growth; 573 if (new_min_size > writer->allocated) { 574 str = _PyBytesWriter_Resize(writer, str, new_min_size); 575 } 576 writer->min_size = new_min_size; 577 writer->ptr = reinterpret_cast<byte*>(str); 578 return str; 579} 580 581static const word kOverallocateFactor = 4; 582 583// Grows the writer to at least the provided size. Overallocates by 1/4 if 584// writer->overallocate or writer->use_bytearray is set. 585PY_EXPORT void* _PyBytesWriter_Resize(_PyBytesWriter* writer, void* str, 586 Py_ssize_t new_size) { 587 writer->ptr = reinterpret_cast<byte*>(str); 588 DCHECK(writerIsConsistent(writer), "invariants broken"); 589 DCHECK(writer->allocated < new_size, "resize should only be called to grow"); 590 DCHECK_BOUND(new_size, SmallInt::kMaxValue); 591 if ((writer->overallocate || writer->use_bytearray) && 592 new_size <= SmallInt::kMaxValue - new_size / kOverallocateFactor) { 593 new_size += new_size / kOverallocateFactor; 594 } 595 596 word len; 597 byte* new_buffer = reinterpret_cast<byte*>(std::malloc(new_size + 1)); 598 if (writer->use_heap_buffer) { 599 len = writer->ptr - writer->heap_buffer; 600 std::memcpy(new_buffer, writer->heap_buffer, len); 601 std::free(writer->heap_buffer); 602 } else { 603 len = writer->ptr - writer->stack_buffer; 604 std::memcpy(new_buffer, writer->stack_buffer, len); 605 } 606 new_buffer[new_size] = '\0'; 607 608 writer->allocated = new_size; 609 writer->heap_buffer = new_buffer; 610 writer->ptr = new_buffer + len; 611 writer->use_heap_buffer = true; 612 return writer->ptr; 613} 614 615// Writes the specified bytes. Grows writer.min_size by the specified length. 616// Do not use to write into memory already allocated by _PyBytesWriter_Prepare. 617PY_EXPORT void* _PyBytesWriter_WriteBytes(_PyBytesWriter* writer, void* str, 618 const void* bytes, Py_ssize_t len) { 619 str = _PyBytesWriter_Prepare(writer, str, len); 620 if (str == nullptr) return nullptr; 621 std::memcpy(str, bytes, len); 622 writer->ptr = reinterpret_cast<byte*>(str) + len; 623 return writer->ptr; 624} 625 626} // namespace py