Home > Back-end >  sscanf_s function throwing exception
sscanf_s function throwing exception

Time:03-29

I am trying to use sscanf_s function but it is throwing below exception

Exception thrown at 0x00007FFAE5C92079 (ucrtbased.dll), .exe: 0xC0000005: Access violation writing location 0x0000000287310000.

Kindly help!

char* f_cUTCDateTime_i = "20220212114700.111111-0530";    
char f_pchDateFormat_i[DICOM_DATE_LEN] = { 0 };
char f_pchTimeFormat_i[DICOM_TIME_LEN] = { 0 };
    
sscanf_s(f_cUTCDateTime_i, "%8ss", f_pchDateFormat_i, f_pchTimeFormat_i);

I tried to pass the parameters as a reference as well as a string still got same exception .

CodePudding user response:

If you'd like sscanf_s to parse character strings, each string variable should be accompanied by the allocated buffer length.

In your case it should be something like:

sscanf_s(f_cUTCDateTime_i, "%8ss", f_pchDateFormat_i, DICOM_DATE_LEN, f_pchTimeFormat_i, DICOM_TIME_LEN);

The access violations occures because the 2nd string variable (f_pchTimeFormat_i) is wrongly interpreted to be the length of the buffer of the 1st string variable (f_pchDateFormat_i)

This is at least the behavior on MSVC. That being said, I join question why use old C strings and C api instead of modern C strings and functions.

CodePudding user response:

#include <string>
#include <iostream>

// ...something defining DICOM_DATE_LEN and DICOM_TIME_LEN...
// In lieu of that:
unsigned const DICOM_DATE_LEN = 8;
unsigned const DICOM_TIME_LEN = 13;

int main()
{
    std::string UTCDateTime = "20220212114700.111111-0530";
    std::string DateFormat = UTCDateTime.substr( 0, DICOM_DATE_LEN );
    std::string TimeFormat = UTCDateTime.substr( DICOM_DATE_LEN, DICOM_TIME_LEN );

    std::cout << "DateFormat: " << DateFormat << "\n"
              << "TimeFormat: " << TimeFormat << std::endl;
}

Output:

DateFormat: 20220212
TimeFormat: 114700.111111

And yes, the renaming of the variables is part of the answer. System Hungarian has been deprecated by Microsoft themselves many years ago, and had no place in any strongly typed language in the first place. Don't use it.

CodePudding user response:

First rule when using some function: Read docuemntation

Remarks

The sscanf_s function reads data from buffer into the location that's given by each argument. The arguments after the format string specify pointers to variables that have a type that corresponds to a type specifier in format. Unlike the less secure version sscanf, a buffer size parameter is required when you use the type field characters c, C, s, S, or string control sets that are enclosed in []. The buffer size in characters must be supplied as an additional parameter immediately after each buffer parameter that requires it. For example, if you are reading into a string, the buffer size for that string is passed as follows:

C

wchar_t ws[10];
swscanf_s(in_str, L"%9s", ws, (unsigned)_countof(ws)); // buffer size is 10, width specification is 9

The buffer size includes the terminating null. A width specification field may be used to ensure that the token that's read in will fit into the buffer. If no width specification field is used, and the token read in is too big to fit in the buffer, nothing is written to that buffer.

Second thing use warning as errors so compiler reports an error when format string is used incorrectly with arguments: https://godbolt.org/z/K7cKohGq7

example.cpp
<source>(12): error C2220: the following warning is treated as an error
<source>(12): warning C4477: 'sscanf_s' : format string '%8s' requires an argument of type 'unsigned int', but variadic argument 2 has type 'char *'
<source>(12): note: this argument is used as a buffer size
<source>(12): warning C4473: 'sscanf_s' : not enough arguments passed for format string
<source>(12): note: placeholders and their parameters expect 4 variadic arguments, but 2 were provided
<source>(12): note: the missing variadic argument 3 is required by format string 's'
<source>(12): note: this argument is used by a conversion specifier

Last thing when asking question you should specify what kind of problem it solves. Then you can get a better solution then yours. You are doing some parsing, but details are elusive so it is hard to propose something more robust which is more like C not C.

    std::istringstream data{"20220212114700.111111-0530"};
    std::tm t;
    data >> std::get_time(&t, "%Y%m%d%H%M%S");

https://godbolt.org/z/e8e5eYKP9

  • Related