UB, or a stupid mistake, or both? 
Author Message
 UB, or a stupid mistake, or both?

Hello,
I made a stupid mistake this morning, as follows:
(fragment only)

char *MakeDate(char *week_start, int day)
{
    static char date[11];
/*some time processing here*/
    return date;

Quote:
}

char *MakeTimeString(char *time)
{
    static char tm_string[6];
/*reformatting a time string here*/
    return tm_string;

Quote:
}

char *TimeOrDuration(char *start, char *duration)
{
    static char duration_string[10];
/*stuff the difference between two times into
duration_string if duration is a time*/
    return duration_string;

Quote:
}

long CatTimeTableExt(char **time_table, char *week_start,
        char *auft_time1, char *auft_duration1,
        char *auft_time2, char *auft_duration2,
        long index)
{
    char ret_txt[<some size>];

    sprintf(ret_txt, "*%s|%s|%s|%s|%s",
            MakeDate(week_start, index),
            MakeTimeString(auft_time1),
            TimeOrDuration(auft_time1, auft_duration1),
            MakeTimeString(auft_time2),
            TimeOrDuration(auft_time2, auft_duration2));
    if(index == 1)
    {
        strcpy(*time_table, ret_txt);
        return 0;
    }
    else  strcat(*time_table, ret_txt);
    return 1;

Quote:
}

This does not give the expected result of course,
and I could easily fix it.
What I wonder is:
Is this UB due to
"an object shall have it's value modified at most....."
IOW can there be a conforming implementation which _gives_ the
expected
result, or is it just a stupid mistake
(OK invoking UB is a stupid mistake as well :-)

Thank you for reading and kind regards

-- .
Robert Stankowic



Fri, 06 Feb 2004 21:48:43 GMT  
 UB, or a stupid mistake, or both?

Quote:

>Hello,
>I made a stupid mistake this morning, as follows:
>(fragment only)

<snip>

[MakeDate, MakeTimeString, and TimeOrDuration all modify and return a
pointer to a static array of char]

Quote:
>    sprintf(ret_txt, "*%s|%s|%s|%s|%s",
>            MakeDate(week_start, index),
>            MakeTimeString(auft_time1),
>            TimeOrDuration(auft_time1, auft_duration1),
>            MakeTimeString(auft_time2),
>            TimeOrDuration(auft_time2, auft_duration2));
>This does not give the expected result of course,
>and I could easily fix it.
>What I wonder is:
>Is this UB due to
>"an object shall have it's value modified at most....."

This doesn't apply here, because there is a sequence point at the end
of each function just before it returns, so none of the static arrays
have their contents modified more than once between sequence points.

The order in which their contents are modified (and, because of this,
which call's results actually get printed), though, depends on the
order in which the function's arguments are evaluated, which is
unspecified (and, therefore, can be anything the implementation wishes
and need not be documented or consistent), so this has the effect of
being well-defined but completely unpredictable (except that it won't
blow your computer up or make demons fly out of your nose, and in
practice for a given implementation it's even likely to be the same
every time).

Quote:
>IOW can there be a conforming implementation which _gives_ the
>expected
>result, or is it just a stupid mistake

I can't see any way for a conforming implementation to give the
expected result, but I'm not a language lawyer (at least not much of
one).

Quote:
>(OK invoking UB is a stupid mistake as well :-)

That depends how and why you invoke UB; I've invoked UB in almost all
the code I've written recently, by calling functions provided by the OS
that aren't defined by ISO C, but the net result of that is that the
program does something that it's supposed to be doing but that can't be
done by code that doesn't invoke UB.

dave

--

Quote:
> which bit of "Can we just not go there again please" did not make sense?

I think it was the "please" that threw me.
                     --Mark McIntyre and Richard Heathfield in comp.lang.c


Fri, 06 Feb 2004 22:58:43 GMT  
 UB, or a stupid mistake, or both?

Quote:

>I made a stupid mistake this morning [...

 snipped: functions that return &staticbuf[0] after writing text into
 the static buffer]

[more code snippts, now using those functions]

Quote:
>    sprintf(ret_txt, "*%s|%s|%s|%s|%s",
>            MakeDate(week_start, index),
>            MakeTimeString(auft_time1),
>            TimeOrDuration(auft_time1, auft_duration1),
>            MakeTimeString(auft_time2),
>            TimeOrDuration(auft_time2, auft_duration2));

[end of code snippets]

Quote:
>This does not give the expected result of course,
>and I could easily fix it.  What I wonder is:
>Is this UB due to
>"an object shall have it's value modified at most....."
>IOW can there be a conforming implementation which _gives_ the
>expected
>result, or is it just a stupid mistake
>(OK invoking UB is a stupid mistake as well :-)

You might ask on comp.std.c to get a more detailed or precise
answer, but I think the answer is: this is not undefined behavior;
this is "unspecified behavior".

There are two function calls to (e.g.) MakeTimeString in the
one function call to sprintf() above.  The standard gives no
guarantees as to which call is done first, but, because there
is a sequence point before the call, and another sequence point
after the return statement inside MakeTimeString, each of the
two calls to MakeTimeString "appears atomic", as it were.  In
other words, one of the two MakeTimeString calls appears to
occur first, and run to completion, before the other call to
MakeTimeString even begins.

(In a computer in which the C compiler automatically parallelizes
such expressions, you could say that each paralleled function call
must first obtain a functions-specific semaphore or mutex, releasing
it only after the call completes.  If a called function were to
modify a shared -- say, file-scope -- variable, it would have to
obtain an even wider-scope semaphore or mutex, to give the illusion
of single-threaded behavior.)

That means that either the lexically-first MakeTimeString call
"starts and finishes first" and the lexically-second call then
runs, or else the lexically-second MakeTimeString call runs first,
then the lexically-first runs second.

In either case, both calls return the same value (&staticbuf[0]).

Finally, after all of the sub-expressions to be passed to sprintf()
have been evaluated, there is yet another sequence point, and then
sprintf() runs.  Since both calls to MakeTimeString returned the
same value, sprintf will obtain the same string twice for each of
the two "%s" directives.  The string obtained depends on whether
the lexically-first MakeTimeString call actually occurred first,
and the actual order of such calls is unspecified.
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)




Sat, 07 Feb 2004 06:12:11 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. Destructor called twice. -- Resolved (stupid mistake)

2. Stupid Stupid Bug with _spawnl

3. You be (UB) or not you be

4. clrscr and UB

5. reverse string - UB

6. Scary UB

7. Converting unsigned char to signed char invokes UB?

8. String literals and UB

9. still UB?

10. mistake in code of sample duwamish.

11. MISTAKE mystery code

12. Any obvious mistakes in this code fragment? (ptrs)

 

 
Powered by phpBB® Forum Software