Thread: Undefined behavior with pointers to different arrays.

  1. #16
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by megafiddle View Post
    So are there then different "types" of pointers to same type? Something that is unaccessable to the programmer?
    No. In C, the type of every pointer is defined.

    Quote Originally Posted by megafiddle View Post
    Is it that a proper conversion will be done for assignment, but not for comparison?
    There is no conversion involved (except that of converting the name of an array into a pointer). It is simply a case where the results of comparison of some pointers are undefined.

    Incidentally, IIRC, comparing for equality and inequality does not have undefined behaviour. It is comparisons related to ordering (such as < and <=) that yield undefined behaviour in some circumstances.

    Quote Originally Posted by megafiddle View Post
    I'm just trying to understand where the danger actually is in the comparison, aside from it providing a possibly useless result.
    The real danger is that the standard specifies it has undefined behaviour. From a C language perspective, that is all you need to know.

    The standard leaves things undefined (or specifies that they result in undefined behaviour) in a number of circumstances. A common one is that there is variation between implementations (compilers, operating system, host hardware) as to whether something is even technically feasible, whether doing it yields an unrecoverable run-time error, and things like that.

    It might make sense to you to test if the address of an X (which is in ROM) is greater than the address of another X (which is in RAM). That doesn't mean it makes sense on all possible implementations.

    And the fact that it is undefined behaviour means that a compiler is not required to report the problem. The only way you might know there is a problem is if a program crashes on one host system, but not another.
    Last edited by grumpy; 11-01-2013 at 10:36 PM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  2. #17
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Ok, thanks.

    Does the undefined behavior only apply to relational operations?

    For example, if you printed (printf) the values of two respective pointers to two arrays,
    would the printed values agree with the result of a relational operations?

    -

  3. #18
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by grumpy
    Incidentally, IIRC, comparing for equality and inequality does not have undefined behaviour. It is comparisons related to ordering (such as < and <=) that yield undefined behaviour in some circumstances.
    The text of the standard as quoted by anduril462 in post #8 does not appear to make any exception for comparing for equality and inequality of pointers to elements from different arrays. However, there is a limited exception provided in a different place:
    Quote Originally Posted by C99 Clause 6.5.9 Paragraph 6
    Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.
    My C11 draft copy says the same thing.

    Quote Originally Posted by megafiddle
    Does the undefined behavior only apply to relational operations?

    For example, if you printed (printf) the values of two respective pointers to two arrays,
    would the printed values agree with the result of a relational operations?
    What do you mean by "agree with the result of a relational operations"? Remember, since the behaviour is undefined, there is no constraint given by the standard on the behaviour. Therefore, "the result of a relational operation" that is undefined could be say, the printing of a "Hello world!" program, or the launching of a nuclear weapon (special hardware required), etc, and have nothing to do with what you regard as "the result of a relational operation".
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #19
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by megafiddle View Post
    Does the undefined behavior only apply to relational operations?
    There are many other instances of undefined behaviour in the standard, including things you can do to pointers that invoke undefined behaviour. This is just one.

    Quote Originally Posted by megafiddle View Post
    For example, if you printed (printf) the values of two respective pointers to two arrays,
    would the printed values agree with the result of a relational operations?
    That question is meaningless, since the relational operators have undefined behaviour. Undefined behaviour trumps everything.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #20
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by megafiddle View Post
    So are there then different "types" of pointers to same type? Something that is unaccessable to the programmer?
    Well, there are qualified and unqualified versions of pointers, that point to the same type:
    Quote Originally Posted by C99 6.2.5 p25
    25 Any type so far mentioned is anunqualified type. Each unqualified type has several
    qualified versionsof its type,38) corresponding to the combinations of one, two, or all
    three of theconst, volatile, and restrictqualifiers. The qualified or unqualified
    versions of a type are distinct types that belong to the same type category and have the
    same representation and alignment requirements.39) A derived type is not qualified by the
    qualifiers (if any) of the type from which it is derived.
    38) See 6.7.3 regarding qualified array and function types.
    39) The same representation and alignment requirements are meant to imply interchangeability asarguments to functions, return values from functions, and members of unions.
    So, the following two types are not exactly the same, even though they both are of the same type category, and point to the same type of object.
    Code:
    char * const foo;  // foo is a const pointer to char
    char * bar;  // bar is a pointer to char
    Quote Originally Posted by grumpy
    No. A pointer can hold any value which represents a valid address in memory.
    I think this is not quite accurate/complete -- not every pointer can hold every valid memory address -- unless I'm misunderstanding your use of "valid". A pointer can hold any value which represents a valid address in memory for that type. For exact reasons you mentioned above (some objects may be in ROM or RAM), or for size & alignment reasons (e.g. Harvard architectures), some pointers may or may not be able to hold certain memory addresses.

  6. #21
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Quote Originally Posted by laserlight View Post
    What do you mean by "agree with the result of a relational operations"? Remember, since the behaviour is undefined, there is no constraint given by the standard on

    the behaviour. Therefore, "the result of a relational operation" that is undefined could be say, the printing of a "Hello world!" program, or the launching of a nuclear weapon (special hardware

    required), etc, and have nothing to do with what you regard as "the result of a relational operation".
    Quote Originally Posted by grumpy View Post
    That question is meaningless, since the relational operators have undefined behaviour. Undefined behaviour trumps everything.
    My interpretation of the standard is that the ordinality of certain pointers and therefore the comparison results of those pointers
    are defined and guaranteed. For pointers to two different arrays, no such guarantee exists.

    My assumption is that the ordinality of two pointers to two arrays does not necessarily follow the order of declaration,
    and therefore a comparison may not give you an expected result. But I don't see the cause of the undefined behaviour
    in the comparison itself.

    I can see that if the ordinality is undefined, then that "undefinedness" will carry over to the comparison result.
    If you compare two random numbers, the result will also be random. But that doesn't mean that that the comparison
    operation is itself generating random results.

    Now if the definition of undefined behaviour extends to everything that it affects, then that's fine. In that case I am just
    being too fussy about the terms and such. But that makes it difficult to ask questions if I am using the terms wrong.

    It seems to me that even if the order of the pointers is undefined, it doesn't mean that the order can't be determined
    for a specific instance of a program execution, even if that order is meaningless.

    For an example like this, I would expect the ordinal value of the printed pointer values to be unpredictable:

    Code:
     int array1[5];
    int array2[5];
    int *p1;
    int *p2;
    
    p1 = array1;
    p2 = array2;
    
    printf("p1 = %p\n", p1);
    printf("p2 = %p\n", p2);
    
    // so far everything is perfectly valid
    
    if(p1 > p2)
        printf("p1 is greater than p2");
    else
        printf("p1 is not greater than p2");
    But are you saying that the program could do something other than print either "p1 is greater than p2" or "p1 is not greater than p2"?

    -

  7. #22
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by anduril462 View Post
    A pointer can hold any value which represents a valid address in memory for that type.
    Yes, indeed, my description was incomplete.

    Quote Originally Posted by megafiddle View Post
    I can see that if the ordinality is undefined, then that "undefinedness" will carry over to the comparison result.
    That's the point you're missing. It is not only the ordinality that is undefined. Even the attempt to compare the results (in specified ways) yields undefined behaviour.
    Quote Originally Posted by megafiddle View Post
    If you compare two random numbers, the result will also be random. But that doesn't mean that that the comparison operation is itself generating random results.
    Sure. But random numbers can be produced without invoking undefined behaviour as well. That's not the point.

    Quote Originally Posted by megafiddle View Post
    Now if the definition of undefined behaviour extends to everything that it affects, then that's fine. In that case I am just being too fussy about the terms and such. But that makes it difficult to ask questions if I am using the terms wrong.
    Yeah, well.

    1) The definition of undefined behaviour does extend "to everything that it affects"
    2) If you are going to be fussy about "terms and such", the onus is on you to properly understand those terms before getting into a debate about them.

    For reference, the 1999 C standard, section 3.4, para 1 defines "undefined behavior" (with the joys of american spelling) to be
    undefined behavior

    behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
    All C and C++ standards have a similar definition (although the precise wording differs).

    Quote Originally Posted by megafiddle View Post
    For an example like this, I would expect the ordinal value of the printed pointer values to be unpredictable:

    Code:
     int array1[5];
    int array2[5];
    int *p1;
    int *p2;
    
    p1 = array1;
    p2 = array2;
    
    printf("p1 = %p\n", p1);
    printf("p2 = %p\n", p2);
    
    // so far everything is perfectly valid
    
    if(p1 > p2)
        printf("p1 is greater than p2");
    else
        printf("p1 is not greater than p2");
    But are you saying that the program could do something other than print either "p1 is greater than p2" or "p1 is not greater than p2"?
    Yes.

    Let's consider five hypothetical compilers.

    1) Compiler A lays out memory, so array1 is at a lower memory location than array2. When built with that compiler, the code will produce "p1 is not greater than p2"
    2) Compiler B lays out memory, so array2 is at a lower memory location than array1. When built with that compiler, the code will produce "p1 is greater than p2"
    3) Compiler C randomises the location of array1 and array2 every time the program is run. When built with that compiler, the code might randomly produce a different output every time the program is run.
    4) Compiler D recognises that array1 and array2 are not otherwise used, so removes them completely. It similarly eliminates p1 and p2 from existence, and emits code so the program always prints out the value 42.
    5) Compiler E triggers a voltage surge that fatally electrocutes the programmer, and produces no output to screen other than "RIP young grasshopper".

    So, which one of these compilers is correct? According to the standard, all of them are. Compiler E might be rather unpopular with programmers because of the result it produces, but it would still be correct according to the standard (but, boy, it would cause the average competence of programmers to increase).

    You see, undefined behaviour is not limited to what results a comparison will produce (for example, based on ordinality). It is an all or nothing thing. Undefined behaviour means any action is permitted, by the standard. Particular compilers (or compiler vendors) may choose to do it one way or another. That is what undefined behaviour is about.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  8. #23
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    May my question is meaningless but , the point of undefined behavior would exist if compiler put the array1 next to array2 in the memory? all of the times? I think again we will have UB because of two pointers that show to different arrays.

  9. #24
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Mr.Lnx View Post
    May my question is meaningless but , the point of undefined behavior would exist if compiler put the array1 next to array2 in the memory? all of the times? I think again we will have UB because of two pointers that show to different arrays.
    It is one thing for a particular compiler vendor to make such a choice for their compiler. Something else for a standard to mandate it for all possible compilers.

    Undefined behaviour allows freedom to compiler vendors to do what works best for their product. The problem comes in with code that assumes a particular (in this case) layout of arrays in memory. That code may not function as intended when built using a different compiler, on a different target machine, etc.

    Bear in mind that the standard is based on consensus among relevant experts, including compiler vendors. The fact this is undefined behaviour is a sign that a single approach could not be found that would work for all compilers, for all host systems, etc etc. These things are determined by vote. While there is an implied goal for the standard committee to minimise the number of instances of undefined behaviour in C, sometimes it is unavoidable.

    In this sense, C differs from proprietary languages like C# or Java. In those languages, the vendors were able to mandate particular solutions to suit themselves. Vendors of competing products (say, a competing JVM) had to comply, even if that was not best for that product or the particular systems it is supported for. And, AFAIK, those languages or their libraries all have instances of undefined behaviour, albeit fewer than in C, but also not as well known (or even admitted to by vendors) as is the case in C.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  10. #25
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Quote Originally Posted by grumpy View Post
    2) If you are going to be fussy about "terms and such", the onus is on you to properly understand those terms before getting into a debate about them.
    Agreed. But one doesn't always know that their understanding is wrong. It's in things like this that you question it.
    Also, not debating, just trying to understand.

    Quote Originally Posted by grumpy View Post
    That's the point you're missing. It is not only the ordinality that is undefined. Even the attempt to compare the results (in specified ways) yields undefined

    behaviour.
    Actually, that's the question I am asking. I was just trying to be clear on the answer.

    Quote Originally Posted by grumpy View Post
    1) The definition of undefined behaviour does extend "to everything that it affects"
    Ok, I think that is what my whole question is centered around.

    According to that definition, a perfectly operating comparison could produce an undefined result, simply because it was fed
    undefined values. In other words, it would evalute as either true or false, indeterminantly, based only on the input values
    being indeterminant.
    It seems to me that the standard was saying nothing more than that. Now, I don't know for sure, that's why I was asking.
    If the comparison itself does in fact exhibit undefined behaviour, then that does simply answer my question.
    Why is it necessary that the comparison also be at fault?

    Quote Originally Posted by grumpy View Post
    Sure. But random numbers can be produced without invoking undefined behaviour as well. That's not the point.
    No. It was just an example of input characteristics carrying over into the output.

    Quote Originally Posted by grumpy View Post
    Let's consider five hypothetical compilers.

    1) Compiler A lays out memory, so array1 is at a lower memory location than array2. When built with that compiler, the code will produce "p1 is not greater than p2"
    2) Compiler B lays out memory, so array2 is at a lower memory location than array1. When built with that compiler, the code will produce "p1 is greater than p2"
    3) Compiler C randomises the location of array1 and array2 every time the program is run. When built with that compiler, the code might randomly produce a different output every time the

    program is run.
    4) Compiler D recognises that array1 and array2 are not otherwise used, so removes them completely. It similarly eliminates p1 and p2 from existence, and emits code so the program always

    prints out the value 42.
    5) Compiler E triggers a voltage surge that fatally electrocutes the programmer, and produces no output to screen other than "RIP young grasshopper".
    Hypotheticals 1, 2 and 3 illustrate my original question. Isn't that considered undefined behaviour even with a perfectly operating comparison?

    Hypothetical 4 - unrelated problem? Couldn't that happen with two pointers to the same array?

    Hypothetical 5 - That's a terrible way to do it! Keyboards and mice are typically nonconductive.

    -
    Last edited by megafiddle; 11-02-2013 at 11:05 PM.

  11. #26
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by megafiddle
    According to that definition, a perfectly operating comparison could produce an undefined result, simply because it was fed
    undefined values. In other words, it would evalute as either true or false, indeterminantly, based only on the input values
    being indeterminant.
    Maybe a formal definition of the terms might help you understand:
    Quote Originally Posted by C++11 Clause 1.3.10
    implementation-defined behavior
    behavior, for a well-formed program construct and correct data, that depends on the implementation and that each implementation documents
    Quote Originally Posted by C++11 Clause 1.3.24
    undefined behavior
    behavior for which this International Standard imposes no requirements
    [ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. —end note ]
    Quote Originally Posted by C++11 Clause 1.3.25
    unspecified behavior
    behavior, for a well-formed program construct and correct data, that depends on the implementation
    [ Note: The implementation is not required to document which behavior occurs. The range of possible behaviors is usually delineated by this International Standard. —end note ]
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #27
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    For exact reasons you mentioned above (some objects may be in ROM or RAM), or for size & alignment reasons (e.g. Harvard architectures), some pointers may or may not be able to hold certain memory addresses.
    'void *' and 'char *' are both able to represent all object pointer types. (6.2.5p28, 6.3.2.3p1)

    Could it be that when two pointers are cast to 'void *', that the destination pointers are considered to point into the same aggregate?
    i dont believe in competition in da field of cboard posts, u see, i believe in a collection of posts each 2 be admired for der own personal statement. when in doubt, ask Willy!

  13. #28
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by Barney McGrew View Post
    'void *' and 'char *' are both able to represent all object pointer types. (6.2.5p28, 6.3.2.3p1)

    Could it be that when two pointers are cast to 'void *', that the destination pointers are considered to point into the same aggregate?
    No. "The same aggregate" is about the memory pointed to, not the type of the pointers in questions. Just because two pointers are of the same type, does not mean they point to the same aggregate. An aggregate type is something that combines multiple objects of some types. So an array is an aggregate of same-type objects. A struct is a sequential aggregate of different-type objects, and a union is an aggregate of different-typed objects that share the same memory space. So if you had two pointers that both pointed to, e.g. elements of the same array, then they both point to the same aggregate and casing them to void and comparing should be valid. But it's just silly.

    void * doesn't exist to get around type safety (or "type restrictions"), it exists for type-generic code. So, e.g. malloc can return a pointer to anything. So your linked list data structure can be a linked list of whatever you want. There are actually parts of the standard and rationale that cover the illegality of casting two different objects to void *. In fact, we had a lengthy discussion about dicking around with casting and void * about a year and a half ago: argv and its "formal" type.

  14. #29
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    I see. This makes me wonder about code like:
    Code:
    int a[3][10];
    a[0] < a[2];
    Would you say it has undefined behaviour? On the one hand, both pointers point into separate aggregates, but on the other, those two aggregates are members of the same, larger aggregate.
    i dont believe in competition in da field of cboard posts, u see, i believe in a collection of posts each 2 be admired for der own personal statement. when in doubt, ask Willy!

  15. #30
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by Barney McGrew View Post
    I see. This makes me wonder about code like:
    Code:
    int a[3][10];
    a[0] < a[2];
    Would you say it has undefined behaviour? On the one hand, both pointers point into separate aggregates, but on the other, those two aggregates are members of the same, larger aggregate.
    Nope, that's defined. They're part of the same aggregate: a. Actually, even the following should be well-defined:
    Code:
    a[0][0] < a[2][2];

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Is this not undefined behavior?
    By Syscal in forum C Programming
    Replies: 6
    Last Post: 07-15-2013, 01:07 AM
  2. Undefined behavior
    By jim mcnamara in forum C Programming
    Replies: 2
    Last Post: 02-18-2013, 11:14 PM
  3. Static vs. Dynamic Arrays, Getting Undefined Behavior
    By StefPrez in forum C++ Programming
    Replies: 11
    Last Post: 01-28-2012, 11:39 PM
  4. Is x=x++; Undefined Behavior?
    By envec83 in forum C Programming
    Replies: 5
    Last Post: 10-04-2011, 01:27 AM
  5. Undefined behavior from VC6 to 2k5
    By m37h0d in forum C++ Programming
    Replies: 10
    Last Post: 06-22-2011, 07:56 PM