File: sanitizer.cpp

package info (click to toggle)
vulkan-validationlayers 1.4.341.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 54,356 kB
  • sloc: cpp: 675,478; python: 12,311; sh: 24; makefile: 24; xml: 14
file content (138 lines) | stat: -rw-r--r-- 7,472 bytes parent folder | download
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
/* Copyright (c) 2024-2026 LunarG, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <spirv/unified1/GLSL.std.450.h>
#include "generated/spirv_grammar_helper.h"
#include "gpuav/core/gpuav.h"
#include "gpuav/resources/gpuav_state_trackers.h"
#include "gpuav/shaders/gpuav_error_codes.h"
#include "gpuav/shaders/gpuav_error_header.h"

namespace gpuav {

static std::string GetSpirvSpecLink(const uint32_t opcode) {
    // Currently the Working Group decided to not provide "real" VUIDs as it would become duplicating the SPIR-V spec
    // So these are not "UNASSIGNED", but instead are "SPIRV" VUs because we can point to the instruction in the SPIR-V spec
    // (https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/7853)
    return "\nSee more at https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#" + std::string(string_SpvOpcode(opcode));
}

void RegisterSanitizer(Validator &gpuav, CommandBufferSubState &cb) {
    if (!gpuav.gpuav_settings.shader_instrumentation.sanitizer) {
        return;
    }

    cb.on_instrumentation_error_logger_register_functions.emplace_back([](Validator &gpuav, CommandBufferSubState &cb,
                                                                          const LastBound &last_bound) {
        CommandBufferSubState::InstrumentationErrorLogger inst_error_logger = [](Validator &gpuav, const Location &loc,
                                                                                 const uint32_t *error_record,
                                                                                 std::string &out_error_msg,
                                                                                 std::string &out_vuid_msg) {
            using namespace glsl;
            bool error_found = false;
            if (GetErrorGroup(error_record) != kErrorGroup_InstSanitizer) {
                return error_found;
            }
            error_found = true;

            std::ostringstream strm;

            const uint32_t error_sub_code = GetSubError(error_record);
            switch (error_sub_code) {
                case kErrorSubCode_Sanitizer_DivideZero: {
                    const uint32_t opcode = error_record[kInst_LogError_ParameterOffset_0];
                    const uint32_t vector_size = error_record[kInst_LogError_ParameterOffset_1];
                    const bool is_float = opcode == spv::OpFMod || opcode == spv::OpFRem;
                    strm << (is_float ? "Float" : "Integer") << " divide by zero. Operand 2 of " << string_SpvOpcode(opcode)
                         << " is ";
                    if (vector_size == 0) {
                        strm << "zero.";
                    } else {
                        strm << "a " << vector_size << "-wide vector which contains a zero value.";
                    }
                    if (is_float) {
                        strm << " The result value is undefined.";
                    }
                    strm << GetSpirvSpecLink(opcode);
                    out_vuid_msg = "SPIRV-Sanitizer-Divide-By-Zero";
                } break;
                case kErrorSubCode_Sanitizer_ImageGather: {
                    const uint32_t component_value = error_record[kInst_LogError_ParameterOffset_0];
                    const int32_t signed_value = (int32_t)component_value;
                    strm << "OpImageGather has a component value of ";
                    if (signed_value > 0) {
                        strm << component_value;
                    } else {
                        strm << signed_value;
                    }
                    strm << ", but it must be 0, 1, 2, or 3" << GetSpirvSpecLink(spv::OpImageGather);
                    out_vuid_msg = "SPIRV-Sanitizer-Image-Gather";
                } break;
                case kErrorSubCode_Sanitizer_Pow: {
                    // Pow is only valid with a scalar/vector of 16/32-bit float
                    const uint32_t vector_size = error_record[kInst_LogError_ParameterOffset_0];
                    // Casting produces artifacts in float value, need to memcpy
                    float x_value = 0.0f;
                    float y_value = 0.0f;
                    memcpy(&x_value, &error_record[kInst_LogError_ParameterOffset_1], sizeof(float));
                    memcpy(&y_value, &error_record[kInst_LogError_ParameterOffset_2], sizeof(float));
                    strm << "Pow (from GLSL.std.450) has an undefined result because operand (x < 0) or (x == 0 && y <= 0)\n  ";
                    if (vector_size > 0) {
                        // Would need a new way to print more than 2 bytes out to get this to work
                        strm << "Using a vector of size " << vector_size << " but currently only can print out scalar values";
                    } else {
                        strm << "X == " << x_value << ", Y == " << y_value;
                    }
                    out_vuid_msg = "SPIRV-Sanitizer-Pow";
                } break;
                case kErrorSubCode_Sanitizer_Atan2: {
                    // Atan is only valid with a scalar/vector of 16/32-bit float
                    strm << "Atan2 (from GLSL.std.450) has an undefined result because both values used are zero.";
                    out_vuid_msg = "SPIRV-Sanitizer-Atan2";
                } break;
                case kErrorSubCode_Sanitizer_Fminmax: {
                    // simple encoding done in inst_sanitizer_fminman (sanitizer.comp)
                    const uint32_t invalid_encode = error_record[kInst_LogError_ParameterOffset_0];
                    const bool x_is_invalid = (invalid_encode & 0x1) != 0;
                    const bool y_is_invalid = (invalid_encode & 0x2) != 0;
                    const uint32_t vector_size = error_record[kInst_LogError_ParameterOffset_1];
                    const uint32_t glsl_opcode = error_record[kInst_LogError_ParameterOffset_2];
                    strm << (glsl_opcode == GLSLstd450FMin ? "FMin" : "FMax")
                         << " (from GLSL.std.450) has an undefined result because ";
                    if (x_is_invalid && y_is_invalid) {
                        strm << "both the x and y operands are NaN\n";
                    } else if (x_is_invalid) {
                        strm << "the x operand is NaN\n";
                    } else {
                        strm << "the y operand is NaN\n";
                    }
                    if (vector_size > 0) {
                        strm << "Using a vector of size " << vector_size << " but currently only can print out scalar values";
                    }
                    out_vuid_msg = "SPIRV-Sanitizer-Fminmax";
                } break;
                default:
                    error_found = false;
                    break;
            }
            out_error_msg += strm.str();
            return error_found;
        };

        return inst_error_logger;
    });
}

}  // namespace gpuav