blob: a50f50f9fa98825f89c0951b5cfa5c4d70f2b5ee [file] [log] [blame]
Adam Langley9ef99d52016-10-25 17:33:49 -07001/* Copyright (c) 2016, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
David Benjamine324de02017-05-20 09:48:45 -040015#include <gtest/gtest.h>
Adam Langley9ef99d52016-10-25 17:33:49 -070016
17#include <openssl/pool.h>
18
David Benjamin7cac8fa2021-10-20 17:17:57 -040019#include "internal.h"
David Benjamine324de02017-05-20 09:48:45 -040020#include "../test/test_util.h"
David Benjamin17cf2cb2016-12-13 01:07:13 -050021
David Benjamin5b33eff2018-09-22 16:52:48 -070022#if defined(OPENSSL_THREADS)
David Benjaminfc04cb22018-07-20 07:20:34 -040023#include <chrono>
24#include <thread>
25#endif
26
Adam Langley9ef99d52016-10-25 17:33:49 -070027
David Benjamine324de02017-05-20 09:48:45 -040028TEST(PoolTest, Unpooled) {
Adam Langley9ef99d52016-10-25 17:33:49 -070029 static const uint8_t kData[4] = {1, 2, 3, 4};
30 bssl::UniquePtr<CRYPTO_BUFFER> buf(
31 CRYPTO_BUFFER_new(kData, sizeof(kData), nullptr));
David Benjamine324de02017-05-20 09:48:45 -040032 ASSERT_TRUE(buf);
Adam Langley9ef99d52016-10-25 17:33:49 -070033
David Benjamine324de02017-05-20 09:48:45 -040034 EXPECT_EQ(Bytes(kData),
35 Bytes(CRYPTO_BUFFER_data(buf.get()), CRYPTO_BUFFER_len(buf.get())));
Adam Langley9ef99d52016-10-25 17:33:49 -070036
David Benjamine324de02017-05-20 09:48:45 -040037 // Test that reference-counting works properly.
David Benjamin2908dd12018-06-29 17:46:42 -040038 bssl::UniquePtr<CRYPTO_BUFFER> buf2 = bssl::UpRef(buf);
David Benjamin7cac8fa2021-10-20 17:17:57 -040039
40 bssl::UniquePtr<CRYPTO_BUFFER> buf_static(
41 CRYPTO_BUFFER_new_from_static_data_unsafe(kData, sizeof(kData), nullptr));
42 ASSERT_TRUE(buf_static);
43 EXPECT_EQ(kData, CRYPTO_BUFFER_data(buf_static.get()));
44 EXPECT_EQ(sizeof(kData), CRYPTO_BUFFER_len(buf_static.get()));
45
46 // Test that reference-counting works properly.
47 bssl::UniquePtr<CRYPTO_BUFFER> buf_static2 = bssl::UpRef(buf_static);
Adam Langley9ef99d52016-10-25 17:33:49 -070048}
49
David Benjamine324de02017-05-20 09:48:45 -040050TEST(PoolTest, Empty) {
Adam Langley9ef99d52016-10-25 17:33:49 -070051 bssl::UniquePtr<CRYPTO_BUFFER> buf(CRYPTO_BUFFER_new(nullptr, 0, nullptr));
David Benjamine324de02017-05-20 09:48:45 -040052 ASSERT_TRUE(buf);
Adam Langley9ef99d52016-10-25 17:33:49 -070053
David Benjamine324de02017-05-20 09:48:45 -040054 EXPECT_EQ(Bytes(""),
55 Bytes(CRYPTO_BUFFER_data(buf.get()), CRYPTO_BUFFER_len(buf.get())));
David Benjamin7cac8fa2021-10-20 17:17:57 -040056
57 bssl::UniquePtr<CRYPTO_BUFFER> buf_static(
58 CRYPTO_BUFFER_new_from_static_data_unsafe(nullptr, 0, nullptr));
59 ASSERT_TRUE(buf_static);
60
61 EXPECT_EQ(nullptr, CRYPTO_BUFFER_data(buf_static.get()));
62 EXPECT_EQ(0u, CRYPTO_BUFFER_len(buf_static.get()));
Adam Langley9ef99d52016-10-25 17:33:49 -070063}
64
David Benjamine324de02017-05-20 09:48:45 -040065TEST(PoolTest, Pooled) {
Adam Langley9ef99d52016-10-25 17:33:49 -070066 bssl::UniquePtr<CRYPTO_BUFFER_POOL> pool(CRYPTO_BUFFER_POOL_new());
David Benjamine324de02017-05-20 09:48:45 -040067 ASSERT_TRUE(pool);
Adam Langley9ef99d52016-10-25 17:33:49 -070068
David Benjamin7cac8fa2021-10-20 17:17:57 -040069 static const uint8_t kData1[4] = {1, 2, 3, 4};
Adam Langley9ef99d52016-10-25 17:33:49 -070070 bssl::UniquePtr<CRYPTO_BUFFER> buf(
David Benjamin7cac8fa2021-10-20 17:17:57 -040071 CRYPTO_BUFFER_new(kData1, sizeof(kData1), pool.get()));
David Benjamine324de02017-05-20 09:48:45 -040072 ASSERT_TRUE(buf);
David Benjamin7cac8fa2021-10-20 17:17:57 -040073 EXPECT_EQ(Bytes(kData1),
74 Bytes(CRYPTO_BUFFER_data(buf.get()), CRYPTO_BUFFER_len(buf.get())));
Adam Langley9ef99d52016-10-25 17:33:49 -070075
76 bssl::UniquePtr<CRYPTO_BUFFER> buf2(
David Benjamin7cac8fa2021-10-20 17:17:57 -040077 CRYPTO_BUFFER_new(kData1, sizeof(kData1), pool.get()));
David Benjamine324de02017-05-20 09:48:45 -040078 ASSERT_TRUE(buf2);
David Benjamin7cac8fa2021-10-20 17:17:57 -040079 EXPECT_EQ(Bytes(kData1), Bytes(CRYPTO_BUFFER_data(buf2.get()),
80 CRYPTO_BUFFER_len(buf2.get())));
Adam Langley9ef99d52016-10-25 17:33:49 -070081
David Benjamine324de02017-05-20 09:48:45 -040082 EXPECT_EQ(buf.get(), buf2.get()) << "CRYPTO_BUFFER_POOL did not dedup data.";
David Benjamin7cac8fa2021-10-20 17:17:57 -040083
84 // Different inputs do not get deduped.
85 static const uint8_t kData2[4] = {5, 6, 7, 8};
86 bssl::UniquePtr<CRYPTO_BUFFER> buf3(
87 CRYPTO_BUFFER_new(kData2, sizeof(kData2), pool.get()));
88 ASSERT_TRUE(buf3);
89 EXPECT_EQ(Bytes(kData2), Bytes(CRYPTO_BUFFER_data(buf3.get()),
90 CRYPTO_BUFFER_len(buf3.get())));
91 EXPECT_NE(buf.get(), buf3.get());
92
93 // When the last refcount on |buf3| is dropped, it is removed from the pool.
94 buf3 = nullptr;
95 EXPECT_EQ(1u, lh_CRYPTO_BUFFER_num_items(pool->bufs));
96
97 // Static buffers participate in pooling.
98 buf3.reset(CRYPTO_BUFFER_new_from_static_data_unsafe(kData2, sizeof(kData2),
99 pool.get()));
100 ASSERT_TRUE(buf3);
101 EXPECT_EQ(kData2, CRYPTO_BUFFER_data(buf3.get()));
102 EXPECT_EQ(sizeof(kData2), CRYPTO_BUFFER_len(buf3.get()));
103 EXPECT_NE(buf.get(), buf3.get());
104
105 bssl::UniquePtr<CRYPTO_BUFFER> buf4(
106 CRYPTO_BUFFER_new(kData2, sizeof(kData2), pool.get()));
107 EXPECT_EQ(buf4.get(), buf3.get());
108
109 bssl::UniquePtr<CRYPTO_BUFFER> buf5(CRYPTO_BUFFER_new_from_static_data_unsafe(
110 kData2, sizeof(kData2), pool.get()));
111 EXPECT_EQ(buf5.get(), buf3.get());
112
113 // When creating a static buffer, if there is already a non-static buffer, it
114 // replaces the old buffer.
115 bssl::UniquePtr<CRYPTO_BUFFER> buf6(CRYPTO_BUFFER_new_from_static_data_unsafe(
116 kData1, sizeof(kData1), pool.get()));
117 ASSERT_TRUE(buf6);
118 EXPECT_EQ(kData1, CRYPTO_BUFFER_data(buf6.get()));
119 EXPECT_EQ(sizeof(kData1), CRYPTO_BUFFER_len(buf6.get()));
120 EXPECT_NE(buf.get(), buf6.get());
121
122 // Subsequent lookups of |kData1| should return |buf6|.
123 bssl::UniquePtr<CRYPTO_BUFFER> buf7(
124 CRYPTO_BUFFER_new(kData1, sizeof(kData1), pool.get()));
125 EXPECT_EQ(buf7.get(), buf6.get());
Adam Langley9ef99d52016-10-25 17:33:49 -0700126}
David Benjaminfc04cb22018-07-20 07:20:34 -0400127
David Benjamin5b33eff2018-09-22 16:52:48 -0700128#if defined(OPENSSL_THREADS)
David Benjaminfc04cb22018-07-20 07:20:34 -0400129TEST(PoolTest, Threads) {
130 bssl::UniquePtr<CRYPTO_BUFFER_POOL> pool(CRYPTO_BUFFER_POOL_new());
131 ASSERT_TRUE(pool);
132
133 // Race threads making pooled |CRYPTO_BUFFER|s.
134 static const uint8_t kData[4] = {1, 2, 3, 4};
135 static const uint8_t kData2[3] = {4, 5, 6};
136 bssl::UniquePtr<CRYPTO_BUFFER> buf, buf2, buf3;
137 {
138 std::thread thread([&] {
139 buf.reset(CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
140 });
141 std::thread thread2([&] {
142 buf2.reset(CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
143 });
144 buf3.reset(CRYPTO_BUFFER_new(kData2, sizeof(kData2), pool.get()));
145 thread.join();
146 thread2.join();
147 }
148
149 ASSERT_TRUE(buf);
150 ASSERT_TRUE(buf2);
151 ASSERT_TRUE(buf3);
152 EXPECT_EQ(buf.get(), buf2.get()) << "CRYPTO_BUFFER_POOL did not dedup data.";
153 EXPECT_NE(buf.get(), buf3.get())
154 << "CRYPTO_BUFFER_POOL incorrectly deduped data.";
155 EXPECT_EQ(Bytes(kData),
156 Bytes(CRYPTO_BUFFER_data(buf.get()), CRYPTO_BUFFER_len(buf.get())));
157 EXPECT_EQ(Bytes(kData2), Bytes(CRYPTO_BUFFER_data(buf3.get()),
158 CRYPTO_BUFFER_len(buf3.get())));
159
160 // Reference-counting of |CRYPTO_BUFFER| interacts with pooling. Race an
161 // increment and free.
162 {
163 bssl::UniquePtr<CRYPTO_BUFFER> buf_ref;
164 std::thread thread([&] { buf_ref = bssl::UpRef(buf); });
165 buf2.reset();
166 thread.join();
167 }
168
169 // |buf|'s data is still valid.
170 EXPECT_EQ(Bytes(kData), Bytes(CRYPTO_BUFFER_data(buf.get()),
171 CRYPTO_BUFFER_len(buf.get())));
172
173 // Race a thread re-creating the |CRYPTO_BUFFER| with another thread freeing
174 // it. Do this twice with sleeps so ThreadSanitizer can observe two different
175 // interleavings. Ideally we would run this test under a tool that could
176 // search all interleavings.
177 {
178 std::thread thread([&] {
179 std::this_thread::sleep_for(std::chrono::milliseconds(1));
180 buf.reset();
181 });
182 buf2.reset(CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
183 thread.join();
184
185 ASSERT_TRUE(buf2);
186 EXPECT_EQ(Bytes(kData), Bytes(CRYPTO_BUFFER_data(buf2.get()),
187 CRYPTO_BUFFER_len(buf2.get())));
188 buf = std::move(buf2);
189 }
190
191 {
192 std::thread thread([&] { buf.reset(); });
193 std::this_thread::sleep_for(std::chrono::milliseconds(1));
194 buf2.reset(CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
195 thread.join();
196
197 ASSERT_TRUE(buf2);
198 EXPECT_EQ(Bytes(kData), Bytes(CRYPTO_BUFFER_data(buf2.get()),
199 CRYPTO_BUFFER_len(buf2.get())));
200 buf = std::move(buf2);
201 }
202
203 // Finally, race the frees.
204 {
205 buf2 = bssl::UpRef(buf);
206 std::thread thread([&] { buf.reset(); });
207 std::thread thread2([&] { buf3.reset(); });
208 buf2.reset();
209 thread.join();
210 thread2.join();
211 }
212}
213#endif