inlandchris1 Ответов: 3

Как избавиться от этого предупреждения C6385 считывание недопустимых данных


Предупреждение C6385 чтение недопустимых данных из 'CRdr': читаемый размер составляет '(unsigned int)*108+4' байт, но '216' байт могут быть прочитаны.
struct CReaders
{
	int		m_IntAddr{};//Card Reader number in ASC not HEX. CARD READER TABLE
	CStringA	m_HexAddr = _T("");//Card Reader Address in Hex, LAST Octet
	CStringA	m_Loc	= _T("");//Location of Card Reader, Text Description
	CStringA	m_Desc 	= _T("");//Description of Card Reader, Additional Text
	int		m_BUS{};	//WHICH COM PORT IS BEING USED
	BOOL		m_ELEVATOR{};
	CStringA	m_CmdLv = _T("");//max of "CMD_MAX"=15 command levels
	int		m_CmdLvInt[CMD_MAX]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//integer
	BOOL		m_VOID{};
	int		m_Type{};	//reader module motherboard type
volatile BOOL		m_GOOD_CHK{};	//USED ONLY IN OMU2 AND CHECKING
	BOOL		m_DISPLAY{};	//FOR USE IF L9 OR L10 DEVICES TO USE
	BOOL		m_DISPLAY_OFFLine{};//FOR DISPLAYING ON THE TRANSACTION 
};


//DB opened and start reading; how many records
  		m_ReaderSet->MoveFirst();
		do
		{
			m_ReaderCount++;	//unsigned int
			m_ReaderSet->MoveNext();
		}while(!m_ReaderSet->IsEOF());
	
		if(m_ReaderCount > READERS_MAX)
			m_ReaderCount = READERS_MAX;


		//if memory is inside CRdr, delete it
		if(CRdr)
			delete [] CRdr;
		CRdr = 0;
		CRdr = new  CReaders[m_ReaderCount+10];
		// INIT STRUCT TO ZERO //ONE BASED HERE! STARTS AT 1  

	for(c=0;c<=(int)m_ReaderCount+1;c++)
	{
		CRdr[c].m_BUS		= 0;
		CRdr[c].m_ELEVATOR	= FALSE;
		CRdr[c].m_GOOD_CHK	= TRUE;
		CRdr[c].m_IntAddr	= 0;
		CRdr[c].m_Type		= 0;
		CRdr[c].m_VOID		= FALSE;
		CRdr[c].m_DISPLAY	= FALSE;
		CRdr[c].m_DISPLAY_OFFLine= FALSE;
		CRdr[c].m_Loc	        = _T("");//Warning C6385 is here, 
 		CRdr[c].m_HexAddr	= _T("");
		CRdr[c].m_CmdLv		= _T("");
 		CRdr[c].m_Desc		= _T("");
	}

CStringA упаковывает до 8 бит. Столбец для m_Loc-это nvarchar(50), null в БД. В
программа, ее вытащили через CStringA:
RFX_Text(pFX, _T("[Loc]"), m_Loc); //m_Loc-это CStringA

Мой вопрос таков: как мне удалить это предупреждение?

Компилятор VS2019-это "все предупреждения", и я обнаружил это с помощью инструмента Analize на VS2019.
Компилятор настроен на "использование Многобайтового набора символов"
Компилятор не знает БД, поэтому 50 nvarchar неизвестны компилятору.
Я ничего не могу сделать с CStringA в структуре, кроме
инициализируйте его нулем или ничем.
Хотел установить его предел, но не может быть не во время инициализации. Я могу "освободить буфер, установить предел" позже, но это не избавит от предупреждения.

Компилятор использует стандартную 8 - битную упаковку для структур.
Я хотел бы дать больше кода, но это часть кода в 300 000 строк, который я сделал. Программа работает нормально и работает уже много лет но это самое главное
последнее раздражение, с которым я хотел бы справиться, но не знаю как, есть какие-нибудь подсказки?
Это один из примеров:
У меня есть 10 других структур с CStrings в качестве членов, которые имеют те же предупреждения.

Еще одна структура использует CTime m_EndSched{}; в качестве члена и получает такое же предупреждение.

Предупреждение C6385 чтение недопустимых данных из 'SchdLvl': читаемый размер составляет '(unsigned int)*100+4' байт, но '200' байт могут быть прочитаны.
ДБ=конечная дата(дата-время,значение null)

