Coverage Report

Created: 2026-02-14 08:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Runtime/DataView.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibJS/Runtime/DataView.h>
8
9
namespace JS {
10
11
JS_DEFINE_ALLOCATOR(DataView);
12
13
NonnullGCPtr<DataView> DataView::create(Realm& realm, ArrayBuffer* viewed_buffer, ByteLength byte_length, size_t byte_offset)
14
0
{
15
0
    return realm.heap().allocate<DataView>(realm, viewed_buffer, move(byte_length), byte_offset, realm.intrinsics().data_view_prototype());
16
0
}
17
18
DataView::DataView(ArrayBuffer* viewed_buffer, ByteLength byte_length, size_t byte_offset, Object& prototype)
19
0
    : Object(ConstructWithPrototypeTag::Tag, prototype)
20
0
    , m_viewed_array_buffer(viewed_buffer)
21
0
    , m_byte_length(move(byte_length))
22
0
    , m_byte_offset(byte_offset)
23
0
{
24
0
}
25
26
void DataView::visit_edges(Visitor& visitor)
27
0
{
28
0
    Base::visit_edges(visitor);
29
0
    visitor.visit(m_viewed_array_buffer);
30
0
}
31
32
// 25.3.1.2 MakeDataViewWithBufferWitnessRecord ( obj, order ), https://tc39.es/ecma262/#sec-makedataviewwithbufferwitnessrecord
33
DataViewWithBufferWitness make_data_view_with_buffer_witness_record(DataView const& data_view, ArrayBuffer::Order order)
34
0
{
35
    // 1. Let buffer be obj.[[ViewedArrayBuffer]].
36
0
    auto* buffer = data_view.viewed_array_buffer();
37
38
0
    ByteLength byte_length { 0 };
39
40
    // 2. If IsDetachedBuffer(buffer) is true, then
41
0
    if (buffer->is_detached()) {
42
        // a. Let byteLength be detached.
43
0
        byte_length = ByteLength::detached();
44
0
    }
45
    // 3. Else,
46
0
    else {
47
        // a. Let byteLength be ArrayBufferByteLength(buffer, order).
48
0
        byte_length = array_buffer_byte_length(*buffer, order);
49
0
    }
50
51
    // 4. Return the DataView With Buffer Witness Record { [[Object]]: obj, [[CachedBufferByteLength]]: byteLength }.
52
0
    return { .object = data_view, .cached_buffer_byte_length = move(byte_length) };
53
0
}
54
55
// 25.3.1.3 GetViewByteLength ( viewRecord ), https://tc39.es/ecma262/#sec-getviewbytelength
56
u32 get_view_byte_length(DataViewWithBufferWitness const& view_record)
57
0
{
58
    // 1. Assert: IsViewOutOfBounds(viewRecord) is false.
59
0
    VERIFY(!is_view_out_of_bounds(view_record));
60
61
    // 2. Let view be viewRecord.[[Object]].
62
0
    auto const& view = *view_record.object;
63
64
    // 3. If view.[[ByteLength]] is not auto, return view.[[ByteLength]].
65
0
    if (!view.byte_length().is_auto())
66
0
        return view.byte_length().length();
67
68
    // 4. Assert: IsFixedLengthArrayBuffer(view.[[ViewedArrayBuffer]]) is false.
69
0
    VERIFY(!view.viewed_array_buffer()->is_fixed_length());
70
71
    // 5. Let byteOffset be view.[[ByteOffset]].
72
0
    auto byte_offset = view.byte_offset();
73
74
    // 6. Let byteLength be viewRecord.[[CachedBufferByteLength]].
75
0
    auto const& byte_length = view_record.cached_buffer_byte_length;
76
77
    // 7. Assert: byteLength is not detached.
78
0
    VERIFY(!byte_length.is_detached());
79
80
    // 8. Return byteLength - byteOffset.
81
0
    return byte_length.length() - byte_offset;
82
0
}
83
84
// 25.3.1.4 IsViewOutOfBounds ( viewRecord ), https://tc39.es/ecma262/#sec-isviewoutofbounds
85
bool is_view_out_of_bounds(DataViewWithBufferWitness const& view_record)
86
0
{
87
    // 1. Let view be viewRecord.[[Object]].
88
0
    auto const& view = *view_record.object;
89
90
    // 2. Let bufferByteLength be viewRecord.[[CachedBufferByteLength]].
91
0
    auto const& buffer_byte_length = view_record.cached_buffer_byte_length;
92
93
    // 3. Assert: IsDetachedBuffer(view.[[ViewedArrayBuffer]]) is true if and only if bufferByteLength is detached.
94
0
    VERIFY(view.viewed_array_buffer()->is_detached() == buffer_byte_length.is_detached());
95
96
    // 4. If bufferByteLength is detached, return true.
97
0
    if (buffer_byte_length.is_detached())
98
0
        return true;
99
100
    // 5. Let byteOffsetStart be view.[[ByteOffset]].
101
0
    auto byte_offset_start = view.byte_offset();
102
0
    u32 byte_offset_end = 0;
103
104
    // 6. If view.[[ByteLength]] is auto, then
105
0
    if (view.byte_length().is_auto()) {
106
        // a. Let byteOffsetEnd be bufferByteLength.
107
0
        byte_offset_end = buffer_byte_length.length();
108
0
    }
109
    // 7. Else,
110
0
    else {
111
        // a. Let byteOffsetEnd be byteOffsetStart + view.[[ByteLength]].
112
0
        byte_offset_end = byte_offset_start + view.byte_length().length();
113
0
    }
114
115
    // 8. If byteOffsetStart > bufferByteLength or byteOffsetEnd > bufferByteLength, return true.
116
0
    if ((byte_offset_start > buffer_byte_length.length()) || (byte_offset_end > buffer_byte_length.length()))
117
0
        return true;
118
119
    // 9. NOTE: 0-length DataViews are not considered out-of-bounds.
120
    // 10. Return false.
121
0
    return false;
122
0
}
123
124
}