using a freed pointer

S

Serve Laurijssen

Consider the following code

char *p1 = malloc(10);
char *p2 = malloc(10);

if (p1 > p2)
puts("bigger");

free(p1);
if (p1 > p2)
puts("bigger");

is this a case of UB on the second comparison? Since p1 does contain a valid
value even though there's no valid object there anymore.
 
C

Clark S. Cox III

Serve said:
Consider the following code

char *p1 = malloc(10);
char *p2 = malloc(10);

if (p1 > p2)
puts("bigger");

free(p1);
if (p1 > p2)
puts("bigger");

is this a case of UB on the second comparison? Since p1 does contain a valid
value even though there's no valid object there anymore.

Yes, it is UB. As an example:

Consider a platform that has separate data and address registers. Also
consider that this platform has virtual memory, and that free() unmaps
the passed-in pointer from the address space. The mere act of loading
the p1 pointer into a register in order to compare it to another
platform could cause a bus error, crash the program, etc.
 
I

Ian Malone

Clark said:
Yes, it is UB. As an example:

Consider a platform that has separate data and address registers. Also
consider that this platform has virtual memory, and that free() unmaps
the passed-in pointer from the address space. The mere act of loading
the p1 pointer into a register in order to compare it to another
platform could cause a bus error, crash the program, etc.

Strictly you can't compare pointers from different objects, I'm
sure someone else on here will be able to say whether p1 > p2
is implementation defined or undefined even without the free,
but it is one of the two.
 
K

Kenneth Brody

Clark S. Cox III said:
Yes, it is UB. As an example:

Consider a platform that has separate data and address registers. Also
consider that this platform has virtual memory, and that free() unmaps
the passed-in pointer from the address space. The mere act of loading
the p1 pointer into a register in order to compare it to another
platform could cause a bus error, crash the program, etc.

Isn't it UB even if p1 isn't freed, because p1 and p2 do not point
within the same object?

Consider the old segmented architecture of the 8088 CPU, and assume
that you are compiling in a mode that uses "far" pointers. If the
mallocs happen to return:

p1 = 0x1000:0xff00 (absolute address 0x1ff00)
and
p2 = 0x2000:0x0010 (absolute address 0x20010)

The code generated by the compiler can (correctly, as far as the
Standard is concerned) claim that "p1 > p2" is true, because the
offset 0xff00 is greater than the offset 0x0010.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
R

Richard Bos

Serve Laurijssen said:
Consider the following code

char *p1 = malloc(10);
char *p2 = malloc(10);

if (p1 > p2)
puts("bigger");

free(p1);
if (p1 > p2)
puts("bigger");

is this a case of UB on the second comparison? Since p1 does contain a valid
value even though there's no valid object there anymore.

It's UB both times because of comparing two pointers to different
objects using a relational operator; it's also UB the second time for
the reason you mention.
I wouldn't wonder if the way some popular implementations handle this UB
(especially the first case) is by pretending that it's legal and making
up a reasonable-looking answer; I wouldn't wonder, either, if the next
implementation crashed your program with a bus error or segfault.

Richard
 
C

Clark S. Cox III

Kenneth said:
Isn't it UB even if p1 isn't freed, because p1 and p2 do not point
within the same object?

Indeed, I forgot about that issue. However, to the OP: in answer to your
question, the following is still undefined.

char *p1 = malloc(10); //Assume that malloc succeeds
char *p2 = p1 + 5;

if(p1 > p2)
puts("bigger");

free(p1);

/*Even attempting to compare p1 or p2 results in UB */
if(p1 > p2)
puts("bigger");
 
A

Ancient_Hacker

Serve said:
Consider the following code

char *p1 = malloc(10);
char *p2 = malloc(10);

if (p1 > p2)
puts("bigger");

free(p1);
if (p1 > p2)
puts("bigger");

is this a case of UB on the second comparison? Since p1 does contain a valid
value even though there's no valid object there anymore.

Several issues:

(1) I doubt if C assigns any meaning to pointer ordering, so why
should you expect p1 > p2 to mean anything even if p1 and p2 are still
allocated?

(2) After a free(p1) I can't think of anything you can do with p1
other than setting it to another value. Even comparing it for
equality to another pointer sounds really iffy, and probably useless
to boot.
 
K

Keith Thompson

Ancient_Hacker said:
Several issues:

(1) I doubt if C assigns any meaning to pointer ordering, so why
should you expect p1 > p2 to mean anything even if p1 and p2 are still
allocated?

Why speculate?

C certainly does assign a meaning to pointer ordering. If it didn't,
the ">" operator wouldn't be legal for pointer operands.

Relational operators ("<", "<=", ">", ">=") on pointer values are
meaningful only if both point into the same object; otherwise the
behavior is undefined. See C99 6.5.8p5 for details; Google n1124.pdf
for a copy of the standard (plus TC1 and TC2).
(2) After a free(p1) I can't think of anything you can do with p1
other than setting it to another value. Even comparing it for
equality to another pointer sounds really iffy, and probably useless
to boot.

After free(p1), the value of p1 is indeterminate; referring to that
value in any way (potentially) invokes undefined behavior. (I added
the weasel-word "potentially" because of some subtle issues involving
indeterminate values vs. trap representations vs. unspecified values;
there's been a discussion recently in comp.std.c. Bottom line: Don't
do that.)
 
P

pete

Serve said:
Consider the following code

char *p1 = malloc(10);
char *p2 = malloc(10);

if (p1 > p2)
puts("bigger");

free(p1);
if (p1 > p2)
puts("bigger");

is this a case of UB on the second comparison?
Since p1 does contain a valid
value even though there's no valid object there anymore.

p1 does not contain a valid value
because there's no valid object there anymore.

The value of a pointer to an object type, can only be either:
1 an adress of an object or one past
2 a null pointer
3 indeterminate
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top