How to transfer an address value without using pointers

S

somenath

thanks! this is really what  was looking for !

that code invokes undefined behavior. I've already explained to Bart
why, but he doesn't seem to appreciate my advice.
You can do this:

#include <stdio.h>

int send(char *str);

int main(void) {
  char s[512];
  sprintf(s, "p", malloc(1024));
  send(s);
  return 0;

}

int send(char *str) {
  void *p;
  sscanf(str, "%p", &p);
  free(p);


I think this free(p) will show undefined behavior. According to my
understanding we should not try to free any memory using function
“free()” if the memory is not obtained through malloc or realloc .
In the above code pointer “p” (void *p) is not obtained using malloc
or realloc . So would it not cause undefined behavior ?
 
V

vippstar

that code invokes undefined behavior. I've already explained to Bart
why, but he doesn't seem to appreciate my advice.
You can do this:
#include <stdio.h>
int send(char *str);
int main(void) {
char s[512];
sprintf(s, "p", malloc(1024));
send(s);
return 0;

int send(char *str) {
void *p;
sscanf(str, "%p", &p);
free(p);

I think this free(p) will show undefined behavior. According to my
understanding we should not try to free any memory using function
“free()” if the memory is not obtained through malloc or realloc .
In the above code pointer “p” (void *p) is not obtained using malloc
or realloc . So would it not cause undefined behavior ?
return 0;
sscanf() will presumably fail the conversion and an uninitialized
pointer will be freed. Not (void *)"p" or anything like that.
It was my mistake. I thought it would work, but apparently it doesn't.
I have a poor understanding of C.
 
I

Ian Collins

Bartc said:
I would imagine that for many programs in 64-bits, the machine would spend
much of it's time pushing around pointers where the top half is zero. Or,
where it would previously push 2 32-bit params for a function, it would now
have to push 2 64-bit params to satisfy the stack width. Again lots of zeros
being moved about. It could have pushed those 2 32-bit values, if
consecutive, in one instruction.
Which is why applications on 64 bit systems tend to be built as 32 bit
unless they require the extra address range.
 
B

Ben Bacarisse

On Jun 17, 7:57 am, (e-mail address removed) wrote:
that code invokes undefined behavior. I've already explained to Bart
why, but he doesn't seem to appreciate my advice.
You can do this:
#include <stdio.h>
int send(char *str);
int main(void) {
char s[512];
sprintf(s, "p", malloc(1024));
send(s);
return 0;

int send(char *str) {
void *p;
sscanf(str, "%p", &p);
free(p);

I think this free(p) will show undefined behavior. According to my
understanding we should not try to free any memory using function
“free()†if the memory is not obtained through malloc or realloc .
In the above code pointer “p†(void *p) is not obtained using malloc
or realloc . So would it not cause undefined behavior ?
return 0;
sscanf() will presumably fail the conversion and an uninitialized
pointer will be freed. Not (void *)"p" or anything like that.
It was my mistake. I thought it would work, but apparently it doesn't.
I have a poor understanding of C.

You are too hard on yourself. You rejected and earlier correction of
the sprintf format to "%p" saying that was not what you meant, but I
can't see what else you could mean. For the record, unless I have got
it all wrong, this is perfectly well defined:

#include <stdio.h>
#include <stdlib.h>

void send(char *str);

int main(void)
{
char s[512];
sprintf(s, "%p", malloc(1024));
send(s);
return 0;
}

void send(char *str)
{
void *p;
sscanf(str, "%p", &p);
free(p);
}

and does not have any memory leaks. If you mean that what you were
proposing would not work when the part doing the sprintf and the part
doing the sscanf have separate address spaces, then yes you are right
that it won't work. All %p does is represent the pointer as text in a
reversible way.
 
S

somenath

On Jun 17, 7:57 am, (e-mail address removed) wrote:
that code invokes undefined behavior. I've already explained to Bart
why, but he doesn't seem to appreciate my advice.
You can do this:
#include <stdio.h>
int send(char *str);
int main(void) {
  char s[512];
  sprintf(s, "p", malloc(1024));
  send(s);
  return 0;
}
int send(char *str) {
  void *p;
  sscanf(str, "%p", &p);
  free(p);
I think this free(p) will show undefined behavior. According to my
understanding we should not try to free any memory using function
“free()” if the memory is not obtained through malloc or realloc .
In the above code  pointer  “p” (void *p) is not obtained using malloc
or realloc . So would it not cause undefined behavior ?
  return 0;
}
sscanf() will presumably fail the conversion and an uninitialized
pointer will be freed. Not (void *)"p" or anything like that.
It was my mistake. I thought it would work, but apparently it doesn't.
I have a poor understanding of C.

You are too hard on yourself.  You rejected and earlier correction of
the sprintf format to "%p" saying that was not what you meant, but I
can't see what else you could mean.  For the record, unless I have got
it all wrong, this is perfectly well defined:

#include <stdio.h>
#include <stdlib.h>

void send(char *str);

int main(void)
{
     char s[512];
     sprintf(s, "%p", malloc(1024));
     send(s);
     return 0;

}

void send(char *str)
{
     void *p;
     sscanf(str, "%p", &p);
     free(p);

}

and does not have any memory leaks.  If you mean that what you were
proposing would not work when the part doing the sprintf and the part
doing the sscanf have separate address spaces, then yes you are right
that it won't work.  All %p does is represent the pointer as text in a
reversible way.

Could you please explain why it won’t show undefined behavior?
When I ran this code I get
Segmentation fault (core dumped).

I think it would be free(str) instead of free(p).
Please correct me if my understanding is wrong.
 
B

Ben Bacarisse

somenath said:
On Jun 18, 4:54 pm, Ben Bacarisse <[email protected]> wrote:
#include <stdio.h>
#include <stdlib.h>

void send(char *str);

int main(void)
{
     char s[512];
     sprintf(s, "%p", malloc(1024));
     send(s);
     return 0;

}

void send(char *str)
{
     void *p;
     sscanf(str, "%p", &p);
     free(p);

}
Could you please explain why it won’t show undefined behavior?
When I ran this code I get
Segmentation fault (core dumped).

Exactly the code above gives you a segmentation fault? If so, what
compiler it it? I can only point to what the standard says about the
%p format which is that you can convert a pointer to text and back
again.
I think it would be free(str) instead of free(p).

That would be quite wrong. str is a parameter, initialised with a
pointer to an array with automatic storage duration. You can't
pass such a pointer to free.
 
S

santosh

somenath said:
On Jun 18, 4:54 pm, Ben Bacarisse <[email protected]> wrote:
[ ... ]
 For the record, unless I have got it all wrong, this is perfectly
 well defined:

#include <stdio.h>
#include <stdlib.h>

void send(char *str);

int main(void)
{
char s[512];
sprintf(s, "%p", malloc(1024));
send(s);
return 0;

}

void send(char *str)
{
void *p;
sscanf(str, "%p", &p);
free(p);

}

and does not have any memory leaks.  If you mean that what you were
proposing would not work when the part doing the sprintf and the part
doing the sscanf have separate address spaces, then yes you are right
that it won't work.  All %p does is represent the pointer as text in
a reversible way.

Could you please explain why it won?t show undefined behavior?

Where do you think it *should* invoke undefined behaviour?
When I ran this code I get
Segmentation fault (core dumped).

Strange. I get no such errors. Are you sure you compiled exactly the
code above?
I think it would be free(str) instead of free(p).

No. In main sprintf is used to convert the pointer value returned by
malloc (which could be NULL) to an implementation defined text format
and store it in the array 's.' This is then supplied as the argument to
the send function which accesses 's' as the local 'str'. Now sscanf is
used to convert the implementation defined text format of the pointer
value in 's' back to a void * value which is then assigned to
local 'p', which in turn is supplied to free.

As far as I can see, everthing is well defined, except perhaps one ought
to use an unsigned char array instead of a plain char one for 's.'
 
B

Ben Bacarisse

santosh said:
somenath said:
On Jun 18, 4:54 pm, Ben Bacarisse <[email protected]> wrote:
char s[512];
sprintf(s, "%p", malloc(1024)); ....
void *p;
sscanf(str, "%p", &p);
free(p);
As far as I can see, everthing is well defined, except perhaps one ought
to use an unsigned char array instead of a plain char one for 's.'

Why do you suggest that? I note the "perhaps", but I can' see *any*
advantage at all in this particular case.
 
S

santosh

Ben said:
santosh said:
somenath said:
On Jun 18, 4:54 pm, Ben Bacarisse <[email protected]> wrote:
char s[512];
sprintf(s, "%p", malloc(1024)); ...
void *p;
sscanf(str, "%p", &p);
free(p);
As far as I can see, everthing is well defined, except perhaps one
ought to use an unsigned char array instead of a plain char one for
's.'

Why do you suggest that? I note the "perhaps", but I can' see *any*
advantage at all in this particular case.

I'm sorry, you're right. There is no difference in either case. I was
confused by a post in a different thread.
 
V

vippstar

For the record, unless I have got
it all wrong, this is perfectly well defined:

#include <stdio.h>
#include <stdlib.h>

void send(char *str);

int main(void)
{
char s[512];
sprintf(s, "%p", malloc(1024));
send(s);
return 0;

}

void send(char *str)
{
void *p;
sscanf(str, "%p", &p);
free(p);

}

and does not have any memory leaks. If you mean that what you were
proposing would not work when the part doing the sprintf and the part
doing the sscanf have separate address spaces, then yes you are right
that it won't work. All %p does is represent the pointer as text in a
reversible way.
There's just one thing about this code that can fail: the sprintf()
line, *if* the text representation of a pointer is more than 510 bytes
long.
Unfortunately, the only way this seems solvable in C89 is:

/* ... */
FILE *fp = tempfile;
int rc = fprintf(tempfile, "%p", (void *)ptr);
/* check rc */
/* if all okay, */
char *s = malloc(rc + 1);
if(ptr) {
sprintf(s, "%p", (void *)ptr);
/* ... */

In C99, it's possible to use snprintf() in various ways, such as with
a fixed size array:

int rc;
char s[512];
rc = snprintf(s, sizeof s, "%p", (void *)s);

Or,

char *ptr = malloc(snprintf(NULL, 0, "%p", (void *)valid_ptr));
if(ptr)
sprintf(ptr, "%p", (void *)valid_ptr);
free(ptr);

But I don't think there's a chance in the *near* future that the
representation of a pointer in text shall require 512 bytes.
 
S

santosh

For the record, unless I have got
it all wrong, this is perfectly well defined:

#include <stdio.h>
#include <stdlib.h>

void send(char *str);

int main(void)
{
char s[512];
sprintf(s, "%p", malloc(1024));
send(s);
return 0;

}

void send(char *str)
{
void *p;
sscanf(str, "%p", &p);
free(p);

}

and does not have any memory leaks. If you mean that what you were
proposing would not work when the part doing the sprintf and the part
doing the sscanf have separate address spaces, then yes you are right
that it won't work. All %p does is represent the pointer as text in
a reversible way.
There's just one thing about this code that can fail: the sprintf()
line, *if* the text representation of a pointer is more than 510 bytes
long.
Unfortunately, the only way this seems solvable in C89 is:

/* ... */
FILE *fp = tempfile;

A typo. I'm sure you meant:

FILE *fp = tmpfile();

Also the call could fail.
int rc = fprintf(tempfile, "%p", (void *)ptr);
/* check rc */
/* if all okay, */
char *s = malloc(rc + 1);
if(ptr) {

Do you mean if(s) here?
sprintf(s, "%p", (void *)ptr);
/* ... */

In C99, it's possible to use snprintf() in various ways, such as with
a fixed size array:

int rc;
char s[512];
rc = snprintf(s, sizeof s, "%p", (void *)s);

Or with a VLA:

char ptr[snprintf(NULL, 0, "%p", (void *)valid_ptr)+1];
Or,

char *ptr = malloc(snprintf(NULL, 0, "%p", (void *)valid_ptr));
if(ptr)
sprintf(ptr, "%p", (void *)valid_ptr);
free(ptr);

But I don't think there's a chance in the *near* future that the
representation of a pointer in text shall require 512 bytes.

Yes.
 
V

vippstar

For the record, unless I have got
it all wrong, this is perfectly well defined:
#include <stdio.h>
#include <stdlib.h>
void send(char *str);
int main(void)
{
char s[512];
sprintf(s, "%p", malloc(1024));
send(s);
return 0;
}
void send(char *str)
{
void *p;
sscanf(str, "%p", &p);
free(p);
}
and does not have any memory leaks. If you mean that what you were
proposing would not work when the part doing the sprintf and the part
doing the sscanf have separate address spaces, then yes you are right
that it won't work. All %p does is represent the pointer as text in
a reversible way.
There's just one thing about this code that can fail: the sprintf()
line, *if* the text representation of a pointer is more than 510 bytes
long.
Unfortunately, the only way this seems solvable in C89 is:
/* ... */
FILE *fp = tempfile;

A typo. I'm sure you meant:

FILE *fp = tmpfile();

Also the call could fail.
I'm on fire today, three errors in 2 posts!
int rc = fprintf(tempfile, "%p", (void *)ptr);
/* check rc */
/* if all okay, */
char *s = malloc(rc + 1);
if(ptr) {

Do you mean if(s) here? Yep
sprintf(s, "%p", (void *)ptr);
/* ... */
In C99, it's possible to use snprintf() in various ways, such as with
a fixed size array:
int rc;
char s[512];
rc = snprintf(s, sizeof s, "%p", (void *)s);

Or with a VLA:

char ptr[snprintf(NULL, 0, "%p", (void *)valid_ptr)+1];
No, it is not guaranteed that the text representation of a pointer is
less than 65534 bytes.
(ISO C99 TC3, 5.2.4.1 - Environmental limits)
Well, what about my 'nitpicki-er' 65535 bytes? :)
 
B

Ben Bacarisse

For the record, unless I have got
it all wrong, this is perfectly well defined:

#include <stdio.h>
#include <stdlib.h>

void send(char *str);

int main(void)
{
char s[512];
sprintf(s, "%p", malloc(1024));
send(s);
return 0;

}

void send(char *str)
{
void *p;
sscanf(str, "%p", &p);
free(p);

}

and does not have any memory leaks. If you mean that what you were
proposing would not work when the part doing the sprintf and the part
doing the sscanf have separate address spaces, then yes you are right
that it won't work. All %p does is represent the pointer as text in a
reversible way.
There's just one thing about this code that can fail: the sprintf()
line, *if* the text representation of a pointer is more than 510 bytes
long.

Good point. That really just means it is not portable. The %p format
is implementation defined, so one can be sure it will not fail if your
library documents the maximum length.
 
S

santosh

[ ... ]
char s[512];
sprintf(s, "%p", malloc(1024)); [ ... ]
void *p;
sscanf(str, "%p", &p);
free(p); [ ... ]
There's just one thing about this code that can fail: the sprintf()
line, *if* the text representation of a pointer is more than 510
bytes long. [ ... ]
In C99, it's possible to use snprintf() in various ways, such as
with a fixed size array:
int rc;
char s[512];
rc = snprintf(s, sizeof s, "%p", (void *)s);

Or with a VLA:

char ptr[snprintf(NULL, 0, "%p", (void *)valid_ptr)+1];
No, it is not guaranteed that the text representation of a pointer is
less than 65534 bytes. (ISO C99 TC3, 5.2.4.1 - Environmental limits) [ ... ]
Well, what about my 'nitpicki-er' 65535 bytes? :)

It should most likely claim the Clc Nitpick of the Year award for 2008.
:)
 
H

Harald van Dijk

int rc;
char s[512];
rc = snprintf(s, sizeof s, "%p", (void *)s);

Or with a VLA:

char ptr[snprintf(NULL, 0, "%p", (void *)valid_ptr)+1];
No, it is not guaranteed that the text representation of a pointer is
less than 65534 bytes.
(ISO C99 TC3, 5.2.4.1 - Environmental limits)

Nor is it guaranteed that an int is less than any fixed number of bytes. A
conforming implementation can reject *every* program that uses objects of
type int that would be strictly conforming on other implementations. But
there's no point in doing so, and if you can assume implementors aren't
insane, you can assume they won't do that. Equally, if you can assume
implementors aren't insane, you shouldn't worry about the length of %p-
formatted pointers as much as you do.
 
A

Antoninus Twink

and if you can assume implementors aren't insane, you can assume they
won't do that.

Quite a high proportion of the traffic on clc is premised on the
assumption that there are insane implementors out there - don't spoil
the fun by bringing reality into the picture.
 
S

santosh

CBFalconer said:
somenath said:
For the record, unless I have got it all wrong, this is perfectly
well defined: [ ... ]
char s[512];
sprintf(s, "%p", malloc(1024)); [ ... ]
void *p;
sscanf(s, "%p", &p);
free(p);
[ ... ]
Could you please explain why it won't show undefined behavior?
When I ran this code I get:
Segmentation fault (core dumped).

Because of the specification attached to the %p descriptor for
sscanf. I suspect you have discovered a bug in your compiler.

Without more information from 'somenath' we cannot say for sure. I
suspect that he has introduced a typo somewhere in the process of
editing-compiling.

<snip>
 
V

vippstar

(e-mail address removed) wrote:
int rc;
char s[512];
rc = snprintf(s, sizeof s, "%p", (void *)s);
Or with a VLA:
char ptr[snprintf(NULL, 0, "%p", (void *)valid_ptr)+1];
No, it is not guaranteed that the text representation of a pointer is
less than 65534 bytes.
(ISO C99 TC3, 5.2.4.1 - Environmental limits)

Nor is it guaranteed that an int is less than any fixed number of bytes. A
conforming implementation can reject *every* program that uses objects of
type int that would be strictly conforming on other implementations. But
I don't see how a conforming implementation can reject every program
that uses int.
Do you mean that,
int main(void) { int i = 0; return i; }
Is allowed to be rejected by a conforming implementation? How so?

I also disagree with what you are saying. The text representation of
%p is not allowed to be more than the hosts INT_MAX.
If it was so, assuming it is size_t ptrsize = (size_t)INT_MAX + 1
Then return (int)ptrsize; would invoke undefined behavior. And the
invoker would be the implementation and not the programmer, so the
implementation is problematic.
there's no point in doing so, and if you can assume implementors aren't
insane, you can assume they won't do that. Equally, if you can assume
implementors aren't insane, you shouldn't worry about the length of %p-
formatted pointers as much as you do.
I don't worry, I'd never care about it outside of comp.lang.c...
%p is rarely used anyway, and most of the times it's to write it to a
file, not to an array of char.
 
H

Harald van Dijk

(e-mail address removed) wrote:
int rc;
char s[512];
rc = snprintf(s, sizeof s, "%p", (void *)s);
Or with a VLA:
char ptr[snprintf(NULL, 0, "%p", (void *)valid_ptr)+1];
No, it is not guaranteed that the text representation of a pointer is
less than 65534 bytes.
(ISO C99 TC3, 5.2.4.1 - Environmental limits)

Nor is it guaranteed that an int is less than any fixed number of
bytes. A conforming implementation can reject *every* program that uses
objects of type int that would be strictly conforming on other
implementations. But
I don't see how a conforming implementation can reject every program
that uses int.
Do you mean that,
int main(void) { int i = 0; return i; } Is allowed to be rejected by a
conforming implementation? How so?

Yes: if sizeof(int) > 65535, then this program exceeds the environmental
limit you mentioned.
I also disagree with what you are saying. The text representation of %p
is not allowed to be more than the hosts INT_MAX.

Okay, I can see that: if it is more, then the implementation cannot meet
the requirements for snprintf's return value.
If it was so, assuming
it is size_t ptrsize = (size_t)INT_MAX + 1

I'm not sure what you mean here. Could you explain a bit more?
Then return (int)ptrsize;
would invoke undefined behavior.

Out-of-range conversions between integer types don't cause the behaviour
to be undefined.
And the invoker would be the
implementation and not the programmer, so the implementation is
problematic.
I don't worry, I'd never care about it outside of comp.lang.c...

That's good to know. :)
 

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,800
Messages
2,569,657
Members
45,411
Latest member
CarmaStarn
Top