Предупреждение о распаде указателя (C26485) и передача переменной-члена NOTIFYICONDATA в _tcscpy_s

#visual-c #code-analysis

Вопрос:

Пример кода:

 void CMeetingScheduleAssistantDlg::CreateBackupTrayNotification(CString strInfoTitle, CString strInfo, CString strTip)
{
    ::ZeroMemory(amp;m_sNTD, sizeof(NOTIFYICONDATA));

    m_sNTD.cbSize = sizeof(NOTIFYICONDATA);
    m_sNTD.hWnd = GetSafeHwnd();
    m_sNTD.uID = 0;
    m_sNTD.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;

    m_sNTD.dwInfoFlags = NIIF_INFO;

    m_sNTD.uCallbackMessage = WM_MSA_BACKUP_NOTIFICATION;
    m_sNTD.uTimeout = 20000; // 20 Seconds
    m_sNTD.hIcon = LoadIcon(AfxGetResourceHandle(),
        MAKEINTRESOURCE(IDR_MAINFRAME));

    _tcscpy_s(m_sNTD.szInfoTitle, gsl::narrow<rsize_t>(strInfoTitle.GetLength())   1, (LPCTSTR)strInfoTitle);
    _tcscpy_s(m_sNTD.szInfo, gsl::narrow<rsize_t>(strInfo.GetLength())   1, (LPCTSTR)strInfo);
    _tcscpy_s(m_sNTD.szTip, gsl::narrow<rsize_t>(strTip.GetLength())   1, (LPCTSTR)strTip);

    Shell_NotifyIcon(NIM_ADD, amp;m_sNTD);
}
 

Игнорируйте (LPCTSTR) приведения, потому что я добавил глобальное pragma значение для игнорирования предупреждений. Мой вопрос здесь относится к этим строкам:

 _tcscpy_s(m_sNTD.szInfoTitle, gsl::narrow<rsize_t>(strInfoTitle.GetLength())   1, (LPCTSTR)strInfoTitle);
_tcscpy_s(m_sNTD.szInfo, gsl::narrow<rsize_t>(strInfo.GetLength())   1, (LPCTSTR)strInfo);
_tcscpy_s(m_sNTD.szTip, gsl::narrow<rsize_t>(strTip.GetLength())   1, (LPCTSTR)strTip);
 

m_sNTD является NOTIFYICONDATA структурой:

 typedef struct _NOTIFYICONDATAA {
  DWORD cbSize;
  HWND  hWnd;
  UINT  uID;
  UINT  uFlags;
  UINT  uCallbackMessage;
  HICON hIcon;
#if ...
  CHAR  szTip[64];
#else
  CHAR  szTip[128];
#endif
  DWORD dwState;
  DWORD dwStateMask;
  CHAR  szInfo[256];
  union {
    UINT uTimeout;
    UINT uVersion;
  } DUMMYUNIONNAME;
  CHAR  szInfoTitle[64];
  DWORD dwInfoFlags;
  GUID  guidItem;
  HICON hBalloonIcon;
} NOTIFYICONDATAA, *PNOTIFYICONDATAA;
 

Я получаю страшное предупреждение о распаде указателя (C26485). Как вы можете видеть, рассматриваемые переменные-члены:

  • CHAR szInfoTitle[64];
  • CHAR szInfo[256];
  • CHAR szTip[128];

Примечание: не уверен if ... , о чем это. Кроме того, моя структура фактически указывает на a NOTIFYICONDATAW , поэтому переменные-члены WCHAR .

В любом случае, я понимаю, что я могу подавить предупреждение о распаде указателя, используя amp;varname[0] . Но в этом случае он не работает:

 _tcscpy_s(m_sNTD.amp;szInfoTitle[0], gsl::narrow<rsize_t>(strInfoTitle.GetLength())   1, (LPCTSTR)strInfoTitle);
_tcscpy_s(m_sNTD.amp;szInfo[0], gsl::narrow<rsize_t>(strInfo.GetLength())   1, (LPCTSTR)strInfo);
_tcscpy_s(m_sNTD.amp;szTip[0], gsl::narrow<rsize_t>(strTip.GetLength())   1, (LPCTSTR)strTip);
 

Ответ №1:

Правильное место для amp; было бы:

 _tcscpy_s(amp;m_sNTD.szInfoTitle[0], gsl::narrow<rsize_t>(strInfoTitle.GetLength())   1, (LPCTSTR)strInfoTitle); 
_tcscpy_s(amp;m_sNTD.szInfo[0], gsl::narrow<rsize_t>(strInfo.GetLength())   1, (LPCTSTR)strInfo); 
_tcscpy_s(amp;m_sNTD.szTip[0], gsl::narrow<rsize_t>(strTip.GetLength())   1, (LPCTSTR)strTip); 
 

Но на самом деле вы используете _tcscpy_s неправильно. Второй параметр — размер буфера назначения, а не источника. _s функции должны быть безопасными, проверяя размер буфера; солгав об этом, вы нарушаете цель этой безопасности.

Просто опустите второй параметр и дайте ему быть выведенным, это также должно исправить предупреждение (действительно исправить, а не подавить):

 _tcscpy_s(m_sNTD.szInfoTitle, (LPCTSTR)strInfoTitle); 
_tcscpy_s(m_sNTD.szInfo, (LPCTSTR)strInfo); 
_tcscpy_s(m_sNTD.szTip, (LPCTSTR)strTip); 
 

Комментарии:

1. Спасибо за пояснения и исправления! Ошибался все эти годы!