1#ifndef SIMDJSON_INLINE_PADDED_STRING_H
2#define SIMDJSON_INLINE_PADDED_STRING_H
3
4#include "simdjson/portability.h"
5#include "simdjson/common_defs.h" // for SIMDJSON_PADDING
6
7#include <climits>
8#include <cstring>
9#include <memory>
10#include <string>
11
12namespace simdjson {
13namespace internal {
14
15// The allocate_padded_buffer function is a low-level function to allocate memory
16// with padding so we can read past the "length" bytes safely. It is used by
17// the padded_string class automatically. It returns nullptr in case
18// of error: the caller should check for a null pointer.
19// The length parameter is the maximum size in bytes of the string.
20// The caller is responsible to free the memory (e.g., delete[] (...)).
21inline char *allocate_padded_buffer(size_t length) noexcept {
22 const size_t totalpaddedlength = length + SIMDJSON_PADDING;
23 if(totalpaddedlength<length) {
24 // overflow
25 return nullptr;
26 }
27#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
28 // avoid getting out of memory
29 if (totalpaddedlength>(1UL<<20)) {
30 return nullptr;
31 }
32#endif
33
34 char *padded_buffer = new (std::nothrow) char[totalpaddedlength];
35 if (padded_buffer == nullptr) {
36 return nullptr;
37 }
38 // We write zeroes in the padded region to avoid having uninitized
39 // garbage. If nothing else, garbage getting read might trigger a
40 // warning in a memory checking.
41 std::memset(s: padded_buffer + length, c: 0, n: totalpaddedlength - length);
42 return padded_buffer;
43} // allocate_padded_buffer()
44
45} // namespace internal
46
47
48inline padded_string::padded_string() noexcept = default;
49inline padded_string::padded_string(size_t length) noexcept
50 : viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
51}
52inline padded_string::padded_string(const char *data, size_t length) noexcept
53 : viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
54 if ((data != nullptr) && (data_ptr != nullptr)) {
55 std::memcpy(dest: data_ptr, src: data, n: length);
56 }
57}
58// note: do not pass std::string arguments by value
59inline padded_string::padded_string(const std::string & str_ ) noexcept
60 : viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(length: str_.size())) {
61 if (data_ptr != nullptr) {
62 std::memcpy(dest: data_ptr, src: str_.data(), n: str_.size());
63 }
64}
65// note: do pass std::string_view arguments by value
66inline padded_string::padded_string(std::string_view sv_) noexcept
67 : viable_size(sv_.size()), data_ptr(internal::allocate_padded_buffer(length: sv_.size())) {
68 if(simdjson_unlikely(!data_ptr)) {
69 //allocation failed or zero size
70 viable_size=0;
71 return;
72 }
73 if (sv_.size()) {
74 std::memcpy(dest: data_ptr, src: sv_.data(), n: sv_.size());
75 }
76}
77inline padded_string::padded_string(padded_string &&o) noexcept
78 : viable_size(o.viable_size), data_ptr(o.data_ptr) {
79 o.data_ptr = nullptr; // we take ownership
80}
81
82inline padded_string &padded_string::operator=(padded_string &&o) noexcept {
83 delete[] data_ptr;
84 data_ptr = o.data_ptr;
85 viable_size = o.viable_size;
86 o.data_ptr = nullptr; // we take ownership
87 o.viable_size = 0;
88 return *this;
89}
90
91inline void padded_string::swap(padded_string &o) noexcept {
92 size_t tmp_viable_size = viable_size;
93 char *tmp_data_ptr = data_ptr;
94 viable_size = o.viable_size;
95 data_ptr = o.data_ptr;
96 o.data_ptr = tmp_data_ptr;
97 o.viable_size = tmp_viable_size;
98}
99
100inline padded_string::~padded_string() noexcept {
101 delete[] data_ptr;
102}
103
104inline size_t padded_string::size() const noexcept { return viable_size; }
105
106inline size_t padded_string::length() const noexcept { return viable_size; }
107
108inline const char *padded_string::data() const noexcept { return data_ptr; }
109
110inline char *padded_string::data() noexcept { return data_ptr; }
111
112inline padded_string::operator std::string_view() const { return std::string_view(data(), length()); }
113
114inline padded_string::operator padded_string_view() const noexcept {
115 return padded_string_view(data(), length(), length() + SIMDJSON_PADDING);
116}
117
118inline simdjson_result<padded_string> padded_string::load(std::string_view filename) noexcept {
119 // Open the file
120 SIMDJSON_PUSH_DISABLE_WARNINGS
121 SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
122 std::FILE *fp = std::fopen(filename: filename.data(), modes: "rb");
123 SIMDJSON_POP_DISABLE_WARNINGS
124
125 if (fp == nullptr) {
126 return IO_ERROR;
127 }
128
129 // Get the file size
130 int ret;
131#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
132 ret = _fseeki64(fp, 0, SEEK_END);
133#else
134 ret = std::fseek(stream: fp, off: 0, SEEK_END);
135#endif // _WIN64
136 if(ret < 0) {
137 std::fclose(stream: fp);
138 return IO_ERROR;
139 }
140#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
141 __int64 llen = _ftelli64(fp);
142 if(llen == -1L) {
143 std::fclose(fp);
144 return IO_ERROR;
145 }
146#else
147 long llen = std::ftell(stream: fp);
148 if((llen < 0) || (llen == LONG_MAX)) {
149 std::fclose(stream: fp);
150 return IO_ERROR;
151 }
152#endif
153
154 // Allocate the padded_string
155 size_t len = static_cast<size_t>(llen);
156 padded_string s(len);
157 if (s.data() == nullptr) {
158 std::fclose(stream: fp);
159 return MEMALLOC;
160 }
161
162 // Read the padded_string
163 std::rewind(stream: fp);
164 size_t bytes_read = std::fread(ptr: s.data(), size: 1, n: len, stream: fp);
165 if (std::fclose(stream: fp) != 0 || bytes_read != len) {
166 return IO_ERROR;
167 }
168
169 return s;
170}
171
172} // namespace simdjson
173
174#endif // SIMDJSON_INLINE_PADDED_STRING_H
175