зеркало из https://github.com/mozilla/gecko-dev.git
485 строки
16 KiB
C++
485 строки
16 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "gtest/gtest.h"
|
|
#include <math.h>
|
|
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/Range.h"
|
|
#include "mozilla/Tainting.h"
|
|
#include "nsTHashtable.h"
|
|
#include "nsHashKeys.h"
|
|
#include "nsTArray.h"
|
|
#include <array>
|
|
#include <deque>
|
|
#include <forward_list>
|
|
#include <list>
|
|
#include <map>
|
|
#include <set>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
using mozilla::Tainted;
|
|
|
|
#define EXPECTED_INT 10
|
|
#define EXPECTED_CHAR 'z'
|
|
|
|
static bool externalFunction(int arg) { return arg > 2; }
|
|
|
|
// ==================================================================
|
|
// MOZ_VALIDATE_AND_GET =============================================
|
|
TEST(Tainting, moz_validate_and_get)
|
|
{
|
|
int bar;
|
|
int comparisonVariable = 20;
|
|
Tainted<int> foo = Tainted<int>(EXPECTED_INT);
|
|
|
|
bar = MOZ_VALIDATE_AND_GET(foo, foo < 20);
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// This test is for comparison to an external variable, testing the
|
|
// default capture mode of the lambda used inside the macro.
|
|
bar = MOZ_VALIDATE_AND_GET(foo, foo < comparisonVariable);
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
bar = MOZ_VALIDATE_AND_GET(
|
|
foo, foo < 20,
|
|
"foo must be less than 20 because higher values represent decibel"
|
|
"levels greater than a a jet engine inside your ear.");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// Test an external variable with a comment.
|
|
bar = MOZ_VALIDATE_AND_GET(foo, foo < comparisonVariable, "Test comment");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// Test an external function with a comment.
|
|
bar = MOZ_VALIDATE_AND_GET(foo, externalFunction(foo), "Test comment");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// Lambda Tests
|
|
bar =
|
|
MOZ_VALIDATE_AND_GET(foo, ([&foo]() { return externalFunction(foo); }()));
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// This test is for the lambda variant with a supplied assertion
|
|
// string.
|
|
bar =
|
|
MOZ_VALIDATE_AND_GET(foo, ([&foo]() { return externalFunction(foo); }()),
|
|
"This tests a comment");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// This test is for the lambda variant with a captured variable
|
|
bar = MOZ_VALIDATE_AND_GET(foo, ([&foo, &comparisonVariable] {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult ||
|
|
comparisonVariable < 4;
|
|
}()),
|
|
"This tests a comment");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// This test is for the lambda variant with full capture mode
|
|
bar = MOZ_VALIDATE_AND_GET(foo, ([&] {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult ||
|
|
comparisonVariable < 4;
|
|
}()),
|
|
"This tests a comment");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// External lambdas
|
|
auto lambda1 = [](int foo) { return externalFunction(foo); };
|
|
|
|
auto lambda2 = [&](int foo) {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
};
|
|
|
|
// Test with an explicit capture
|
|
auto lambda3 = [&comparisonVariable](int foo) {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
};
|
|
|
|
bar = MOZ_VALIDATE_AND_GET(foo, lambda1(foo));
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// Test with a comment
|
|
bar = MOZ_VALIDATE_AND_GET(foo, lambda1(foo), "Test comment.");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// Test with a default capture mode
|
|
bar = MOZ_VALIDATE_AND_GET(foo, lambda2(foo), "Test comment.");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
bar = MOZ_VALIDATE_AND_GET(foo, lambda3(foo), "Test comment.");
|
|
ASSERT_EQ(bar, EXPECTED_INT);
|
|
|
|
// We can't test MOZ_VALIDATE_AND_GET failing, because that triggers
|
|
// a release assert.
|
|
}
|
|
|
|
// ==================================================================
|
|
// MOZ_IS_VALID =====================================================
|
|
TEST(Tainting, moz_is_valid)
|
|
{
|
|
int comparisonVariable = 20;
|
|
Tainted<int> foo = Tainted<int>(EXPECTED_INT);
|
|
|
|
ASSERT_TRUE(MOZ_IS_VALID(foo, foo < 20));
|
|
|
|
ASSERT_FALSE(MOZ_IS_VALID(foo, foo > 20));
|
|
|
|
ASSERT_TRUE(MOZ_IS_VALID(foo, foo < comparisonVariable));
|
|
|
|
ASSERT_TRUE(
|
|
MOZ_IS_VALID(foo, ([&foo]() { return externalFunction(foo); }())));
|
|
|
|
ASSERT_TRUE(MOZ_IS_VALID(foo, ([&foo, &comparisonVariable]() {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult ||
|
|
comparisonVariable < 4;
|
|
}())));
|
|
|
|
// External lambdas
|
|
auto lambda1 = [](int foo) { return externalFunction(foo); };
|
|
|
|
auto lambda2 = [&](int foo) {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
};
|
|
|
|
// Test with an explicit capture
|
|
auto lambda3 = [&comparisonVariable](int foo) {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
};
|
|
|
|
ASSERT_TRUE(MOZ_IS_VALID(foo, lambda1(foo)));
|
|
|
|
ASSERT_TRUE(MOZ_IS_VALID(foo, lambda2(foo)));
|
|
|
|
ASSERT_TRUE(MOZ_IS_VALID(foo, lambda3(foo)));
|
|
}
|
|
|
|
// ==================================================================
|
|
// MOZ_VALIDATE_OR ==================================================
|
|
TEST(Tainting, moz_validate_or)
|
|
{
|
|
int result;
|
|
int comparisonVariable = 20;
|
|
Tainted<int> foo = Tainted<int>(EXPECTED_INT);
|
|
|
|
result = MOZ_VALIDATE_OR(foo, foo < 20, 100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
result = MOZ_VALIDATE_OR(foo, foo > 20, 100);
|
|
ASSERT_EQ(result, 100);
|
|
|
|
result = MOZ_VALIDATE_OR(foo, foo < comparisonVariable, 100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
// External lambdas
|
|
auto lambda1 = [](int foo) { return externalFunction(foo); };
|
|
|
|
auto lambda2 = [&](int foo) {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
};
|
|
|
|
// Test with an explicit capture
|
|
auto lambda3 = [&comparisonVariable](int foo) {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
};
|
|
|
|
result = MOZ_VALIDATE_OR(foo, lambda1(foo), 100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
result = MOZ_VALIDATE_OR(foo, lambda2(foo), 100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
result = MOZ_VALIDATE_OR(foo, lambda3(foo), 100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
result =
|
|
MOZ_VALIDATE_OR(foo, ([&foo]() { return externalFunction(foo); }()), 100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
// This test is for the lambda variant with a supplied assertion
|
|
// string.
|
|
result =
|
|
MOZ_VALIDATE_OR(foo, ([&foo] { return externalFunction(foo); }()), 100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
// This test is for the lambda variant with a captured variable
|
|
result =
|
|
MOZ_VALIDATE_OR(foo, ([&foo, &comparisonVariable] {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
}()),
|
|
100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
|
|
// This test is for the lambda variant with full capture mode
|
|
result =
|
|
MOZ_VALIDATE_OR(foo, ([&] {
|
|
bool intermediateResult = externalFunction(foo);
|
|
return intermediateResult || comparisonVariable < 4;
|
|
}()),
|
|
100);
|
|
ASSERT_EQ(result, EXPECTED_INT);
|
|
}
|
|
|
|
// ==================================================================
|
|
// MOZ_FIND_AND_VALIDATE ============================================
|
|
TEST(Tainting, moz_find_and_validate)
|
|
{
|
|
Tainted<int> foo = Tainted<int>(EXPECTED_INT);
|
|
Tainted<char> baz = Tainted<char>(EXPECTED_CHAR);
|
|
|
|
//-------------------------------
|
|
const mozilla::Array<int, 6> mozarrayWithFoo(0, 5, EXPECTED_INT, 15, 20, 25);
|
|
const mozilla::Array<int, 5> mozarrayWithoutFoo(0, 5, 15, 20, 25);
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, mozarrayWithFoo) ==
|
|
mozarrayWithFoo[2]);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo,
|
|
mozarrayWithoutFoo) == nullptr);
|
|
|
|
//-------------------------------
|
|
class TestClass {
|
|
public:
|
|
int a;
|
|
int b;
|
|
|
|
TestClass(int a, int b) {
|
|
this->a = a;
|
|
this->b = b;
|
|
}
|
|
|
|
bool operator==(const TestClass& other) const {
|
|
return this->a == other.a && this->b == other.b;
|
|
}
|
|
};
|
|
|
|
const mozilla::Array<TestClass, 5> mozarrayOfClassesWithFoo(
|
|
TestClass(0, 1), TestClass(2, 3), TestClass(EXPECTED_INT, EXPECTED_INT),
|
|
TestClass(4, 5), TestClass(6, 7));
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(
|
|
foo, foo == list_item.a && foo == list_item.b,
|
|
mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]);
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(
|
|
foo, (foo == list_item.a && foo == list_item.b),
|
|
mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]);
|
|
|
|
ASSERT_TRUE(
|
|
*MOZ_FIND_AND_VALIDATE(
|
|
foo,
|
|
(foo == list_item.a && foo == list_item.b && externalFunction(foo)),
|
|
mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]);
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(
|
|
foo, ([](int tainted_val, TestClass list_item) {
|
|
return tainted_val == list_item.a &&
|
|
tainted_val == list_item.b;
|
|
}(foo, list_item)),
|
|
mozarrayOfClassesWithFoo) == mozarrayOfClassesWithFoo[2]);
|
|
|
|
auto lambda4 = [](int tainted_val, TestClass list_item) {
|
|
return tainted_val == list_item.a && tainted_val == list_item.b;
|
|
};
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, lambda4(foo, list_item),
|
|
mozarrayOfClassesWithFoo) ==
|
|
mozarrayOfClassesWithFoo[2]);
|
|
|
|
//-------------------------------
|
|
const char m[] = "m";
|
|
const char o[] = "o";
|
|
const char z[] = {EXPECTED_CHAR, '\0'};
|
|
const char l[] = "l";
|
|
const char a[] = "a";
|
|
|
|
nsTHashtable<nsCharPtrHashKey> hashtableWithBaz;
|
|
hashtableWithBaz.PutEntry(m);
|
|
hashtableWithBaz.PutEntry(o);
|
|
hashtableWithBaz.PutEntry(z);
|
|
hashtableWithBaz.PutEntry(l);
|
|
hashtableWithBaz.PutEntry(a);
|
|
nsTHashtable<nsCharPtrHashKey> hashtableWithoutBaz;
|
|
hashtableWithoutBaz.PutEntry(m);
|
|
hashtableWithoutBaz.PutEntry(o);
|
|
hashtableWithoutBaz.PutEntry(l);
|
|
hashtableWithoutBaz.PutEntry(a);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(baz, *list_item.GetKey() == baz,
|
|
hashtableWithBaz) ==
|
|
hashtableWithBaz.GetEntry(z));
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(baz, *list_item.GetKey() == baz,
|
|
hashtableWithoutBaz) == nullptr);
|
|
|
|
//-------------------------------
|
|
const nsTArray<int> nsTArrayWithFoo = {0, 5, EXPECTED_INT, 15, 20, 25};
|
|
const nsTArray<int> nsTArrayWithoutFoo = {0, 5, 15, 20, 25};
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, nsTArrayWithFoo) ==
|
|
nsTArrayWithFoo[2]);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo,
|
|
nsTArrayWithoutFoo) == nullptr);
|
|
|
|
//-------------------------------
|
|
const std::array<int, 6> arrayWithFoo{0, 5, EXPECTED_INT, 15, 20, 25};
|
|
const std::array<int, 5> arrayWithoutFoo{0, 5, 15, 20, 25};
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, arrayWithFoo) ==
|
|
arrayWithFoo[2]);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, arrayWithoutFoo) ==
|
|
nullptr);
|
|
|
|
//-------------------------------
|
|
const std::deque<int> dequeWithFoo{0, 5, EXPECTED_INT, 15, 20, 25};
|
|
const std::deque<int> dequeWithoutFoo{0, 5, 15, 20, 25};
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, dequeWithFoo) ==
|
|
dequeWithFoo[2]);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, dequeWithoutFoo) ==
|
|
nullptr);
|
|
|
|
//-------------------------------
|
|
const std::forward_list<int> forwardWithFoo{0, 5, EXPECTED_INT, 15, 20, 25};
|
|
const std::forward_list<int> forwardWithoutFoo{0, 5, 15, 20, 25};
|
|
|
|
auto forwardListIt = forwardWithFoo.begin();
|
|
std::advance(forwardListIt, 2);
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, forwardWithFoo) ==
|
|
*forwardListIt);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, forwardWithoutFoo) ==
|
|
nullptr);
|
|
|
|
//-------------------------------
|
|
const std::list<int> listWithFoo{0, 5, EXPECTED_INT, 15, 20, 25};
|
|
const std::list<int> listWithoutFoo{0, 5, 15, 20, 25};
|
|
|
|
auto listIt = listWithFoo.begin();
|
|
std::advance(listIt, 2);
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, listWithFoo) ==
|
|
*listIt);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, listWithoutFoo) ==
|
|
nullptr);
|
|
|
|
//-------------------------------
|
|
const std::map<std::string, int> mapWithFoo{{
|
|
{"zero", 0},
|
|
{"five", 5},
|
|
{"ten", EXPECTED_INT},
|
|
{"fifteen", 15},
|
|
{"twenty", 20},
|
|
{"twenty-five", 25},
|
|
}};
|
|
const std::map<std::string, int> mapWithoutFoo{{
|
|
{"zero", 0},
|
|
{"five", 5},
|
|
{"fifteen", 15},
|
|
{"twenty", 20},
|
|
{"twenty-five", 25},
|
|
}};
|
|
|
|
const auto map_it = mapWithFoo.find("ten");
|
|
|
|
ASSERT_TRUE(
|
|
MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo, mapWithFoo)->second ==
|
|
map_it->second);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo,
|
|
mapWithoutFoo) == nullptr);
|
|
|
|
//-------------------------------
|
|
const std::set<int> setWithFoo{0, 5, EXPECTED_INT, 15, 20, 25};
|
|
const std::set<int> setWithoutFoo{0, 5, 15, 20, 25};
|
|
|
|
auto setIt = setWithFoo.find(EXPECTED_INT);
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, setWithFoo) ==
|
|
*setIt);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, setWithoutFoo) ==
|
|
nullptr);
|
|
|
|
//-------------------------------
|
|
const std::unordered_map<std::string, int> unordermapWithFoo = {
|
|
{"zero", 0}, {"five", 5}, {"ten", EXPECTED_INT},
|
|
{"fifteen", 15}, {"twenty", 20}, {"twenty-five", 25},
|
|
};
|
|
const std::unordered_map<std::string, int> unordermapWithoutFoo{{
|
|
{"zero", 0},
|
|
{"five", 5},
|
|
{"fifteen", 15},
|
|
{"twenty", 20},
|
|
{"twenty-five", 25},
|
|
}};
|
|
|
|
auto unorderedMapIt = unordermapWithFoo.find("ten");
|
|
|
|
ASSERT_TRUE(
|
|
MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo, unordermapWithFoo)
|
|
->second == unorderedMapIt->second);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item.second == foo,
|
|
unordermapWithoutFoo) == nullptr);
|
|
|
|
//-------------------------------
|
|
const std::unordered_set<int> unorderedsetWithFoo{0, 5, EXPECTED_INT,
|
|
15, 20, 25};
|
|
const std::unordered_set<int> unorderedsetWithoutFoo{0, 5, 15, 20, 25};
|
|
|
|
auto unorderedSetIt = unorderedsetWithFoo.find(EXPECTED_INT);
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo,
|
|
unorderedsetWithFoo) == *unorderedSetIt);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo,
|
|
unorderedsetWithoutFoo) == nullptr);
|
|
|
|
//-------------------------------
|
|
const std::vector<int> vectorWithFoo{0, 5, EXPECTED_INT, 15, 20, 25};
|
|
const std::vector<int> vectorWithoutFoo{0, 5, 15, 20, 25};
|
|
|
|
ASSERT_TRUE(*MOZ_FIND_AND_VALIDATE(foo, list_item == foo, vectorWithFoo) ==
|
|
vectorWithFoo[2]);
|
|
|
|
ASSERT_TRUE(MOZ_FIND_AND_VALIDATE(foo, list_item == foo, vectorWithoutFoo) ==
|
|
nullptr);
|
|
}
|
|
|
|
// ==================================================================
|
|
// MOZ_NO_VALIDATE ==================================================
|
|
TEST(Tainting, moz_no_validate)
|
|
{
|
|
int result;
|
|
Tainted<int> foo = Tainted<int>(EXPECTED_INT);
|
|
|
|
result = MOZ_NO_VALIDATE(
|
|
foo,
|
|
"Value is used to match against a dictionary key in the parent."
|
|
"If there's no key present, there won't be a match."
|
|
"There is no risk of grabbing a cross-origin value from the dictionary,"
|
|
"because the IPC actor is instatiated per-content-process and the "
|
|
"dictionary is not shared between actors.");
|
|
ASSERT_TRUE(result == EXPECTED_INT);
|
|
}
|