Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Aqui estão algumas maneiras de tirar o máximo proveito da linguagem de anotação de código-fonte (SAL) e evitar alguns problemas comuns.
_In_
Se a função deve gravar no elemento , use _Inout_ em vez de _In_. Isto é relevante em casos de conversão automática de macros mais antigas para SAL. Antes da SAL, muitos programadores usavam macros como comentários — macros que eram nomeadas IN, OUT, IN_OUT, ou variantes desses nomes. Embora recomendemos que você converta essas macros para SAL, também pedimos que você tenha cuidado ao convertê-las, porque o código pode ter mudado desde que o protótipo original foi escrito e a macro antiga pode não refletir mais o que o código faz. Tenha especial cuidado com a OPTIONAL macro de comentário porque ela é frequentemente colocada incorretamente, por exemplo, no lado errado de uma vírgula.
#include <sal.h>
// Incorrect
void Func1(_In_ int *p1)
{
if (p1 == NULL)
return;
*p1 = 1;
}
// Correct
// _Out_opt_ because the function tolerates NULL as a valid argument, i.e.
// no error is returned. If the function didn't check p1 for NULL, then
// _Out_ would be the better choice
void Func2(_Out_opt_ PCHAR p1)
{
if (p1 == NULL)
return;
*p1 = 1;
}
_opt_
Se o chamador não tiver permissão para passar um ponteiro nulo, use _In_ ou _Out_ em vez de _In_opt_ ou _Out_opt_. Isso se aplica até mesmo a uma função que verifica seus parâmetros e retorna um erro se for NULL quando não deveria ser. Embora ter uma função verificar o seu parâmetro para elementos inesperados NULL e retornar de forma graciosa seja uma boa prática de programação defensiva, isso não significa que a anotação do parâmetro possa ser de um tipo opcional (_*Xxx*_opt_).
#include <sal.h>
// Incorrect
void Func1(_Out_opt_ int *p1)
{
*p = 1;
}
// Correct
void Func2(_Out_ int *p1)
{
*p = 1;
}
_Pre_defensive_ e _Post_defensive_
Se uma função aparecer numa fronteira de confiança, recomendamos que utilize a _Pre_defensive_ anotação. O modificador "defensivo" modifica certas anotações para indicar que, no ponto de chamada, deve-se verificar rigorosamente a interface, mas no corpo da implementação deve-se assumir que podem ser passados parâmetros incorretos. Nesse caso, _In_ _Pre_defensive_ é preferível na fronteira de confiança para indicar que, embora um chamador receba um erro se tentar passar NULL, o corpo da função é analisado como se o parâmetro pudesse ser NULL, e quaisquer tentativas de desreferenciar o ponteiro sem antes tentar verificá-lo para NULL são sinalizadas. Uma _Post_defensive_ anotação também está disponível, para uso em retornos de chamada em que a parte confiável é assumida como sendo o chamador e o código não confiável é o código chamado.
_Out_writes_
O exemplo a seguir demonstra um uso indevido comum do _Out_writes_.
#include <sal.h>
// Incorrect
void Func1(_Out_writes_(size) CHAR *pb,
DWORD size
);
A anotação _Out_writes_ significa que você tem um buffer. Ele tem cb bytes alocados, com o primeiro byte inicializado ao sair. A anotação não está completamente errada e ajuda a expressar o tamanho alocado. No entanto, ele não diz quantos elementos a função inicializa.
O próximo exemplo mostra três maneiras corretas de especificar completamente o tamanho exato da parte inicializada do buffer.
#include <sal.h>
// Correct
void Func1(_Out_writes_to_(size, *pCount) CHAR *pb,
DWORD size,
PDWORD pCount
);
void Func2(_Out_writes_all_(size) CHAR *pb,
DWORD size
);
void Func3(_Out_writes_(size) PSTR pb,
DWORD size
);
_Out_ PSTR
O uso de _Out_ PSTR é quase sempre errado. Essa combinação é interpretada como tendo um parâmetro de saída que aponta para um buffer de caracteres e o buffer é terminado em nulo.
#include <sal.h>
// Incorrect
void Func1(_Out_ PSTR pFileName, size_t n);
// Correct
void Func2(_Out_writes_(n) PSTR wszFileName, size_t n);
Uma anotação como _In_ PCSTR é comum e útil. Ele aponta para uma cadeia de caracteres de entrada que tem terminação nula porque a pré-condição de _In_ permite o reconhecimento de uma cadeia de caracteres terminada em nulo.
_In_ WCHAR* p
_In_ WCHAR* p diz que há um ponteiro p de entrada que aponta para um caractere. No entanto, na maioria dos casos, esta provavelmente não é a especificação pretendida. Em vez disso, o que provavelmente se pretende é a especificação de uma matriz terminada em nulo; Para fazer isso, use _In_ PWSTR.
#include <sal.h>
// Incorrect
void Func1(_In_ WCHAR* wszFileName);
// Correct
void Func2(_In_ PWSTR wszFileName);
A falta de especificação adequada de terminação nula é comum. Use a versão apropriada STR para substituir o tipo, conforme mostrado no exemplo a seguir.
#include <sal.h>
#include <string.h>
// Incorrect
BOOL StrEquals1(_In_ PCHAR p1, _In_ PCHAR p2)
{
return strcmp(p1, p2) == 0;
}
// Correct
BOOL StrEquals2(_In_ PSTR p1, _In_ PSTR p2)
{
return strcmp(p1, p2) == 0;
}
_Out_range_
Se o parâmetro for um ponteiro e você quiser expressar o intervalo do valor do elemento apontado pelo ponteiro, use _Deref_out_range_ em vez de _Out_range_. No exemplo a seguir, é expresso o intervalo de *pcbFilled, e não de pcbFilled.
#include <sal.h>
// Incorrect
void Func1(
_Out_writes_bytes_to_(cbSize, *pcbFilled) BYTE *pb,
DWORD cbSize,
_Out_range_(0, cbSize) DWORD *pcbFilled
);
// Correct
void Func2(
_Out_writes_bytes_to_(cbSize, *pcbFilled) BYTE *pb,
DWORD cbSize,
_Deref_out_range_(0, cbSize) _Out_ DWORD *pcbFilled
);
_Deref_out_range_(0, cbSize) não é estritamente necessário para algumas ferramentas porque pode ser inferido a partir do _Out_writes_to_(cbSize,*pcbFilled), mas é mostrado aqui para completude.
Contexto errado em _When_
Outro erro comum é usar a avaliação pós-estado para pré-condições. No exemplo a seguir, _Requires_lock_held_ é uma pré-condição.
#include <sal.h>
// Incorrect
_When_(return == 0, _Requires_lock_held_(p->cs))
int Func1(_In_ MyData *p, int flag);
// Correct
_When_(flag == 0, _Requires_lock_held_(p->cs))
int Func2(_In_ MyData *p, int flag);
A expressão return refere-se a um valor de estado posterior que não está disponível no estado anterior.
TRUE no _Success_
Se a função for bem-sucedida quando o valor de retorno for diferente de zero, use return != 0 como condição de sucesso em vez de return == TRUE. Não zero não significa necessariamente que é equivalente ao valor real que o compilador fornece para TRUE. O parâmetro to _Success_ é uma expressão, e as seguintes expressões são avaliadas como equivalentes: return != 0, return != false, return != FALSE, e return sem parâmetros ou comparações.
// Incorrect
_Success_(return == TRUE) _Acquires_lock_(*lpCriticalSection)
BOOL WINAPI TryEnterCriticalSection(
_Inout_ LPCRITICAL_SECTION lpCriticalSection
);
// Correct
_Success_(return != 0) _Acquires_lock_(*lpCriticalSection)
BOOL WINAPI TryEnterCriticalSection(
_Inout_ LPCRITICAL_SECTION lpCriticalSection
);
Variável de referência
Para uma variável de referência, a versão anterior da SAL usava o ponteiro implícito como destino de anotação e exigia a adição de a __deref às anotações anexadas a uma variável de referência. Esta versão usa o próprio objeto e não requer _Deref_.
#include <sal.h>
// Incorrect
void Func1(
_Out_writes_bytes_all_(cbSize) BYTE *pb,
_Deref_ _Out_range_(0, 2) _Out_ DWORD &cbSize
);
// Correct
void Func2(
_Out_writes_bytes_all_(cbSize) BYTE *pb,
_Out_range_(0, 2) _Out_ DWORD &cbSize
);
Anotações em valores de retorno
O exemplo a seguir mostra um problema comum em anotações de valor de retorno.
#include <sal.h>
// Incorrect
_Out_opt_ void *MightReturnNullPtr1();
// Correct
_Ret_maybenull_ void *MightReturnNullPtr2();
Neste exemplo, _Out_opt_ diz que o ponteiro pode ser NULL como parte da pré-condição. No entanto, as pré-condições não podem ser aplicadas ao valor de retorno. Neste caso, a anotação correta é _Ret_maybenull_.
Ver também
Usando anotações SAL para reduzir defeitos de código C/C++
Compreender SAL
Anotando parâmetros de função e valores de retorno
Anotando o comportamento da função
Anotando instruções e classes
Anotando o comportamento de bloqueio
Especificando quando e onde uma anotação se aplica
Funções intrínsecas