this repo has no description
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