some doubts on undefined behaviour

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • destination
    New Member
    • Dec 2009
    • 34

    some doubts on undefined behaviour

    struct X
    {
    int x,y;
    char c;
    };

    main()
    {
    struct X x,*px;
    px=&x;
    printf("%d",*px );
    }

    I think the above piece of code printf produces a UB since it is expecting and we are providing it with a variable of type struct X.
    i just need a confirmation on this so that i can post some more doubt on UB.
  • destination
    New Member
    • Dec 2009
    • 34

    #2
    since it is expecting a typo
    actually i wanted to write since it is expecting an int.

    Comment

    • Banfa
      Recognized Expert Expert
      • Feb 2006
      • 9067

      #3
      I think you are correct because the compiler is free to pass parameters in pretty much anyway it chooses and I know that some compilers I have used use completely separate methods to pass basic types (like int) and compound types (such as structs). If the compiler was expecting an int and was passed a struct then it would look in the wrong place and quite possibly at an invalid memory location for the data.

      Comment

      • donbock
        Recognized Expert Top Contributor
        • Mar 2008
        • 2427

        #4
        Originally posted by C99, section 6.7.2.1, #13
        Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (of if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
        Originally posted by C99, section 6.3.2.3, #7
        A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.
        The function call in question is printf(). This function is something of a special case, its prototype only specifies the type of the first argument. All other arguments go through the default argument promotions. I couldn't find a clear statement of precisely what the default argument promotion is for pointers, but odds are it "erases" the distinction between a pointer-to-struct and a pointer-to-int.

        Although ill-advised, I believe the code posted by the OP is not undefined behavior.

        Comment

        • destination
          New Member
          • Dec 2009
          • 34

          #5
          Tell me if these are UB or not
          printf("%d",9.9 );//expecting int iam passing float.
          printf("%f",5);//expecting float iam passing int.
          printf("%c",3.3 );//expecting character iam passing float.

          I think default arguement promotion will take place in the above statement.
          Tell me whether default argument promotion will take place or not.If no then why??

          Comment

          • weaknessforcats
            Recognized Expert Expert
            • Mar 2007
            • 9214

            #6
            Considering that printf has only two arguments and the one for your variable is ..., then how do you expect promoitions to take place?

            The code for printf() is public domain. Look at the code yourself and answer your question.

            Comment

            • destination
              New Member
              • Dec 2009
              • 34

              #7
              The code for printf() is public domain.
              Could not understand what did you mean?

              Comment

              • weaknessforcats
                Recognized Expert Expert
                • Mar 2007
                • 9214

                #8
                That means the code for printf is probably on your computer right now as part of your compiler installation. When you make debug builds, come compilers have the coode for the C library avaiable so tio can be compiled with debugger info inserted.

                The code varies by compiler.

                Here is the code from Visual Studio.NET 2008:

                Code:
                /***
                *printf.c - print formatted
                *
                *       Copyright (c) Microsoft Corporation. All rights reserved.
                *
                *Purpose:
                *       defines printf() - print formatted data
                *
                *******************************************************************************/
                
                #include <cruntime.h>
                #include <stdio.h>
                #include <dbgint.h>
                #include <stdarg.h>
                #include <file2.h>
                #include <internal.h>
                #include <mtdll.h>
                #include <stddef.h>
                #include <process.h>
                
                /***
                *int printf(format, ...) - print formatted data
                *
                *Purpose:
                *       Prints formatted data on stdout using the format string to
                *       format data and getting as many arguments as called for
                *       Uses temporary buffering to improve efficiency.
                *       _output does the real work here
                *
                *Entry:
                *       char *format - format string to control data format/number of arguments
                *       followed by list of arguments, number and type controlled by
                *       format string
                *
                *Exit:
                *       returns number of characters printed
                *
                *Exceptions:
                *
                *******************************************************************************/
                
                int __cdecl printf (
                        const char *format,
                        ...
                        )
                /*
                 * stdout 'PRINT', 'F'ormatted
                 */
                {
                        va_list arglist;
                        int buffing;
                        int retval;
                
                        _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
                
                        va_start(arglist, format);
                
                        _lock_str2(1, stdout);
                        __try {
                
                        buffing = _stbuf(stdout);
                
                        retval = _output_l(stdout,format,NULL,arglist);
                
                        _ftbuf(buffing, stdout);
                
                        }
                        __finally {
                            _unlock_str2(1, stdout);
                        }
                
                        return(retval);
                }
                
                int __cdecl _printf_l (
                        const char *format,
                        _locale_t plocinfo,
                        ...
                        )
                {
                    va_list arglist;
                
                    va_start(arglist, plocinfo);
                
                    return _vprintf_l(format, plocinfo, arglist);
                }
                
                
                int __cdecl _printf_s_l (
                        const char *format,
                        _locale_t plocinfo,
                        ...
                        )
                {
                    va_list arglist;
                
                    va_start(arglist, plocinfo);
                
                    return _vprintf_s_l(format, plocinfo, arglist);
                }
                
                int __cdecl printf_s (
                        const char *format,
                        ...
                        )
                {
                    va_list arglist;
                
                    va_start(arglist, format);
                
                    return _vprintf_s_l(format, NULL, arglist);
                }
                
                int __cdecl _printf_p_l (
                        const char *format,
                        _locale_t plocinfo,
                        ...
                        )
                {
                    va_list arglist;
                
                    va_start(arglist, plocinfo);
                
                    return _vprintf_p_l(format, plocinfo, arglist);
                }
                
                int __cdecl _printf_p (
                        const char *format,
                        ...
                        )
                {
                    va_list arglist;
                
                    va_start(arglist, format);
                
                    return _vprintf_p_l(format, NULL, arglist);
                }
                
                static UINT_PTR __enable_percent_n = 0;
                
                /***
                 *int _set_printf_count_output(int)
                 *
                 *Purpose:
                 *   Enables or disables %n format specifier for printf family functions
                 *
                 *Internals:
                 *   __enable_percent_n is set to (__security_cookie|1) for security reasons;
                 *   if set to a static value, an attacker could first modify __enable_percent_n
                 *   and then provide a malicious %n specifier.  The cookie is ORed with 1
                 *   because a zero cookie is a possibility.
                 ******************************************************************************/
                int __cdecl _set_printf_count_output(int value)
                {
                    int old = (__enable_percent_n == (__security_cookie | 1));
                    __enable_percent_n = (value ? (__security_cookie | 1) : 0);
                    return old;
                }
                
                /***
                 *int _get_printf_count_output()
                 *
                 *Purpose:
                 *   Checks whether %n format specifier for printf family functions is enabled
                 ******************************************************************************/
                int __cdecl _get_printf_count_output()
                {
                    return ( __enable_percent_n == (__security_cookie | 1));
                }

                Comment

                • donbock
                  Recognized Expert Top Contributor
                  • Mar 2008
                  • 2427

                  #9
                  The prototype for printf() is part of the C Standard, hence it should be readily available to you.

                  There are several open-source C compilers, gcc is the obvious example. You can obtain the source code for their implementation of printf.

                  On the other hand, that may not be necessary. The default argument conversions are controlled solely by the prototype and your invocation of the function. It is a safe bet that printf uses stdarg.h to obtain its parameters. Refer to the stdarg documentation to try and infer what happens for the type mismatches you propose.

                  What is prompting you to ask about these pathological cases?

                  Comment

                  • Banfa
                    Recognized Expert Expert
                    • Feb 2006
                    • 9067

                    #10
                    Originally posted by bonbock
                    I couldn't find a clear statement of precisely what the default argument promotion is for pointers, but odds are it "erases" the distinction between a pointer-to-struct and a pointer-to-int.
                    Examine the code more closely, it is not a pointer that is being passed but a structure. I know some compilers would put a pointer on the stack to a location allocated for the function call but there are several other options that compilers might use as well as actually putting the entire structure on the stack.

                    Whatever happens, undefined behaviour or not, I think this is generally a bad thing to do.

                    Comment

                    • destination
                      New Member
                      • Dec 2009
                      • 34

                      #11
                      donbock
                      What is prompting you to ask about these pathological cases?

                      Well i know one is discouraged to use such non-sense in a code. But just for fun i tried to run the code and wanted to know what is exactly happening. So i thought of getting an expert advice on such cases.
                      Anyways thanx everyone for looking into my query.

                      Comment

                      • donbock
                        Recognized Expert Top Contributor
                        • Mar 2008
                        • 2427

                        #12
                        Originally posted by banfa
                        Examine the code more closely, it is not a pointer that is being passed but a structure.
                        You are quite right. I missed the asterix (*) that dereferenced px. Definitely undefined behavior.

                        Comment

                        Working...