1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cassert>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "usr/include/linux/netlink.h"
// NOTE: this exists as a regression test for crbug/357433195, where before the
// associated patch that added this, this would fail an assertion in
// extract_edits.py. However after fixing the assertion the code below doesn't
// get rewritten so original.cc == expected.cc, we're just asserting that the
// script doesn't fail on it.
namespace internal {
namespace {
using std::size_t;
// Expected rewrite:
// bool GetAddress(base::span<const struct nlmsghdr> header,
bool GetAddress(const struct nlmsghdr* header,
int header_length,
bool* really_deprecated) {
if (really_deprecated) {
*really_deprecated = false;
}
// Expected rewrite:
// const struct nlmsghdr* msg = reinterpret_cast<const struct nlmsghdr*>(
// UNSAFE_TODO(NLMSG_DATA(header.data())));
const struct nlmsghdr* msg =
reinterpret_cast<const struct nlmsghdr*>(NLMSG_DATA(header));
return true;
}
// Expected rewrite:
// template <typename T>
// T* SafelyCastNetlinkMsgData(base::span<const struct nlmsghdr> header,
// int length) {
template <typename T>
T* SafelyCastNetlinkMsgData(const struct nlmsghdr* header, int length) {
if (length <= 0 || static_cast<size_t>(length) < NLMSG_HDRLEN + sizeof(T)) {
return nullptr;
}
// Expected rewrite:
// return reinterpret_cast<const T*>(UNSAFE_TODO(NLMSG_DATA(header.data())));
return reinterpret_cast<const T*>(NLMSG_DATA(header));
}
} // namespace
} // namespace internal
// While fixing the above, the updating sometimes caused the rewrite to occur in
// the middle of the MACRO rather than inside the macro. This catches that case.
// Expected rewrite:
// dict.data()
#define CAST_FUN reinterpret_cast<std::size_t**>(dict);
#define CAST_FUN_2(x) reinterpret_cast<std::size_t**>(x);
// Expected rewrite:
// base::span<int*> dict
std::size_t check(int** dict, std::size_t N) {
// Expected rewrite:
// if (!dict.empty())
if (dict) {
for (int i = 0; i < N; ++i) {
int* ptr = dict[i];
// No expected rewrite
std::size_t** new_ptr = CAST_FUN;
// Expected rewrite:
// dict.data()
std::size_t** new_ptr_2 = CAST_FUN_2(dict);
if (**new_ptr > 10) {
return **new_ptr;
} else {
return **new_ptr_2;
}
}
}
return 10;
}
void checkMacroInFile() {
int array[2][1] = {{int(2)}, {int(3)}};
// Expected rewrite:
// base::span<int*>
int** front = reinterpret_cast<int**>(array);
check(front, 2);
}
// Finally after fixing the initial multiple neighbors there was a new one and
// this one catches that. Again this used to crash and showcases the situations
// where the assertion would fail.
struct Entry {
explicit Entry(std::string n) : name(n) {}
std::string name;
std::unordered_map<std::string, int> metrics;
};
class Recorder {
public:
// No expected rewrite.
bool EntryHasMetricNoRewrites(const Entry* entry, std::string metric_name) {
const int* val = nullptr;
if (entry->metrics.find(metric_name) != entry->metrics.end()) {
val = &entry->metrics.find(metric_name)->second;
}
return val != nullptr;
}
// No expected rewrite
bool EntryHasMetricRhsRewrite(const Entry* const* entries,
size_t len,
std::string metric_name) {
// Can't use entries like a buffer to avoid the rewrite.
const int* val = nullptr;
if (!entries || metric_name == "hello" || len > 3) {
return false;
}
return true;
}
// Expected rewrite:
// base::span<const Entry* const>
bool EntryHasMetricFullRewrite(const Entry* const* entries,
size_t len,
std::string metric_name) {
const int* val = nullptr;
for (size_t i = 0; i < len; ++i) {
const Entry* entry = entries[i];
if (entry->metrics.find(metric_name) != entry->metrics.end()) {
val = &entry->metrics.find(metric_name)->second;
}
}
return val != nullptr;
}
// No expected rewrite.
std::vector<const Entry*> GetEntriesByName(std::string name) const {
std::vector<const Entry*> result;
for (const auto& entry : entries_) {
if (entry->name == name) {
result.push_back(entry.get());
}
}
return result;
}
std::vector<std::unique_ptr<Entry>> entries_;
};
// No expected rewrite.
#define EXPECT_HAS_UKM_NO_REWRITE(name) \
assert(test_recorder_->EntryHasMetricNoRewrites(entry, name));
// Expected rewrite:
// test_entries.data()
#define EXPECT_HAS_UKM_RHS_REWRITE(name) \
assert(test_recorder_->EntryHasMetricRhsRewrite(test_entries, \
entries.size(), name));
// No expected rewrite.
#define EXPECT_HAS_UKM_FULL_REWRITE(name) \
assert(test_recorder_->EntryHasMetricFullRewrite(test_entries, \
entries.size(), name));
void MediaMetricsProviderTestTestUkm() {
Recorder recorder_;
Recorder* test_recorder_ = &recorder_;
test_recorder_->entries_.push_back(std::make_unique<Entry>("foo"));
// Test when neither lhs nor rhs gets rewritten this is the common case in the
// code base.
{
const auto& entries = test_recorder_->GetEntriesByName("foo");
assert(1u == entries.size());
// No expected rewrite.
for (const Entry* entry : entries) {
// This macro references |entry| and thus would need to rewrite it as
// .data() if we changed the for loop to a base::span (which we don't).
EXPECT_HAS_UKM_NO_REWRITE("bar");
}
}
{
const auto& entries = test_recorder_->GetEntriesByName("foo");
assert(1u == entries.size());
// No expected rewrite.
for (const Entry* entry : entries) {
// This macro references |entry| and thus would need to rewrite it as
// .data() if we changed the for loop to a base::span (which we don't).
EXPECT_HAS_UKM_NO_REWRITE("bar");
}
}
// Test how we handle macros when the function (lhs) doesn't get rewritten but
// the rhs does.
{
const auto& entries = test_recorder_->GetEntriesByName("foo");
// Expected rewrite:
// base::span<const Entry*> test_entries = entries;
const Entry* const* test_entries = entries.data();
const_cast<const Entry**>(test_entries)[0] = nullptr;
EXPECT_HAS_UKM_RHS_REWRITE("bar");
}
{
const auto& entries = test_recorder_->GetEntriesByName("foo");
// Expected rewrite:
// base::span<const Entry*> test_entries = entries;
const Entry* const* test_entries = entries.data();
const_cast<const Entry**>(test_entries)[0] = nullptr;
EXPECT_HAS_UKM_RHS_REWRITE("bar");
}
// Test how we handle macros when the function and the rhs gets rewritten.
{
const auto& entries = test_recorder_->GetEntriesByName("foo");
// Expected rewrite:
// base::span<const Entry* const> test_entries = entries;
const Entry* const* test_entries = entries.data();
EXPECT_HAS_UKM_FULL_REWRITE("bar");
}
{
const auto& entries = test_recorder_->GetEntriesByName("foo");
// Expected rewrite:
// base::span<const Entry* const> test_entries = entries;
const Entry* const* test_entries = entries.data();
EXPECT_HAS_UKM_FULL_REWRITE("bar");
}
}
|