다음을 통해 공유


구조화된 SARIF 진단

MSVC 컴파일러는 진단을 SARIF(정적 분석 결과 교환 형식)로 출력하도록 만들 수 있습니다. SARIF는 컴퓨터에서 읽을 수 있는 JSON 기반 형식입니다.

MSVC 컴파일러가 SARIF 진단을 생성하도록 만드는 방법에는 두 가지가 있습니다.

  • 명령줄에 /experimental:log 스위치를 전달합니다. 자세한 내용은 설명서를 /experimental:log 참조하세요.
  • 프로그래밍 방식으로 시작하고 cl.exe 환경 변수를 SARIF_OUTPUT_PIPE 설정하여 파이프를 통해 SARIF 블록을 검색합니다.

파이프를 통해 SARIF 검색

컴파일이 진행되는 동안 MSVC 컴파일러에서 SARIF를 사용하는 도구는 파이프를 사용합니다. Windows 파이프를 만드는 방법에 대한 CreatePipe 자세한 내용은 설명서를 참조하세요.

파이프를 통해 SARIF를 검색하려면 환경 변수를 파이프의 쓰기 끝에 대한 UTF-16으로 인코딩된 정수 표현으로 설정한 SARIF_OUTPUT_PIPE 다음 시작합니다cl.exe.HANDLE SARIF는 다음과 같이 파이프를 따라 전송됩니다.

  • 새 진단을 사용할 수 있는 경우 이 파이프에 기록됩니다.
  • 진단은 전체 SARIF 개체가 아니라 한 번에 하나씩 파이프에 기록됩니다.
  • 각 진단은 알림 형식JSON-RPC 2.0 메시지로 표시됩니다.
  • JSON-RPC 메시지에는 다음 JSON-RPC 메시지의 길이(바이트)인 두 개의 줄 바꿈 뒤에 양식 Content-Length: <N> 이 있는 <N> 헤더가 접두 Content-Length 사로 추가됩니다.
  • JSON-RPC 메시지와 헤더는 모두 UTF-8로 인코딩됩니다.
  • 이 JSON-RPC-with-header 형식은 vs-streamjsonrpc호환됩니다.
  • JSON-RPC 호출 OnSarifResult의 메서드 이름은 .
  • 호출에는 매개 변수 이름으로 result인코딩되는 단일 매개 변수가 있습니다.
  • 인수 값은 SARIF 버전 2.1 표준에 지정된 단일 result 개체입니다.

예시

다음은 다음에서 생성한 JSON-RPC SARIF 결과의 예입니다 cl.exe.

Content-Length: 334

{"jsonrpc":"2.0","method":"OnSarifResult","params":{"result":{"ruleId":"C1034","level":"fatal","message":{"text":"iostream: no include path set"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"file:///C:/Users/sybrand/source/repos/cppcon-diag/cppcon-diag/cppcon-diag.cpp"},"region":{"startLine":1,"startColumn":10}}}]}}}{"jsonrpc":"2.0","method":"OnSarifResult","params":{"result":{"ruleId":"C1034","level":"fatal","message":{"text":"iostream: no include path set"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"file:///C:/Users/sybrand/source/repos/cppcon-diag/cppcon-diag/cppcon-diag.cpp"},"region":{"startLine":1,"startColumn":10}}}]}}}

SARIF 결과 데이터

컴파일러는 일부 진단의 중첩된 구조를 나타내는 추가 정보를 포함할 수 있는 SARIF를 출력합니다. 진단(SARIF 개체로 result 표시됨)에는 해당 필드에 추가 정보의 "진단 트리"가 relatedLocations 포함될 수 있습니다. 이 트리는 다음과 같이 SARIF 속성 모음 을 사용하여 인코딩됩니다.

location 개체의 properties 필드에는 진단 트리에서 이 위치의 깊이 값이 있는 속성이 포함될 nestingLevel 수 있습니다. 위치에 지정된 위치가 nestingLevel 없으면 깊이가 있는 것으로 0 간주되며 이 위치는 해당 위치가 포함된 개체가 result 나타내는 루트 진단의 자식입니다. 그렇지 않으면 값이 필드에서 이 위치 바로 앞에 있는 위치 relatedLocations 의 깊이보다 크면 이 위치는 해당 위치의 자식입니다. 그렇지 않으면 이 위치는 동일한 깊이를 가진 필드에서 가장 앞에 location relatedLocations 있는 형제입니다.

예시

다음 코드를 생각해 봅시다.

struct dog {};
struct cat {};

void pet(dog);
void pet(cat);

struct lizard {};

int main() {
    pet(lizard{});
}

이 코드를 컴파일하면 컴파일러는 다음과 같은 result 개체를 생성합니다(physicalLocation 간단히 하기 위해 속성이 제거됨).

{
    "ruleId": "C2665",
    "level": "error",
    "message": {
        "text": "'pet': no overloaded function could convert all the argument types"
    },
    "relatedLocations": [
        {
            "id": 0,
            "message": {
                "text": "could be 'void pet(cat)'"
            }
        },
        {
            "id": 1,
            "message": {
                "text": "'void pet(cat)': cannot convert argument 1 from 'lizard' to 'cat'"
            },
            "properties": {
                "nestingLevel": 1
            }
        },
        {
            "id": 2,
            "message": {
                "text": "No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called"
            },
            "properties": {
                "nestingLevel": 2
            }
        },
        {
            "id": 3,
            "message": {
                "text": "or       'void pet(dog)'"
            }
        },
        {
            "id": 4,
            "message": {
                "text": "'void pet(dog)': cannot convert argument 1 from 'lizard' to 'dog'"
            },
            "properties": {
                "nestingLevel": 1
            }
        },
        {
            "id": 5,
            "message": {
                "text": "No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called"
            },
            "properties": {
                "nestingLevel": 2
            }
        },
        {
            "id": 6,
            "message": {
                "text": "while trying to match the argument list '(lizard)'"
            }
        }
    ]
}

result 개체의 메시지에서 생성된 논리 진단 트리는 다음과 같습니다.

  • 'pet': 오버로드된 함수가 모든 인수 형식을 변환할 수 없음
    • 는 'void 애완 동물 (고양이)'일 수 있습니다.
      • 'void pet(cat)': 인수 1을 '도마뱀'에서 '고양이'로 변환할 수 없습니다.
        • 이 변환을 수행할 수 있는 사용자 정의 변환 연산자를 사용할 수 없거나 연산자를 호출할 수 없습니다.
    • 또는 'void pet(dog)'
      • 'void pet(dog)': 인수 1을 '도마뱀'에서 '개'로 변환할 수 없습니다.
        • 이 변환을 수행할 수 있는 사용자 정의 변환 연산자를 사용할 수 없거나 연산자를 호출할 수 없습니다.
    • 인수 목록 '(lizard)'와 일치시키려고 하는 동안

참고 항목

/experimental:log (구조적 SARIF 진단 사용)