Самое последнее средство изменить все CStrings на char, но это означает использование sprintf/scopy/strcat/sprintf_s (который скоро будет запрещен)или команды format на CString в обратном порядке.



Что я уже пробовал:

Я пытался ввести CString в структуру, но это незаконно. Я попытался упаковать до 2,4,8,16 бит с помощью #pragma pack(n) или в самом компиляторе. Я попытался "освободить установленный предел" для CString позже в коде, но компилятор все еще имеет предупреждение.

Rick York

Нет, функции sprintf, strcpy, в функции strcat и не забанит, и не будет МНОГОБАЙТОВОЙ кодировки. Это стандартные библиотечные функции, и Microsoft не имеет права запрещать их использование в библиотеке.

Если они действительно удаляют их из RTL VS, то вы можете использовать свои собственные реализации из них. Я уверен, что там будет из чего выбирать.

inlandchris1

Спасибо тебе за это. У меня сложилось впечатление, что их планировалось удалить из-за страха перед вирусом. Я сделаю мысленную заметку.

KarstenK

возможным решением является использование массива TCHAR подходящего размера. А для петли пределы выглядят странно.

inlandchris1

Ну, это хорошая идея, но это та же самая энергия, чтобы заменить все CStrings на chars [?], просто много работы, но это мое последнее средство, спасибо за ответ

inlandchris1

Я согласен с циклом, просто хотел выделить больше, чем мне нужно, чтобы предотвратить переполнение, но на самом деле все, что мне нужно, - это еще 1 на распределение.

3 Ответов

Рейтинг:
7

inlandchris1

Рик й., спасибо вам за ваше решение. Я не думал вне коробки об инициализации членов, мышление на языке " С’, а не на C++. Я не знал, что вы можете поместить функции внутри структуры, но когда вы действительно думаете о том, что C++ - это гигантская структура, все держится крепко. Я проверил это, и это работает как лучший способ инициализации структур! Но я все равно получаю то же самое предупреждение о CString. Я попытался сделать предварительное выделение 200 в инициализации структуры, но это не остановило предупреждения. БД показывает ширину 50 nvarchars, а в пакете struct из 8 символов char стоит 4, умножая 50=200.
Это самый эффективный метод инициализации, который я когда-либо видел, и я хочу поблагодарить вас за то, что вы поделились им, очень ценю его.
Функция .clear (), которую вы используете для CStrings, которых у меня нет. Я считаю, что это метод “using namespace System”, который я не использую в компиляторе /clr. Поэтому я просто опускаю inits на CStrings и просто предварительно распределяю CStrings.
Выделение "нового" плюс 10 было всего лишь глупым страхом переполнения переменной, переключенным обратно на вашу идею +1, которая является лучшей идеей.
Спасибо,
Крейг К.


Rick York

clear() является членом std::basic_string - я забыл, что вы используете CString, и я никогда не использую его. Я считаю, что у него есть метод Empty (), который будет делать то же самое, но он должен быть создан пустым, поэтому в нем нет необходимости.

Кстати - это должно быть опубликовано как комментарий к моему посту, а не другое решение, точно так же, как я отвечаю на ваш.

inlandchris1

Мне любопытно, почему вам не нравится CString(). Я заглянул в string (), и у него не так много функций, как у CString, но есть ли проблема с производительностью?

Rick York

Я работаю с большим количеством STL и внутренних библиотечных материалов, и я решил выбрать один класс string и придерживаться его. Это не правда, что мне это не нравится. Просто я стараюсь избегать всех коллекций MFC и шаблонных классов и вместо этого использую STL-вещи.

inlandchris1

Спасибо. MFC почти исчез с 2010 года, но я запустил эту программу в 2008 году и теперь застрял с ней для ремонта и обновления в качестве обновления Windows. Скоро никаких обновлений в программе больше не будет, так как MFC навсегда исчезнет. Слишком плохо, много программ для этого одного работодателя; около 500 000 строк старого кода.

inlandchris1

Рик, О'Кей, наконец-то нашел проблему с чтением недопустимых данных из структуры. У меня был дополнительный член CString, который я не использовал и не инициализировал. Это, по-видимому, мешало некоторым другим членам быть CString или char*, впервые увидев это, но с радостью получив его. Структуры должны быть плотными, без провисания, просто я подумал, что передам это дальше.

