Thread overview | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
November 13, 2013 obliterate | ||||
---|---|---|---|---|
| ||||
Hello, I will soon get to work on typed allocators; I figured there will be some issues percolating to untyped allocators that will require design changes (hopefully minor). For starters, I want to define a function that "obliterates" an object, i.e. makes it almost surely unusable and not obeying its own invariants. At the same time, that state should be entirely reproducible and memory-safe. Here's what I'm thinking. First, obliterate calls the destructor if present and then writes the fields as follows: * unsigned integers: t.max / 2 * signed integers: t.min / 2 * characters: ? * Pointers and class references: size_t.max - 65_535, i.e. 64K below the upper memory limit. On all systems I know it can be safely assumed that that area will cause GPF when accessed. * Arrays: some weird length (like 17), and also starting at size_t.max minus the memory occupied by the array. * floating point numbers: NaN, or some ridiculous value like F.max / 2? Andrei |
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Tuesday, November 12, 2013 16:33:17 Andrei Alexandrescu wrote:
> Hello,
>
>
> I will soon get to work on typed allocators; I figured there will be some issues percolating to untyped allocators that will require design changes (hopefully minor).
>
> For starters, I want to define a function that "obliterates" an object, i.e. makes it almost surely unusable and not obeying its own invariants. At the same time, that state should be entirely reproducible and memory-safe.
>
> Here's what I'm thinking. First, obliterate calls the destructor if present and then writes the fields as follows:
>
> * unsigned integers: t.max / 2
>
> * signed integers: t.min / 2
>
> * characters: ?
>
> * Pointers and class references: size_t.max - 65_535, i.e. 64K below the upper memory limit. On all systems I know it can be safely assumed that that area will cause GPF when accessed.
>
> * Arrays: some weird length (like 17), and also starting at size_t.max minus the memory occupied by the array.
>
> * floating point numbers: NaN, or some ridiculous value like F.max / 2?
1. How is this different from destroy aside from the fact that it's specifically choosing values which aren't T.init?
2. What is the purpose of not choosing T.init?
- Jonathan M Davis
|
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Wednesday, 13 November 2013 at 00:33:17 UTC, Andrei Alexandrescu wrote: > For starters, I want to define a function that "obliterates" an object, i.e. makes it almost surely unusable and not obeying its own invariants. At the same time, that state should be entirely reproducible and memory-safe. What's this for? When will it be used? How will it behave in release mode? No-op, or same as non-release? > Here's what I'm thinking. First, obliterate calls the destructor if present and then writes the fields as follows: > > * unsigned integers: t.max / 2 > > * signed integers: t.min / 2 > > * characters: ? Why not 0xFF? (char.init, invalid UTF-8 code unit) > * Pointers and class references: size_t.max - 65_535, i.e. 64K below the upper memory limit. On all systems I know it can be safely assumed that that area will cause GPF when accessed. Make that value odd. That will also guarantee a GPF on systems where unaligned pointer access is forbidden. > * Arrays: some weird length (like 17), and also starting at size_t.max minus the memory occupied by the array. I guess the non-zero length is for code which is going to check it? Because otherwise, leaving length as just 0 will, in debug mode, cause a range error. In release mode, array index access will not check the length anyway. > * floating point numbers: NaN, or some ridiculous value like F.max / 2? NaNs are viral, so there's that. |
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 11/12/13 4:59 PM, Jonathan M Davis wrote:
> On Tuesday, November 12, 2013 16:33:17 Andrei Alexandrescu wrote:
>> Hello,
>>
>>
>> I will soon get to work on typed allocators; I figured there will be
>> some issues percolating to untyped allocators that will require design
>> changes (hopefully minor).
>>
>> For starters, I want to define a function that "obliterates" an object,
>> i.e. makes it almost surely unusable and not obeying its own invariants.
>> At the same time, that state should be entirely reproducible and
>> memory-safe.
>>
>> Here's what I'm thinking. First, obliterate calls the destructor if
>> present and then writes the fields as follows:
>>
>> * unsigned integers: t.max / 2
>>
>> * signed integers: t.min / 2
>>
>> * characters: ?
>>
>> * Pointers and class references: size_t.max - 65_535, i.e. 64K below the
>> upper memory limit. On all systems I know it can be safely assumed that
>> that area will cause GPF when accessed.
>>
>> * Arrays: some weird length (like 17), and also starting at size_t.max
>> minus the memory occupied by the array.
>>
>> * floating point numbers: NaN, or some ridiculous value like F.max / 2?
>
> 1. How is this different from destroy aside from the fact that it's specifically
> choosing values which aren't T.init?
>
> 2. What is the purpose of not choosing T.init?
Consider a memory-safe allocator (oddly enough they exist: in brief think non-intrusive unbounded per-type freelist). That would allow access after deallocation but would fail in a reproducible way.
The idea is that it should fail, so T.init is not good.
Andrei
|
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vladimir Panteleev | On 11/12/13 5:10 PM, Vladimir Panteleev wrote: > On Wednesday, 13 November 2013 at 00:33:17 UTC, Andrei Alexandrescu wrote: >> For starters, I want to define a function that "obliterates" an >> object, i.e. makes it almost surely unusable and not obeying its own >> invariants. At the same time, that state should be entirely >> reproducible and memory-safe. > > What's this for? When will it be used? Safe allocators. > How will it behave in release mode? No-op, or same as non-release? A safe allocator would obliterate in release mode if it wants to stay safe. >> Here's what I'm thinking. First, obliterate calls the destructor if >> present and then writes the fields as follows: >> >> * unsigned integers: t.max / 2 >> >> * signed integers: t.min / 2 >> >> * characters: ? > > Why not 0xFF? (char.init, invalid UTF-8 code unit) > >> * Pointers and class references: size_t.max - 65_535, i.e. 64K below >> the upper memory limit. On all systems I know it can be safely assumed >> that that area will cause GPF when accessed. > > Make that value odd. That will also guarantee a GPF on systems where > unaligned pointer access is forbidden. > >> * Arrays: some weird length (like 17), and also starting at size_t.max >> minus the memory occupied by the array. > > I guess the non-zero length is for code which is going to check it? > Because otherwise, leaving length as just 0 will, in debug mode, cause a > range error. In release mode, array index access will not check the > length anyway. I'm thinking along the lines of - empty arrays are common in sane objects. >> * floating point numbers: NaN, or some ridiculous value like F.max / 2? > > NaNs are viral, so there's that. Cool. Andrei |
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vladimir Panteleev | On 11/12/13 5:10 PM, Vladimir Panteleev wrote:
>> * Pointers and class references: size_t.max - 65_535, i.e. 64K below
>> the upper memory limit. On all systems I know it can be safely assumed
>> that that area will cause GPF when accessed.
>
> Make that value odd. That will also guarantee a GPF on systems where
> unaligned pointer access is forbidden.
Ha, I missed that. Nice!
Andrei
|
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Wednesday, 13 November 2013 at 00:33:17 UTC, Andrei Alexandrescu wrote: > Hello, > > > I will soon get to work on typed allocators; I figured there will be some issues percolating to untyped allocators that will require design changes (hopefully minor). > > For starters, I want to define a function that "obliterates" an object, i.e. makes it almost surely unusable and not obeying its own invariants. At the same time, that state should be entirely reproducible and memory-safe. > > Here's what I'm thinking. First, obliterate calls the destructor if present and then writes the fields as follows: > > * unsigned integers: t.max / 2 > > * signed integers: t.min / 2 > > * characters: ? > > * Pointers and class references: size_t.max - 65_535, i.e. 64K below the upper memory limit. On all systems I know it can be safely assumed that that area will cause GPF when accessed. > > * Arrays: some weird length (like 17), and also starting at size_t.max minus the memory occupied by the array. > > * floating point numbers: NaN, or some ridiculous value like F.max / 2? > > > > Andrei Perhaps these are of interest: http://stackoverflow.com/a/127404/216300 |
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Tuesday, November 12, 2013 17:19:04 Andrei Alexandrescu wrote:
> On 11/12/13 4:59 PM, Jonathan M Davis wrote:
> > On Tuesday, November 12, 2013 16:33:17 Andrei Alexandrescu wrote:
> >> Hello,
> >>
> >>
> >> I will soon get to work on typed allocators; I figured there will be some issues percolating to untyped allocators that will require design changes (hopefully minor).
> >>
> >> For starters, I want to define a function that "obliterates" an object, i.e. makes it almost surely unusable and not obeying its own invariants. At the same time, that state should be entirely reproducible and memory-safe.
> >>
> >> Here's what I'm thinking. First, obliterate calls the destructor if present and then writes the fields as follows:
> >>
> >> * unsigned integers: t.max / 2
> >>
> >> * signed integers: t.min / 2
> >>
> >> * characters: ?
> >>
> >> * Pointers and class references: size_t.max - 65_535, i.e. 64K below the upper memory limit. On all systems I know it can be safely assumed that that area will cause GPF when accessed.
> >>
> >> * Arrays: some weird length (like 17), and also starting at size_t.max minus the memory occupied by the array.
> >>
> >> * floating point numbers: NaN, or some ridiculous value like F.max / 2?
> >
> > 1. How is this different from destroy aside from the fact that it's specifically choosing values which aren't T.init?
> >
> > 2. What is the purpose of not choosing T.init?
>
> Consider a memory-safe allocator (oddly enough they exist: in brief think non-intrusive unbounded per-type freelist). That would allow access after deallocation but would fail in a reproducible way.
>
> The idea is that it should fail, so T.init is not good.
Except that pretty most of your examples don't seem like they would fail any more than T.init would. int.max / 2 in so no more valid or invalid than 0. The only difference I see would be that by setting pointers/references/arrays to a weird value rather than null, they'll be treated as if they have a value and then blow up rather than blowing up on a null value. For all the built-in types, T.init is essentially supposed to be as invalid as the type can get without pointing off into memory that it shouldn't be addressing.
So, the only thing I see that this suggestion does over using T.init is that on pointers/references/arrays, you won't end up with code that checks for null and avoids blowing up. Code that checks for null would then blow up just as much as code that assumes that the pointer/reference/array was non-null. But that's the only difference I see, since none of the other types end up with values that are any more invalid than T.init.
- Jonathan M Davis
|
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Am 13.11.2013 02:21, schrieb Andrei Alexandrescu:
> On 11/12/13 5:10 PM, Vladimir Panteleev wrote:
>>> * Pointers and class references: size_t.max - 65_535, i.e. 64K below
>>> the upper memory limit. On all systems I know it can be safely assumed
>>> that that area will cause GPF when accessed.
>>
>> Make that value odd. That will also guarantee a GPF on systems where
>> unaligned pointer access is forbidden.
>
> Ha, I missed that. Nice!
>
> Andrei
>
The classics:
0xFFFFDEAD dead
0xFFFFD1ED died
Not so obvious:
0xFFFFFA1D failed
0xFFFFACED (the result makes you dumb) faced
0xFFFFFEED don't feed me with this
0xFFFFDF0F don't follow (this pointer) or (you are) f*****
|
November 13, 2013 Re: obliterate | ||||
---|---|---|---|---|
| ||||
Posted in reply to KlausO | On 13.11.2013 08:16, KlausO wrote: > Am 13.11.2013 02:21, schrieb Andrei Alexandrescu: >> On 11/12/13 5:10 PM, Vladimir Panteleev wrote: >>>> * Pointers and class references: size_t.max - 65_535, i.e. 64K below >>>> the upper memory limit. On all systems I know it can be safely assumed >>>> that that area will cause GPF when accessed. >>> >>> Make that value odd. That will also guarantee a GPF on systems where >>> unaligned pointer access is forbidden. >> >> Ha, I missed that. Nice! >> >> Andrei >> > > The classics: > > 0xFFFFDEAD dead > 0xFFFFD1ED died > > Not so obvious: > > 0xFFFFFA1D failed > 0xFFFFACED (the result makes you dumb) faced > 0xFFFFFEED don't feed me with this > 0xFFFFDF0F don't follow (this pointer) or (you are) f***** I thought I recalled some system initializing its data to 0xF001, but apparently it was Algol 68-R using the character string "FOOLFOOLFOOL..."[0]. Still, I guess a case could be made for 0xFFFFF001. [0]: http://www.catb.org/jargon/html/F/fool.html -- Simen |
Copyright © 1999-2021 by the D Language Foundation