1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/win/variant_vector.h"
11
12 #include <optional>
13
14 #include "base/check_op.h"
15 #include "base/notreached.h"
16 #include "base/numerics/checked_math.h"
17 #include "base/process/memory.h"
18 #include "base/win/scoped_safearray.h"
19 #include "base/win/scoped_variant.h"
20
21 namespace base {
22 namespace win {
23
24 namespace {
25
26 // Lexicographical comparison between the contents of |vector| and |safearray|.
27 template <VARTYPE ElementVartype>
CompareAgainstSafearray(const std::vector<ScopedVariant> & vector,const ScopedSafearray & safearray,bool ignore_case)28 int CompareAgainstSafearray(const std::vector<ScopedVariant>& vector,
29 const ScopedSafearray& safearray,
30 bool ignore_case) {
31 std::optional<ScopedSafearray::LockScope<ElementVartype>> lock_scope =
32 safearray.CreateLockScope<ElementVartype>();
33 // If we fail to create a lock scope, then arbitrarily treat |this| as
34 // greater. This should only happen when the SAFEARRAY fails to be locked,
35 // so we cannot compare the contents of the SAFEARRAY.
36 if (!lock_scope)
37 return 1;
38
39 // Create a temporary VARIANT which does not own its contents, and is
40 // populated with values from the |lock_scope| so it can be compared against.
41 VARIANT non_owning_temp;
42 V_VT(&non_owning_temp) = ElementVartype;
43
44 auto vector_iter = vector.begin();
45 auto scope_iter = lock_scope->begin();
46 for (; vector_iter != vector.end() && scope_iter != lock_scope->end();
47 ++vector_iter, ++scope_iter) {
48 internal::VariantConverter<ElementVartype>::RawSet(&non_owning_temp,
49 *scope_iter);
50 int compare_result = vector_iter->Compare(non_owning_temp, ignore_case);
51 // If there is a difference in values, return the difference.
52 if (compare_result)
53 return compare_result;
54 }
55 // There are more elements in |vector|, so |vector| is
56 // greater than |safearray|.
57 if (vector_iter != vector.end())
58 return 1;
59 // There are more elements in |safearray|, so |vector| is
60 // less than |safearray|.
61 if (scope_iter != lock_scope->end())
62 return -1;
63 return 0;
64 }
65
66 } // namespace
67
68 VariantVector::VariantVector() = default;
69
VariantVector(VariantVector && other)70 VariantVector::VariantVector(VariantVector&& other)
71 : vartype_(std::exchange(other.vartype_, VT_EMPTY)),
72 vector_(std::move(other.vector_)) {}
73
operator =(VariantVector && other)74 VariantVector& VariantVector::operator=(VariantVector&& other) {
75 DCHECK_NE(this, &other);
76 vartype_ = std::exchange(other.vartype_, VT_EMPTY);
77 vector_ = std::move(other.vector_);
78 return *this;
79 }
80
~VariantVector()81 VariantVector::~VariantVector() {
82 Reset();
83 }
84
operator ==(const VariantVector & other) const85 bool VariantVector::operator==(const VariantVector& other) const {
86 return !Compare(other);
87 }
88
operator !=(const VariantVector & other) const89 bool VariantVector::operator!=(const VariantVector& other) const {
90 return !VariantVector::operator==(other);
91 }
92
Reset()93 void VariantVector::Reset() {
94 vector_.clear();
95 vartype_ = VT_EMPTY;
96 }
97
ReleaseAsScalarVariant()98 VARIANT VariantVector::ReleaseAsScalarVariant() {
99 ScopedVariant scoped_variant;
100
101 if (!Empty()) {
102 DCHECK_EQ(Size(), 1U);
103 scoped_variant = std::move(vector_[0]);
104 Reset();
105 }
106
107 return scoped_variant.Release();
108 }
109
ReleaseAsSafearrayVariant()110 VARIANT VariantVector::ReleaseAsSafearrayVariant() {
111 ScopedVariant scoped_variant;
112
113 switch (Type()) {
114 case VT_EMPTY:
115 break;
116 case VT_BOOL:
117 scoped_variant.Set(CreateAndPopulateSafearray<VT_BOOL>());
118 break;
119 case VT_I1:
120 scoped_variant.Set(CreateAndPopulateSafearray<VT_I1>());
121 break;
122 case VT_UI1:
123 scoped_variant.Set(CreateAndPopulateSafearray<VT_UI1>());
124 break;
125 case VT_I2:
126 scoped_variant.Set(CreateAndPopulateSafearray<VT_I2>());
127 break;
128 case VT_UI2:
129 scoped_variant.Set(CreateAndPopulateSafearray<VT_UI2>());
130 break;
131 case VT_I4:
132 scoped_variant.Set(CreateAndPopulateSafearray<VT_I4>());
133 break;
134 case VT_UI4:
135 scoped_variant.Set(CreateAndPopulateSafearray<VT_UI4>());
136 break;
137 case VT_I8:
138 scoped_variant.Set(CreateAndPopulateSafearray<VT_I8>());
139 break;
140 case VT_UI8:
141 scoped_variant.Set(CreateAndPopulateSafearray<VT_UI8>());
142 break;
143 case VT_R4:
144 scoped_variant.Set(CreateAndPopulateSafearray<VT_R4>());
145 break;
146 case VT_R8:
147 scoped_variant.Set(CreateAndPopulateSafearray<VT_R8>());
148 break;
149 case VT_DATE:
150 scoped_variant.Set(CreateAndPopulateSafearray<VT_DATE>());
151 break;
152 case VT_BSTR:
153 scoped_variant.Set(CreateAndPopulateSafearray<VT_BSTR>());
154 break;
155 case VT_DISPATCH:
156 scoped_variant.Set(CreateAndPopulateSafearray<VT_DISPATCH>());
157 break;
158 case VT_UNKNOWN:
159 scoped_variant.Set(CreateAndPopulateSafearray<VT_UNKNOWN>());
160 break;
161 // The default case shouldn't be reachable, but if we added support for more
162 // VARTYPEs to base::win::internal::VariantConverter<> and they were
163 // inserted into a VariantVector then it would be possible to reach the
164 // default case for those new types until implemented.
165 //
166 // Because the switch is against VARTYPE (unsigned short) and not VARENUM,
167 // removing the default case will not result in build warnings/errors if
168 // there are missing cases. It is important that this uses VARTYPE rather
169 // than VARENUM, because in the future we may want to support complex
170 // VARTYPES. For example a value within VT_TYPEMASK that's joined something
171 // outside the typemask like VT_ARRAY or VT_BYREF.
172 default:
173 NOTREACHED();
174 }
175
176 // CreateAndPopulateSafearray handles resetting |this| to VT_EMPTY because it
177 // transfers ownership of each element to the SAFEARRAY.
178 return scoped_variant.Release();
179 }
180
Compare(const VARIANT & other,bool ignore_case) const181 int VariantVector::Compare(const VARIANT& other, bool ignore_case) const {
182 // If the element variant types are different, compare against the types.
183 if (Type() != (V_VT(&other) & VT_TYPEMASK))
184 return (Type() < (V_VT(&other) & VT_TYPEMASK)) ? (-1) : 1;
185
186 // Both have an empty variant type so they are the same.
187 if (Type() == VT_EMPTY)
188 return 0;
189
190 int compare_result = 0;
191 if (V_ISARRAY(&other)) {
192 compare_result = Compare(V_ARRAY(&other), ignore_case);
193 } else {
194 compare_result = vector_[0].Compare(other, ignore_case);
195 // If the first element is equal to |other|, and |vector_|
196 // has more than one element, then |vector_| is greater.
197 if (!compare_result && Size() > 1)
198 compare_result = 1;
199 }
200 return compare_result;
201 }
202
Compare(const VariantVector & other,bool ignore_case) const203 int VariantVector::Compare(const VariantVector& other, bool ignore_case) const {
204 // If the element variant types are different, compare against the types.
205 if (Type() != other.Type())
206 return (Type() < other.Type()) ? (-1) : 1;
207
208 // Both have an empty variant type so they are the same.
209 if (Type() == VT_EMPTY)
210 return 0;
211
212 auto iter1 = vector_.begin();
213 auto iter2 = other.vector_.begin();
214 for (; (iter1 != vector_.end()) && (iter2 != other.vector_.end());
215 ++iter1, ++iter2) {
216 int compare_result = iter1->Compare(*iter2, ignore_case);
217 if (compare_result)
218 return compare_result;
219 }
220 // There are more elements in |this|, so |this| is greater than |other|.
221 if (iter1 != vector_.end())
222 return 1;
223 // There are more elements in |other|, so |this| is less than |other|.
224 if (iter2 != other.vector_.end())
225 return -1;
226 return 0;
227 }
228
Compare(SAFEARRAY * safearray,bool ignore_case) const229 int VariantVector::Compare(SAFEARRAY* safearray, bool ignore_case) const {
230 VARTYPE safearray_vartype;
231 // If we fail to get the element variant type for the SAFEARRAY, then
232 // arbitrarily treat |this| as greater.
233 if (FAILED(SafeArrayGetVartype(safearray, &safearray_vartype)))
234 return 1;
235
236 // If the element variant types are different, compare against the types.
237 if (Type() != safearray_vartype)
238 return (Type() < safearray_vartype) ? (-1) : 1;
239
240 ScopedSafearray scoped_safearray(safearray);
241 int compare_result = 0;
242 switch (Type()) {
243 case VT_BOOL:
244 compare_result = CompareAgainstSafearray<VT_BOOL>(
245 vector_, scoped_safearray, ignore_case);
246 break;
247 case VT_I1:
248 compare_result = CompareAgainstSafearray<VT_I1>(vector_, scoped_safearray,
249 ignore_case);
250 break;
251 case VT_UI1:
252 compare_result = CompareAgainstSafearray<VT_UI1>(
253 vector_, scoped_safearray, ignore_case);
254 break;
255 case VT_I2:
256 compare_result = CompareAgainstSafearray<VT_I2>(vector_, scoped_safearray,
257 ignore_case);
258 break;
259 case VT_UI2:
260 compare_result = CompareAgainstSafearray<VT_UI2>(
261 vector_, scoped_safearray, ignore_case);
262 break;
263 case VT_I4:
264 compare_result = CompareAgainstSafearray<VT_I4>(vector_, scoped_safearray,
265 ignore_case);
266 break;
267 case VT_UI4:
268 compare_result = CompareAgainstSafearray<VT_UI4>(
269 vector_, scoped_safearray, ignore_case);
270 break;
271 case VT_I8:
272 compare_result = CompareAgainstSafearray<VT_I8>(vector_, scoped_safearray,
273 ignore_case);
274 break;
275 case VT_UI8:
276 compare_result = CompareAgainstSafearray<VT_UI8>(
277 vector_, scoped_safearray, ignore_case);
278 break;
279 case VT_R4:
280 compare_result = CompareAgainstSafearray<VT_R4>(vector_, scoped_safearray,
281 ignore_case);
282 break;
283 case VT_R8:
284 compare_result = CompareAgainstSafearray<VT_R8>(vector_, scoped_safearray,
285 ignore_case);
286 break;
287 case VT_DATE:
288 compare_result = CompareAgainstSafearray<VT_DATE>(
289 vector_, scoped_safearray, ignore_case);
290 break;
291 case VT_BSTR:
292 compare_result = CompareAgainstSafearray<VT_BSTR>(
293 vector_, scoped_safearray, ignore_case);
294 break;
295 case VT_DISPATCH:
296 compare_result = CompareAgainstSafearray<VT_DISPATCH>(
297 vector_, scoped_safearray, ignore_case);
298 break;
299 case VT_UNKNOWN:
300 compare_result = CompareAgainstSafearray<VT_UNKNOWN>(
301 vector_, scoped_safearray, ignore_case);
302 break;
303 // The default case shouldn't be reachable, but if we added support for more
304 // VARTYPEs to base::win::internal::VariantConverter<> and they were
305 // inserted into a VariantVector then it would be possible to reach the
306 // default case for those new types until implemented.
307 //
308 // Because the switch is against VARTYPE (unsigned short) and not VARENUM,
309 // removing the default case will not result in build warnings/errors if
310 // there are missing cases. It is important that this uses VARTYPE rather
311 // than VARENUM, because in the future we may want to support complex
312 // VARTYPES. For example a value within VT_TYPEMASK that's joined something
313 // outside the typemask like VT_ARRAY or VT_BYREF.
314 default:
315 NOTREACHED();
316 }
317
318 scoped_safearray.Release();
319 return compare_result;
320 }
321
322 template <VARTYPE ElementVartype>
CreateAndPopulateSafearray()323 SAFEARRAY* VariantVector::CreateAndPopulateSafearray() {
324 DCHECK(!Empty());
325
326 ScopedSafearray scoped_safearray(
327 SafeArrayCreateVector(ElementVartype, 0, checked_cast<ULONG>(Size())));
328 if (!scoped_safearray.Get()) {
329 constexpr size_t kElementSize =
330 sizeof(typename internal::VariantConverter<ElementVartype>::Type);
331 base::TerminateBecauseOutOfMemory(sizeof(SAFEARRAY) +
332 (Size() * kElementSize));
333 }
334
335 std::optional<ScopedSafearray::LockScope<ElementVartype>> lock_scope =
336 scoped_safearray.CreateLockScope<ElementVartype>();
337 DCHECK(lock_scope);
338
339 for (size_t i = 0; i < Size(); ++i) {
340 VARIANT element = vector_[i].Release();
341 (*lock_scope)[i] =
342 internal::VariantConverter<ElementVartype>::RawGet(element);
343 }
344 Reset();
345
346 return scoped_safearray.Release();
347 }
348
349 } // namespace win
350 } // namespace base
351