Рейтинг:
18

Rick York

Дело в том, что вам не нужно делать большинство вещей, которые вы делаете с этими строковыми членами. Он уже инициализирован, чтобы быть пустым, поэтому инициализатор не нужен. У него есть четкий метод, так что вы можете вызвать его вместо того, чтобы назначать ему пустую строку.

Кроме того, эти строки не имеют смысла :

    CRdr = new  CReaders[m_ReaderCount+10];
    // INIT STRUCT TO ZERO //ONE BASED HERE! STARTS AT 1

for(c=0;c<=(int)m_ReaderCount+1;c++)
потому что вы не инициализируете все данные. Зачем выделять его, если он не будет использоваться? Лучшим способом сделать это было бы :
 // determine exactly how many will be used
int readersUsed = m_ReaderCount + 1;  // or what ever that should be
readers = new CReaders[ readersUsed ];
for( c = 0; c < readersUsed; ++c )
   readers[ c ].Initialize();
По-видимому, у вас есть произвольные значения для числа считывателей, а затем для числа инициализируемых устройств. Это должны быть те самые ТАКОЙ ЖЕ число, что бы это ни было.

Примечание - я использовал метод Initialize класса CReader, потому что он нужен, если у вас нет его инициализаторов, настроенных так, как они должны быть.

-edit - вот как я бы это сделал :
struct CReaders
{
    CStringA    m_HexAddr;   //Card Reader Address in Hex, LAST Octet
    CStringA    m_Loc;       //Location of Card Reader, Text Description
    CStringA    m_Desc;      //Description of Card Reader, Additional Text
    CStringA    m_CmdLv;     //max of "CMD_MAX"=15 command levels
    int         m_CmdLvInt[ CMD_MAX ];
    int         m_IntAddr;   //Card Reader number in ASC not HEX. CARD READER TABLE
    int         m_BUS;       //WHICH COM PORT IS BEING USED
    int         m_Type;      //reader module motherboard type
    BOOL        m_ELEVATOR;
    BOOL        m_VOID;
    BOOL        m_GOOD_CHK;  //USED ONLY IN OMU2 AND CHECKING
    BOOL        m_DISPLAY;   //FOR USE IF L9 OR L10 DEVICES TO USE
    BOOL        m_DISPLAY_OFFLine;  //FOR DISPLAYING ON THE TRANSACTION 

    CReaders()
    {
        Initialize();
    }

    void Initialize()
    {
        m_HexAddr.Empty();
        m_Loc.Empty();
        m_Desc.Empty();
        m_CmdLv.Empty();

        for( inr n = 0; n < CMD_MAX; ++n )
            n_CmdLvInt[ n ] = 0;

        m_IntAddr         = 0;
        m_BUS             = 0;
        m_Type            = 0;
        m_ELEVATOR        = FALSE;
        m_VOID            = FALSE;
        m_GOOD_CHK        = TRUE;
        m_DISPLAY         = FALSE;
        m_DISPLAY_OFFLine = FALSE;
    }
};
эта схема инициализирует данные в конструкторе


Рейтинг:
0

OriginalGriff

Проверьте значение CMD_MAX - на первый взгляд это 108 + 4 байта (то есть 28 32-битных целых чисел), а фактический необходимый размер больше.


inlandchris1

CMD_MAX-это только #define (был, теперь его "constexpr auto") 15, что означает максимум 15 для этого массива.
Я предполагаю, что 108+4-это CString, потому что то, что нужно, - это 200, а nvarchar(50) - это символ длиной 50. Символ имеет длину 4 байта 50 == 200. Итак, анализируемая часть VS2019 действительно прочитала БД и обнаружила, что она может читать до 200. Но почему CString ограничен 108+4?

OriginalGriff

"Символ имеет длину 4 байта"

Откуда у тебя такая идея?
Символ char-это либо 1 байт, либо 2 байта в зависимости от определения _UNICODE в параметрах компиляции ...

inlandchris1

Да, хороший ответ, это уплотнение в структуре, когда компилятор установлен на 8, как то, о чем я писал. Выбор-это выбор из: 2,4,8,16. Значение по умолчанию равно 8 и делает символ равным 4, хорошо?