help: new[]-delete[] crash?

A

alohahulaland

Hi,

I got crash with the following code (damage: after normal bloack
(#45)):

char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
delete [] s;

Question 1: Is it legal to delete s before moving it back to the
beginning?
then I try this, still got the same crash:


char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
s--;
s--;
s--;
delete [] s;

any idea why?
 
L

Lionel B

Hi,

I got crash with the following code (damage: after normal bloack (#45)):

char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
^^^^^^^
Here you assign beyond the end of the memory reserved for s. That's
undefined behaviour. This is quite likely causing the crash, rather than
the delete [].
delete [] s;

Question 1: Is it legal to delete s before moving it back to the
beginning?

I think that's undefined behaviour.

What are you actually trying to do?
then I try this, still got the same crash:


char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
^^^^^^^
s--;
s--;
s--;
delete [] s;

any idea why?

Same reason as before.
 
R

Richard Herring

In message
Hi,

I got crash with the following code (damage: after normal bloack
(#45)):

char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
delete [] s;

Question 1: Is it legal to delete s before moving it back to the
beginning?

Of course not. The pointer you're passing to delete[] is not the one
that new[] returned. But there's a problem before you even get to the
delete[] :
then I try this, still got the same crash:


char* s=new char[3];

You allocate 3 elements...
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';

.... and assign to 4.
s--;
s--;
s--;
delete [] s;

any idea why?

Why on earth aren't you using std::string for this kind of manipulation?
 
A

alohahulaland

I got crash with the following code (damage: after normal bloack (#45)):
char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';

^^^^^^^
Here you assign beyond the end of the memory reserved for s. That's
undefined behaviour. This is quite likely causing the crash, rather than
the delete [].
delete [] s;
Question 1: Is it legal to delete s before moving it back to the
beginning?

I think that's undefined behaviour.

What are you actually trying to do?
then I try this, still got the same crash:
char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
^^^^^^^

s--;
s--;
s--;
delete [] s;
any idea why?

Same reason as before.

No, didn't assign anything.
Trying to pinpoint the problem, I stripped it down to that simple. If
I comment out that delete[] line, the crash's gone.

Although this is not the cause of crash here, is it legal to delete a
pointer to an array after stepping it down the road?
 
A

alohahulaland

In message


I got crash with the following code (damage: after normal bloack
(#45)):
char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
delete [] s;
Question 1: Is it legal to delete s before moving it back to the
beginning?

Of course not. The pointer you're passing to delete[] is not the one
that new[] returned. But there's a problem before you even get to the
delete[] :
then I try this, still got the same crash:
char* s=new char[3];

You allocate 3 elements...
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';

... and assign to 4.
s--;
s--;
s--;
delete [] s;
any idea why?

Why on earth aren't you using std::string for this kind of manipulation?

Holy moly...LOL...that's it! the sequela from switching between c
char* and c++ string class I guess. you are my hero. :)

So, to delete s, you'd have to step it back to the original memory
location?

char* s=new char[4];

*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';

s--;
s--;
s--;

delete [] s;
 
J

joecook

Holy moly...LOL...that's it! the sequela from switching between c
char* and c++ string class I guess. you are my hero. :)

So, to delete s, you'd have to step it back to the original memory
location?

No No No. That's not it. It's insane. If I saw this in a code
review, I'd try to get you on janitor duty. :)

If you really really want to not use std::string, ignore RAII and
manage your own pointers at this level, _at least_ do something like
the following:

char* s=new char[3];
int index = 0;
s[index++]='a';
s[index++]='b';
s[index++]='c';
delete [] s; // no "unwinding"

Joe C
 
F

Fred

In message
Hi,
I got crash with the following code (damage: after normal bloack
(#45)):
char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';
delete [] s;
Question 1: Is it legal to delete s before moving it back to the
beginning?
Of course not. The pointer you're passing to delete[] is not the one
that new[] returned. But there's a problem before you even get to the
delete[] :
then I try this, still got the same crash:
char* s=new char[3];
You allocate 3 elements...
... and assign to 4.
s--;
s--;
s--;
delete [] s;
any idea why?
Why on earth aren't you using std::string for this kind of manipulation?

Holy moly...LOL...that's it! the sequela from switching between c
char* and c++ string class I guess. you are my hero. :)

So, to delete s, you'd have to step it back to the original memory
location?

char* s=new char[4];

*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';

s--;
s--;
s--;

delete [] s;- Hide quoted text -

- Show quoted text -

You dp not have to "step it back". You only have
to ensure that what you pass to delete is a pointer
that points to the same thing that new returned.

A much better way:

char *s = new char[3];
char *p = s;
*p++ = 'a';
*p++ = 'b';
....
// or
s[0] = 'a';
s[1] = 'b';
....


delete [] s;
 
A

alohahulaland

Holy moly...LOL...that's it! the sequela from switching between c
char* and c++ string class I guess. you are my hero. :)
So, to delete s, you'd have to step it back to the original memory
location?

No No No. That's not it. It's insane. If I saw this in a code
review, I'd try to get you on janitor duty. :)

If you really really want to not use std::string, ignore RAII and
manage your own pointers at this level, _at least_ do something like
the following:

char* s=new char[3];
int index = 0;
s[index++]='a';
s[index++]='b';
s[index++]='c';
delete [] s; // no "unwinding"

Joe C

"No No No. That's not it. It's insane. If I saw this in a code
review, I'd try to get you on janitor duty. :)"
---That's how we got our past two janitors :)

That's by no means the real code. I stripped it down and played with
my little insane experiment just for the sake of understanding the
stuff under the hood.

I didn't realize deleteing would give rise to undefined behavior after
you changing the mem location that the pointer was initially assigned
to by "new" (delete would call dtor anyway). It's clear to me now that
you need to make sure the mom location it points to doesn't change
when you delete.

Thanks a bunch, and also for Fred.

Yours and Fred's explanation is quite clear to me here.
 
G

gw7rib

I didn't realize deleteing would give rise to undefined behavior after
you changing the mem location that the pointer was initially assigned
to by "new" (delete would call dtor anyway). It's clear to me now that
you need to make sure the mom location it points to doesn't change
when you delete.

If you're ready for a bit more explanation...

The chances are, when you ask for memory with s=new char[3]; it
actually looks for a free chunk of memory that is a bit longer than
just 3 characters. It uses the first part of this to store useful
information, such as how many items there are in the current
allocation and where the next bit of free memory is. The address it
returns to you is not actually the very beginning of the chunk it's
just reserved, instead it's an address which comes just after this
useful information and is the beginning of the 3 character space that
you are allowed to play with.

Then when you do delete, it looks at the bit of memory just before the
address you pass to delete, which tells it how much memory to free and
how to keep track of what memory is now in use.

So in your original code, when you told it to delete [] s; then
(assuming things hadn't already gone horribly wrong) it looked for
information about how much memory had been allocated - and it found
"abc". So it got confused. Probably.

(Note, however, that it's not obliged to organise memory anything like
this, but I think it's how it's normally done.)

Hope that helps.
Paul.
 
A

alohahulaland

I didn't realize deleteing would give rise to undefined behavior after
you changing the mem location that the pointer was initially assigned
to by "new" (delete would call dtor anyway). It's clear to me now that
you need to make sure the mom location it points to doesn't change
when you delete.

If you're ready for a bit more explanation...

The chances are, when you ask for memory with s=new char[3]; it
actually looks for a free chunk of memory that is a bit longer than
just 3 characters. It uses the first part of this to store useful
information, such as how many items there are in the current
allocation and where the next bit of free memory is. The address it
returns to you is not actually the very beginning of the chunk it's
just reserved, instead it's an address which comes just after this
useful information and is the beginning of the 3 character space that
you are allowed to play with.

Then when you do delete, it looks at the bit of memory just before the
address you pass to delete, which tells it how much memory to free and
how to keep track of what memory is now in use.

So in your original code, when you told it to delete [] s; then
(assuming things hadn't already gone horribly wrong) it looked for
information about how much memory had been allocated - and it found
"abc". So it got confused. Probably.

(Note, however, that it's not obliged to organise memory anything like
this, but I think it's how it's normally done.)

Hope that helps.
Paul.

Sure, Paul, your comments are appreciated too. Is that overhead within
the "sizeof" if you
do it in the old fashion, malloc(sizeof(type))?

Mike
 
I

Ian Collins

Holy moly...LOL...that's it! the sequela from switching between c
char* and c++ string class I guess. you are my hero. :)
You would get exactly the same problem in C with malloc() and free().
 
A

alohahulaland

alohahulaland wrote:

[...]
"No No No. That's not it. It's insane. If I saw this in a code
review, I'd try to get you on janitor duty. :)"
---That's how we got our past two janitors :)
That's by no means the real code. I stripped it down and played with
my little insane experiment just for the sake of understanding the
stuff under the hood.

I just want to say that your experimentation and questions are good. When
you're done, you'll understand pointers better. Making mistakes and
exploring these messy approaches is a good way to gain a firm grasp.

This reminds me of what one of my college professors once said many
years back,"don't be afraid of asking stupid questions, that's how you
get smart", I'd like to add, "don't be afraid of letting loose your
insanity and getting messy, that's how you get clean hands next
time." :)
 
A

alohahulaland

alohahulaland said:
(e-mail address removed) wrote: [...]
Then when you do delete, it looks at the bit of memory just before the
address you pass to delete, which tells it how much memory to free and
how to keep track of what memory is now in use.
So in your original code, when you told it to delete [] s; then
(assuming things hadn't already gone horribly wrong) it looked for
information about how much memory had been allocated - and it found
"abc". So it got confused. Probably.
[...]
Sure, Paul, your comments are appreciated too. Is that overhead within
the "sizeof" if you do it in the old fashion, malloc(sizeof(type))?

Some overhead is necessary for the memory manager to avoid giving that
block of memory to anyone else. This is beyond whatever you request, and
the amount depends on the memory manager. Normal code isn't exposed to
this detail, so the exact overhead doesn't matter.

It's part of modularity, where only certain aspects of something are
well-defined, and anything else shouldn't be depended on. In this case,
when you request N bytes of memory, you get a pointer to the first byte,
can access up to N-1 bytes past that, and can also form a pointer one past
the last byte (but can't access it). Other bytes may be accessible, but
not reliably, as they aren't part of the contract. Once you're done with
the memory, you pass a pointer to the first byte to the free routine
(passing any other pointer again is outside the contract, so you don't
know what will happen). And then, you can't use the pointer AT ALL, not
even compare it with anything.

This is absolutely clear now.It's hard to say that being offered a
certain level of latitude of memory manipulation is a bad thing, like
specifying your own paddings between data chunks in memory or
alignment with unnamed bit fields.

Again, your insightful comments are appreciated, blargg.
 
I

Ian Collins

Please don't quote signatures.

You mean, miscounting the element by one, the nullchar?

As well as passing something to free not returned by malloc and friends.
 
L

Lionel B

I got crash with the following code (damage: after normal bloack
(#45)):
char* s=new char[3];
*s='a';
s++;
*s='b';
s++;
*s='c';
s++;
*s='\0';

^^^^^^^
Here you assign beyond the end of the memory reserved for s. That's
undefined behaviour. This is quite likely causing the crash, rather
than the delete [].
delete [] s;
[...]
^^^^^^^^
Please don't quote signatures
No, didn't assign anything.

Of course you did. You allocated 3 chars:

char* s=new char[3];

and then assigned 4:

*s='a'; // assign to s[0]
s++;
*s='b'; // assign to s[1]
s++;
*s='c'; // assign to s[2]
s++;
*s='\0'; // assign to s[3] - oops, s[3] not allocated - Undefined Behaviour

delete [] s; // wrong, but since you've already got UB, irrelevant
Trying to pinpoint the problem, I stripped it down to that simple. If I
comment out that delete[] line, the crash's gone.

The last assignment is Undefined Behaviour, after which all bets are off.
Whether (or where) your program crashes subsequently is unlikely to tell
you anything useful.

[...]
 

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

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,286
Latest member
ChristieSo

Latest Threads

Top