strtol strangeness?

I'm probably missing something very simple, perhaps I'm tired.

Why is it that the line of code

"DWORD DWordValue = 0xF988FA1F; "

places the proper hex value into the DWordValue variable (4186503711, 0xF988FA1F), but this line of code

"DWordValue = strtol("0xF988FA1F", NULL, 16);"

places the unanticipated value (2147483647, 0x7FFFFFFF)

Don't Long and DWORD size to 4 bytes What am I doing wrong

I am testing this because I need to read hex strings in from a file, and then write them as REG_DWORDs to registry sub-key named values. (Any easy ways to do that would also be useful).




Answer this question

strtol strangeness?

  • Cush

    Wow.

    Glad I could help.

    I tried this on 2 different compilers (and implementations of CRT), and the other implementation was not returning values as documented (either).

    The CRT documentation (in either implementation) is not written quite to the necessary clarity (but enough for most of the commonly encountered situations).



  • michael aird

    Great find, once again. errno is not a reliable error check if arbitary things can happen between the error and the check, which seems to be what's happening in the service call.  Without knowing too much about how it was implemented, it looks like design flaw.  As a straightforward workaround, I would reset errno back to 0 yourself after calling strto(u)l, using _set_errno .  Or you could restore it with the previous value from _get_errno.

    Why is the errno not being cleared   I don't think that's the situation here: strto(u)l sets it and the service calling code reads it blindly.  errno should be cleared on functions prior to setting it.  The fact that strto(u)l isn't doing it is probably a bug.

    Note that the secure CRT in VS2005 does away with this obviously unsafe errno and redesigns functions to directly return error codes.

    Brian

     


  • Simon Gorski

    So here's an intersting problem that has caused me much heartache today.

    I have a C# webservice that I call from a VS2005 C++ app.

    if I make a service call it works fine as expected.

    If I add the following lines before the call, the call fails (HRESULT = E_FAIL)

    char *p;

    long lVal= strtoul("8e9dc962", &p, 16);

    After a lot of testing, I found the same thing as you describe with strtol not liking any eight digit hex number beginning with 8 or greater.

    If I use strtoul it works fine and the service call succeeds.

    SO...does anyone know what the heck strtol is doing to corrupt my code. I understand the overlfow, but it is suposed to handle it. It almost seems like it may be corrupting the stack.

    Bill


  • JonnyAJAX

    All I know is that that this morning while adding a new service to my site and updating a product to talk to it, all was fine. Later I added another call and, low and behold, the call failed. I even tried calling the one that worked previously. it also stopped working. I had tried several things to isolate the problem to include stepping into the soap calls where it was failing. still had no idea why. Out of desperation, i started doing the old comment out a line at a time trick. ...and what do you know, strtol seems to be the culprit. If I leave the strtol call in and use any number less than 0x80000000, all is fine. The instant I use a larger number, the service call fails. Oh, and by the way, this number/string has nothing to do with the call…as in it is not passed to it. When I change to the unsigned version, it works like a charm.


  • Calvin Bell

    The function is parsing the digits as a 32-bit signed value, but unfortunately, the bit in position 32 is treated as the value 2^31 rather than a sign bit.  So an overflow occurs, and LONG_MAX is returned (consistent with documentation). 

    The sign bit is only set when the input string begins with the '-' character.  As a workaround in your case, use strtoul as described by Bill later in this thread.

    A tip: the exact behavior of CRT functions can often be learned by using the debugger to step through the source code, which is shipped with Visual Studio.  Set a breakpoint on strtol, and do "step-into" to dig down into its workings.

    Brian


  • GS80

    Sounds like you have an incentive to migrate to the Secure CRT. I cannot find the replacement for strtol, unfortunately. That could have been an oversight on Microsoft's part. (In general, errno is no longer used in the Secure CRT).
  • Oren Novotny

    Ok Brian, I suppose I should thank you for giving me the incentive to investigate this further. I made a local copy of the strtol function and called it. Same result, the service call works if the number is less than 0x80000000 and fails when it is greater.

    The actual CRT function is strtoxl. Towards the bottom of the function is the validation code that looks like this:

    if (!(flags & FL_READDIGIT)) {

    /* no number there; return 0 and point to beginning of

    string */

    if (endptr)

    /* store beginning of string in endptr later on */

    p = nptr;

    number = 0L; /* return 0 */

    }

    else if (((flags & FL_OVERFLOW) ||

    ( !(flags & FL_UNSIGNED) &&

    ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||

    ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) ))

    {

    /* overflow or signed overflow occurred */

    errno = ERANGE;

    if ( flags & FL_UNSIGNED )

    number = ULONG_MAX;

    else if ( flags & FL_NEG )

    number = (unsigned long)(-LONG_MIN);

    else

    number = LONG_MAX;

    }

    You will note the “else if” condition where it checks for negatives and values exceeding LONG_MAX, which our culprit numbers do. If it does, it sets errno to ERANGE. THAT IS THE UNDERLYING PROBLEM!

    If I remove all calls to strtol and simply insert the line:

    errno = ERANGE;

    immediately before any service call, the service call fails.

    So, the next question is why is errno not being cleared and causing the following soap call to return E_FAIL.

    __atlsoap_hr = SendRequest(_T("SOAPAction:\"http://mywebsitename/GetServerDateTime\"\r\n"));

    if (FAILED(__atlsoap_hr))

    {

    goto __skip_cleanup;

    }


  • Darko01

    Bugs should be submitted to the Visual Studio feedback site. This way you can live with a clean conscience that you didn't keep this issue all to yourself, and future users will benefit. :)
  • Alan Robbins

    I have been avoiding that ever since I ported this app to VS2005! This app is HUGE and unfortunately the change to the secure CRT is not a mindless search and replace in most cases.

    Well, looks like I now have a reason (other that all the deprecated warnings)!


  • Yogendran

    Good find.  To the OP, strtoul is what you should be using. EDIT: CHANGED WORKAROUND IN MY FIRST POST.

    As for your issue, Bill, I'm afraid you're not giving enough context.  Are you claiming that strtol itself is corrupting the stack   Or is this just a logical bug stemming from the invalid parsing of the input string The former seems unlikely, especially with the stack overflow (unrelated to the overflow we've been discussing) checking employed in VS 2003 and VS 2005.


  • Jay S

    Definitely weird, and I can only make wild speculations. This could be a bug in strtol, or it could be some pathological interaction between the CRT and the service call mechanism (maybe it sets some global error condition), or it could be a bug somewhere else in your code that somehow becomes symptomatic only when strtol is called (e.g. a particular location in the stack looks different, and the erroneous code is reading from this stack location).   If it were me, I'd continue down the path of understanding exactly how strtol is causing the failure by copying the source code (call it my_strtol), verifying that it also reproduces the problem, and then pruning it down, especially in the code path that deals with the overflow case. 


  • SSreejith

    Brian, the problem is that I have no control over the soap code which is auto generated by VS2005 when I select “add web reference”. The header file which defines the interface class and all soap calls is generated for me. Sure, I could modify it, but if I do so and need to update the web reference as changes are made to my service, my changes would be lost and I would need to redo them.

    The problem is that I stumbled upon this by chance…thank God. The hex number I have been talking about is an ID generated from my site and sent to the customer which they, in turn, must provide before the service call is made. Had I picked just about any other value I have in the DB (less than our magical 0x8+) I never would have found this and at some point in the future I would get a rather pithy email/call from a customer wondering why our SW was broken.

    So, now that I know what is causing this, the errno condition, I am even more concerned because, theoretically, any CRT function called anywhere prior to my service call that set errno could cause the sendrequest to fail. This is disturbing to say the least. I guess my only workaround right now is to manually set errno to 0 just prior to all service calls. That’s fine, but the question remains, what other unforeseen things does this effect

    Sure seems like a bug to me.


  • strtol strangeness?