• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 2293

02 May 2024 08:09PM UTC coverage: 90.759% (+0.01%) from 90.747%
2293

push

Evergreen

web-flow
Fix a deadlock when accessing current user from inside an App listener (#7671)

App::switch_user() emitted changes without first releasing the lock on
m_user_mutex, leading to a deadlock if anyone inside the listener tried to
acquire the mutex. The rest of the places where we emitted changes were
correct.

The newly added wrapper catches this error when building with clang.

101946 of 180246 branches covered (56.56%)

14 of 17 new or added lines in 2 files covered. (82.35%)

67 existing lines in 15 files now uncovered.

212564 of 234207 relevant lines covered (90.76%)

5790527.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.08
/src/realm/collection_parent.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2023 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include <realm/collection_parent.hpp>
20
#include "realm/list.hpp"
21
#include "realm/set.hpp"
22
#include "realm/dictionary.hpp"
23
#include "realm/util/overload.hpp"
24

25
#include <random>
26
#include <mutex>
27

28
namespace realm {
29

30
std::ostream& operator<<(std::ostream& ostr, const PathElement& elem)
31
{
47,565✔
32
    if (elem.is_ndx()) {
47,565✔
33
        size_t ndx = elem.get_ndx();
10,752✔
34
        if (ndx == 0) {
10,752✔
35
            ostr << "FIRST";
3,918✔
36
        }
3,918✔
37
        else if (ndx == size_t(-1)) {
6,834✔
38
            ostr << "LAST";
330✔
39
        }
330✔
40
        else {
6,504✔
41
            ostr << elem.get_ndx();
6,504✔
42
        }
6,504✔
43
    }
10,752✔
44
    else if (elem.is_col_key()) {
36,813✔
45
        ostr << elem.get_col_key();
×
46
    }
×
47
    else if (elem.is_key()) {
36,813✔
48
        ostr << "'" << elem.get_key() << "'";
36,669✔
49
    }
36,669✔
50
    else if (elem.is_all()) {
144✔
51
        ostr << '*';
144✔
52
    }
144✔
53

54
    return ostr;
47,565✔
55
}
47,565✔
56

57
std::ostream& operator<<(std::ostream& ostr, const Path& path)
58
{
21,057✔
59
    for (auto& elem : path) {
46,509✔
60
        ostr << '[' << elem << ']';
46,509✔
61
    }
46,509✔
62
    return ostr;
21,057✔
63
}
21,057✔
64

65
bool StablePath::is_prefix_of(const StablePath& other) const noexcept
66
{
10,686✔
67
    if (size() > other.size())
10,686✔
68
        return false;
234✔
69
    return std::equal(begin(), end(), other.begin());
10,452✔
70
}
10,686✔
71

72
/***************************** CollectionParent ******************************/
73

74
CollectionParent::~CollectionParent() {}
2,707,893✔
75

76
void CollectionParent::check_level() const
77
{
4,290✔
78
    if (size_t(m_level) + 1 > s_max_level) {
4,290✔
79
        throw LogicError(ErrorCodes::LimitExceeded, "Max nesting level reached");
6✔
80
    }
6✔
81
}
4,290✔
82

83
template <typename Base, template <typename> typename Collection, typename LinkCol>
84
std::unique_ptr<Base> create_collection(ColKey col_key, uint8_t level)
85
{
440,073✔
86
    bool nullable = col_key.get_attrs().test(col_attr_Nullable);
440,073✔
87
    switch (col_key.get_type()) {
440,073✔
88
        case col_type_Int:
27,273✔
89
            if (nullable)
27,273✔
90
                return std::make_unique<Collection<util::Optional<Int>>>(col_key);
5,622✔
91
            return std::make_unique<Collection<Int>>(col_key);
21,651✔
92
        case col_type_Bool:
9,264✔
93
            if (nullable)
9,264✔
94
                return std::make_unique<Collection<util::Optional<Bool>>>(col_key);
4,812✔
95
            return std::make_unique<Collection<Bool>>(col_key);
4,452✔
96
        case col_type_Float:
10,056✔
97
            if (nullable)
10,056✔
98
                return std::make_unique<Collection<util::Optional<Float>>>(col_key);
5,226✔
99
            return std::make_unique<Collection<Float>>(col_key);
4,830✔
100
        case col_type_Double:
10,314✔
101
            if (nullable)
10,314✔
102
                return std::make_unique<Collection<util::Optional<Double>>>(col_key);
5,226✔
103
            return std::make_unique<Collection<Double>>(col_key);
5,088✔
104
        case col_type_String:
245,412✔
105
            return std::make_unique<Collection<String>>(col_key);
245,412✔
106
        case col_type_Binary:
9,882✔
107
            return std::make_unique<Collection<Binary>>(col_key);
9,882✔
108
        case col_type_Timestamp:
9,978✔
109
            return std::make_unique<Collection<Timestamp>>(col_key);
9,978✔
110
        case col_type_Decimal:
9,564✔
111
            return std::make_unique<Collection<Decimal128>>(col_key);
9,564✔
112
        case col_type_ObjectId:
18,414✔
113
            if (nullable)
18,414✔
114
                return std::make_unique<Collection<util::Optional<ObjectId>>>(col_key);
13,944✔
115
            return std::make_unique<Collection<ObjectId>>(col_key);
4,470✔
116
        case col_type_UUID:
9,306✔
117
            if (nullable)
9,306✔
118
                return std::make_unique<Collection<util::Optional<UUID>>>(col_key);
4,848✔
119
            return std::make_unique<Collection<UUID>>(col_key);
4,458✔
120
        case col_type_TypedLink:
✔
121
            return std::make_unique<Collection<ObjLink>>(col_key);
×
122
        case col_type_Mixed:
15,714✔
123
            return std::make_unique<Collection<Mixed>>(col_key, level + 1);
15,714✔
124
        case col_type_Link:
64,896✔
125
            return std::make_unique<LinkCol>(col_key);
64,896✔
126
        default:
✔
127
            REALM_TERMINATE("Unsupported column type.");
128
    }
440,073✔
129
}
440,073✔
130

131
LstBasePtr CollectionParent::get_listbase_ptr(ColKey col_key, uint8_t level)
132
{
322,254✔
133
    REALM_ASSERT(col_key.get_attrs().test(col_attr_List) || col_key.get_type() == col_type_Mixed);
322,254✔
134
    return create_collection<LstBase, Lst, LnkLst>(col_key, level);
322,254✔
135
}
322,254✔
136

137
SetBasePtr CollectionParent::get_setbase_ptr(ColKey col_key, uint8_t level)
138
{
117,819✔
139
    REALM_ASSERT(col_key.get_attrs().test(col_attr_Set));
117,819✔
140
    return create_collection<SetBase, Set, LnkSet>(col_key, level);
117,819✔
141
}
117,819✔
142

143
CollectionBasePtr CollectionParent::get_collection_ptr(ColKey col_key, uint8_t level)
144
{
127,461✔
145
    if (col_key.is_list()) {
127,461✔
146
        return get_listbase_ptr(col_key, level);
23,451✔
147
    }
23,451✔
148
    else if (col_key.is_set()) {
104,010✔
149
        return get_setbase_ptr(col_key, level);
74,271✔
150
    }
74,271✔
151
    else if (col_key.is_dictionary()) {
29,739✔
152
        return std::make_unique<Dictionary>(col_key, level + 1);
29,739✔
153
    }
29,739✔
154
    return {};
×
155
}
127,461✔
156

157
int64_t CollectionParent::generate_key(size_t sz)
158
{
6,636✔
159
    static std::mt19937 gen32;
6,636✔
160
    static std::mutex mutex;
6,636✔
161

162
    int64_t key;
6,636✔
163
    const std::lock_guard<std::mutex> lock(mutex);
6,636✔
164
    do {
6,636✔
165
        if (sz < 0x10) {
6,636✔
166
            key = int8_t(gen32());
4,038✔
167
        }
4,038✔
168
        else if (sz < 0x1000) {
2,598✔
169
            key = int16_t(gen32());
2,598✔
170
        }
2,598✔
UNCOV
171
        else {
×
UNCOV
172
            key = int32_t(gen32());
×
UNCOV
173
        }
×
174
    } while (key == 0);
6,636✔
175

176
    return key;
6,636✔
177
}
6,636✔
178

179
void CollectionParent::set_key(BPlusTreeMixed& tree, size_t index)
180
{
4,038✔
181
    int64_t key = generate_key(tree.size());
4,038✔
182
    while (tree.find_key(key) != realm::not_found) {
4,050✔
183
        key++;
12✔
184
    }
12✔
185
    tree.set_key(index, key);
4,038✔
186
}
4,038✔
187

188
} // namespace realm
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc