summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-check-out-of-bound-access.cpp
blob: 51adc2b4c3718d65fbb3ead33c39337b6cb929f7 (plain)
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
// slang-check-out-of-bound-access.cpp
#include "slang-check-out-of-bound-access.h"

#include "slang-ir-inst-pass-base.h"
#include "slang-ir-insts.h"
#include "slang-ir.h"

namespace Slang
{

struct OutOfBoundAccessChecker : public InstPassBase
{
    DiagnosticSink* sink;

    OutOfBoundAccessChecker(IRModule* inModule, DiagnosticSink* inSink)
        : InstPassBase(inModule), sink(inSink)
    {
    }


    void checkArrayAccess(IRInst* inst, IRInst* base, IRInst* index)
    {
        // Check if index is a constant integer
        auto indexLit = as<IRIntLit>(index);
        if (!indexLit)
            return; // Skip non-constant indices

        // Get the base type
        auto baseType = base->getDataType();

        // Handle pointer-to-array case (for GetElementPtr)
        if (auto ptrType = as<IRPtrTypeBase>(baseType))
        {
            baseType = ptrType->getValueType();
        }

        // Check if base is an array type
        auto arrayType = as<IRArrayTypeBase>(baseType);
        if (!arrayType)
            return; // Skip non-array types

        // Check if array size is a constant
        auto arraySizeInst = arrayType->getElementCount();
        auto arraySizeLit = as<IRIntLit>(arraySizeInst);
        if (!arraySizeLit)
            return; // Skip arrays with non-constant size

        // Get the actual values
        IRIntegerValue indexValue = indexLit->getValue();
        IRIntegerValue arraySizeValue = arraySizeLit->getValue();

        // Check bounds: index should be >= 0 and < arraySize
        if (indexValue < 0 || indexValue >= arraySizeValue)
        {
            sink->diagnose(inst, Diagnostics::arrayIndexOutOfBounds, indexValue, arraySizeValue);
        }
    }

    void processModule()
    {
        processAllInsts(
            [&](IRInst* inst)
            {
                switch (inst->getOp())
                {
                case kIROp_GetElement:
                case kIROp_GetElementPtr:
                    {
                        if (inst->getOperandCount() < 2)
                            return;

                        auto base = inst->getOperand(0);
                        auto index = inst->getOperand(1);

                        checkArrayAccess(inst, base, index);
                    }
                    break;
                }
            });
    }
};

void checkForOutOfBoundAccess(IRModule* module, DiagnosticSink* sink)
{
    OutOfBoundAccessChecker checker(module, sink);
    checker.processModule();
}

} // namespace Slang