locked
sscanf_s behavior puzzling RRS feed

  • Question

  • Windows 7, Visual Studio 2008, console app, C++ Here is a call to a method:

    ...........

       status = m_C_Client_TCP_Win_Api.Set_ip_address( "127.1.2.3", 49000 );

    ................

    Here is the method with code removed up to the problem point:

    .............

    bool C_Client_TCP_Win_Api::Set_ip_address( char * new_address,  unsigned short new_port )
    {   ...
        unsigned int octects[ 4 ];
        sscanf_status = sscanf_s( m_ip_address, "%d", &octects[ 0 ] );
        sscanf_status = sscanf_s( m_ip_address, "%d.%d", &octects[ 0 ], &octects[ 1 ] );
        sscanf_status = sscanf_s( m_ip_address, "%d.%d.%d", &octects[ 0 ], &octects[ 1 ], &octects[ 2 ] );
        sscanf_status = sscanf_s( m_ip_address, "%d.%d.%d.%d", &octects[ 0 ], &octects[ 1 ], octects[ 2 ], &octects[ 3 ] );
    

    .................

    The first three sscanf statement were added to better characterize the problem. The first two ran without a problem, putting the expected values in the integer array. The third one crashed. 

    Specifically, the last one, the original one, crashes with an access violation writting location 0x002. The code breaks at line number 1111 in module input.c at the following:

    ............

    if (longone)
         *(long UNALIGNED *)pointer = (unsigned long)number;
    

    .................

    Variable number contains the value 2 (two) so it is trying to write to address 0x002. However, it seems to me that this should not be the case. Trailing dots were added at the end of the IP address making it "127.1.2.3..." but the result is the same. In the debugger the execution point can be moved down to the next break statement and then stepped back out to the method Set_ip_address(). Then the values in the octects array are: 127, 1, 2, and 3. Just what they should be. A search turned up a thread stating that there is a size argument. The help file gets to this page: http://msdn.microsoft.com/en-us/library/t6z7bya3(VS.90).aspx It does not adequatly describe this new argument and has this statement:

    .................

    Unlike scanf and wscanf, scanf_s and wscanf_s require the buffer size to be specified for all input parameters of type c, C, s, S, or [. The buffer size is passed as an additional parameter immediately following the pointer to the buffer or variable. For example, if reading a string, the buffer size for that string is passed as follows:
    char s[10]; 
    scanf("%9s", s, 10); 
    

    ....................

    Does this mean that after each argument matching the %d there must be a size. What about when the size is unknown? I tried this, putting the size after each argument with a crash:

    ................

    sscanf_status = sscanf_s( m_ip_address, "%d.%d", &octects[ 0 ], 3 &octects[ 1 ], 1 );

    .................

    Putting the size at the end does like this does not work

    sscanf_status = sscanf_s( m_ip_address, "%d.%d.%d.%d", &octects[ 0 ], &octects[ 1 ], octects[ 2 ], &octects[ 3 ], sizeof( m_ip_address) );
     This is very puzzling.  Does anyone have a solution?

    I tried using the HTML formatting option and used angle brackets to surround the phrases pre and /pre.  That did not work worth a hoot so I put some dots in to demark the code and quotes.





    • Edited by JAG77 Sunday, October 6, 2013 3:44 AM formatting
    Sunday, October 6, 2013 3:28 AM

Answers

  • sscanf_status = sscanf_s( m_ip_address, "%d.%d.%d.%d", &octects[ 0 ], &octects[ 1 ], octects[ 2 ], &octects[ 3 ] );

    One of these arguments is not like the others, one of these just doesn't belong.

    Also, what's m_ip_address, and how, if at all, is it related to new_address?


    Igor Tandetnik

    • Marked as answer by JAG77 Sunday, October 6, 2013 2:26 PM
    Sunday, October 6, 2013 4:27 AM
  • I just want to point out two of the things you quoted.  From the manual:

    >Unlike scanf and wscanf, scanf_s and wscanf_s require the buffer size to be specified
    >for all input parameters of type c, C, s, S, or [.

    Then your question was:

    >Does this mean that after each argument matching the %d there must be a size.

    Now, since %d is not c, C, s, C or [, I hope it's clear you don't need a size.

    >What about when the size is unknown? 

    You always know the size of the buffers you're providing.  If you don't know the size of a string buffer, how can you possibly know how many characters you can stuff in there?

    By the way, did Igor's hint show you the problem?  You were missing a & in the 4th example.


    Tim Roberts, VC++ MVP Providenza & Boekelheide, Inc.

    • Marked as answer by JAG77 Sunday, October 6, 2013 2:26 PM
    Sunday, October 6, 2013 6:22 AM

All replies

  • sscanf_status = sscanf_s( m_ip_address, "%d.%d.%d.%d", &octects[ 0 ], &octects[ 1 ], octects[ 2 ], &octects[ 3 ] );

    One of these arguments is not like the others, one of these just doesn't belong.

    Also, what's m_ip_address, and how, if at all, is it related to new_address?


    Igor Tandetnik

    • Marked as answer by JAG77 Sunday, October 6, 2013 2:26 PM
    Sunday, October 6, 2013 4:27 AM
  • I just want to point out two of the things you quoted.  From the manual:

    >Unlike scanf and wscanf, scanf_s and wscanf_s require the buffer size to be specified
    >for all input parameters of type c, C, s, S, or [.

    Then your question was:

    >Does this mean that after each argument matching the %d there must be a size.

    Now, since %d is not c, C, s, C or [, I hope it's clear you don't need a size.

    >What about when the size is unknown? 

    You always know the size of the buffers you're providing.  If you don't know the size of a string buffer, how can you possibly know how many characters you can stuff in there?

    By the way, did Igor's hint show you the problem?  You were missing a & in the 4th example.


    Tim Roberts, VC++ MVP Providenza & Boekelheide, Inc.

    • Marked as answer by JAG77 Sunday, October 6, 2013 2:26 PM
    Sunday, October 6, 2013 6:22 AM
  • Hello Igor,

    The missing & was my problem.  I looked at this time and time again and failed to see that.  Its my own mistakes that frustrate me more than anything else. 

    Regarding the variable, I probably should have included these lines in the code.

      m_ip_port = new_port;
      strcpy_s( m_ip_address, MAX_IP_ADDRESS_LENGTH, new_address );

    Tim,

    I read your post a few times before I realized what you, and the docs were telling me.  The c,C s,S are as in %c, %s, etc.  Again, I looked and read but did not think along the right paths to get this right.

    This is embarrassing.

    Thank you both for taking the time to reply.


    ~jag77 We need to know what a dragon is before we study its anatomy. (Bryan Kelly, 2010) If you work with telemetry please visit this bulletin board: www.bkelly.ws/irig_106


    • Edited by JAG77 Sunday, October 6, 2013 2:29 PM formatting
    Sunday, October 6, 2013 2:26 PM