unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Dumper problems and a possible solutions
@ 2014-06-24 17:19 Rich Felker
  2014-06-24 19:27 ` Stefan Monnier
  2014-06-25 18:03 ` Dmitry Antipov
  0 siblings, 2 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-24 17:19 UTC (permalink / raw)
  To: emacs-devel

Hi,

I've been trying to get current emacs working on musl libc based
systems, and running into trouble with the dumper. After a lot of
hacking I got it to work, and I'm hoping something based on the ideas
(not the implementation, which is hideously ugly) in my work could be
acceptable upstream.

By far the biggest problem is malloc-related. musl does not support
overriding malloc, so I'm building with system malloc. The emacs
dumper assumes all of the allocations that need to survive dumping end
up in the brk segment, which is not a constraint musl's allocator can
satisfy -- it has no support for huge allocations in brk, and will
sometimes opt to use mmap rather than brk for extending the heap for
small objects.

The hack I used to solve this is really simple: I added to alloc.c a
tiny allocator that just uses a giant static buffer which gets used
for lisp object allocations prior to dumping (it has an extern flag
that the dumper sets to indicate whether this code is running prior to
dumping or afterwards). With free being a NOP, as it is in my
implementation right now, I had to make this buffer 400 megs; that's
the main reason the patch would be utterly unacceptable as-is. I
believe the problem could be solved by writing a trivial "early
malloc" implementation that uses a static buffer, but with proper
recycling of free areas.

There are also, however, at least two other issues which affect static
linking. Dynamic linking does not seem to be affected because the
dumper doesn't save libc's globals in the dynamic-linked case, and
these involve global state in libc:

One is that, with modern Linux kernels with brk randomization as part
of ASLR, dumping saves malloc's idea of the current brk, and when it
mismatches at runtime, malloc will either crash or "allocate" memory
that's not even mapped. Trying to work around this in musl is not
acceptable because it would penalize all programs with extra syscalls
whenever malloc has to expand the brk.

The other issue is that musl's clock_gettime and related functions
store the pointer to the vdso version of this function. Since the
kernel maps vdso at a random address, the stored value from before
dumping will not be valid when the dumped executable is run.

To solve ALL of the problems with the dumper (which seems to be a
recurring theme), I have a proposed design to make it fully portable
-- even moreso than xemacs "portable dumper" which is still an ugly
hack. The idea is simple: after loading all of the lisp objects that
need dumping, walk the lisp heap and output a representation for each
object as a giant static array in C source format, then compile and
link this new translation unit with the rest of the emacs .o files to
produce a final emacs binary. No hacks with binary formats would be
involved; everything would happen at the C source level. As part of
the lisp heap dumping, address references to other objects would have
to be relocated to refer to the object's position in the static array
rather than the original address at which the object resided when
created in temacs. That's some non-trivial work, but definitely no
prohibitive, and as a bonus, the generated address-constant references
in the static array would transform to load-address-relative
relocations for the linker, allowing emacs to be built as a
position-indepdendent executable (PIE) if desired.

Does this sound like a viable direction? I'm not an emacs hacker by
any means and don't think I'm qualified to do the lisp heap dumping
implementation, but I could certainly help with design or any issues
that arise during implementation if others are interested in working
on it.

If not, or if that's going to be a very long-term project, would a
cleaned-up version of my current solution be acceptable upstream?

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-24 17:19 Dumper problems and a possible solutions Rich Felker
@ 2014-06-24 19:27 ` Stefan Monnier
  2014-06-24 19:40   ` Rich Felker
  2014-06-25 18:03 ` Dmitry Antipov
  1 sibling, 1 reply; 43+ messages in thread
From: Stefan Monnier @ 2014-06-24 19:27 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

> To solve ALL of the problems with the dumper (which seems to be a
> recurring theme), I have a proposed design to make it fully portable
> -- even moreso than xemacs "portable dumper" which is still an ugly
> hack. The idea is simple: after loading all of the lisp objects that
> need dumping, walk the lisp heap and output a representation for each
> object as a giant static array in C source format, then compile and
> link this new translation unit with the rest of the emacs .o files to
> produce a final emacs binary. No hacks with binary formats would be
> involved; everything would happen at the C source level. As part of
> the lisp heap dumping, address references to other objects would have
> to be relocated to refer to the object's position in the static array
> rather than the original address at which the object resided when
> created in temacs. That's some non-trivial work, but definitely no
> prohibitive, and as a bonus, the generated address-constant references
> in the static array would transform to load-address-relative
> relocations for the linker, allowing emacs to be built as a
> position-indepdendent executable (PIE) if desired.

Generating a big static C array against which to link sounds fine and
very portable, indeed.  I'm not sure how hard/easy the relocation could
turn out to be.  There's the problem of finding *all* the references,
and there's the problem that moving an object means that its "hash"
value changes.

> If not, or if that's going to be a very long-term project, would a
> cleaned-up version of my current solution be acceptable upstream?

Making the "dump" portable would be very welcome.  Generating a big
static C array sounds OK.  So whether the result is acceptable or not
will depend on what's needed to solve the problems linked to relocation.

Another option is to "dump" the heap into a binary file that we would
later on "mmap".


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-24 19:27 ` Stefan Monnier
@ 2014-06-24 19:40   ` Rich Felker
  2014-06-24 20:24     ` Stefan Monnier
  0 siblings, 1 reply; 43+ messages in thread
From: Rich Felker @ 2014-06-24 19:40 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

On Tue, Jun 24, 2014 at 03:27:39PM -0400, Stefan Monnier wrote:
> > To solve ALL of the problems with the dumper (which seems to be a
> > recurring theme), I have a proposed design to make it fully portable
> > -- even moreso than xemacs "portable dumper" which is still an ugly
> > hack. The idea is simple: after loading all of the lisp objects that
> > need dumping, walk the lisp heap and output a representation for each
> > object as a giant static array in C source format, then compile and
> > link this new translation unit with the rest of the emacs .o files to
> > produce a final emacs binary. No hacks with binary formats would be
> > involved; everything would happen at the C source level. As part of
> > the lisp heap dumping, address references to other objects would have
> > to be relocated to refer to the object's position in the static array
> > rather than the original address at which the object resided when
> > created in temacs. That's some non-trivial work, but definitely no
> > prohibitive, and as a bonus, the generated address-constant references
> > in the static array would transform to load-address-relative
> > relocations for the linker, allowing emacs to be built as a
> > position-indepdendent executable (PIE) if desired.
> 
> Generating a big static C array against which to link sounds fine and
> very portable, indeed.  I'm not sure how hard/easy the relocation could
> turn out to be.  There's the problem of finding *all* the references,
> and there's the problem that moving an object means that its "hash"
> value changes.

Thanks for the feedback. Can you elaborate on how/why the hash
changes, and where it's stored that would need to be updated? As far
as the relocation, my impression is that it would just need to be able
to identify pointers in lisp objects (this is already possible since
the GC needs to do it, right?), and rewrite them to (essentially)
"static_lisp_heap + offset_of_pointed_to_object" when writing the dump
out as a C array.

> > If not, or if that's going to be a very long-term project, would a
> > cleaned-up version of my current solution be acceptable upstream?
> 
> Making the "dump" portable would be very welcome.  Generating a big
> static C array sounds OK.  So whether the result is acceptable or not
> will depend on what's needed to solve the problems linked to relocation.
> 
> Another option is to "dump" the heap into a binary file that we would
> later on "mmap".

This is the xemacs "portable dumper" approach, and I believe it's
inferrior because it depends on being able to map back at the same
location. If the region is a page-aligned static buffer in the main
executable and you mmap over it with MAP_FIXED, this is safe for the
most part, but it's still incompatible with PIE. I think it would be
nice to solve this problem in a way that also makes PIE possible.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-24 19:40   ` Rich Felker
@ 2014-06-24 20:24     ` Stefan Monnier
  2014-06-24 21:15       ` Rich Felker
  0 siblings, 1 reply; 43+ messages in thread
From: Stefan Monnier @ 2014-06-24 20:24 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

> Thanks for the feedback. Can you elaborate on how/why the hash
> changes, and where it's stored that would need to be updated?

When placing an object in a hash-table, the hashing function often just
uses the address as "the hash value".  So any hash-table that uses such
a hash-function will need to be rehashed after relocation.

> As far as the relocation, my impression is that it would just need to
> be able to identify pointers in lisp objects (this is already possible
> since the GC needs to do it, right?), and rewrite them to
> (essentially) "static_lisp_heap + offset_of_pointed_to_object" when
> writing the dump out as a C array.

Yes, the GC already knows how to find the references that are inside
Lisp objects, but there can also be references coming from global
variables (for sure) or non-Lisp data-structures or maybe from the stack
(not sure about those last two).

> This is the xemacs "portable dumper" approach, and I believe it's
> inferrior because it depends on being able to map back at the same
> location.

We could support relocation at mmap-time to solve this.
Neither solution is clearly superior to the other, it just depends on
you priority.  For me, either way would be an improvement over what we
have (tho, again, it might still depend on the constraints imposed by
the need to perform relocation).


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-24 20:24     ` Stefan Monnier
@ 2014-06-24 21:15       ` Rich Felker
  2014-06-24 21:37         ` Stefan Monnier
  0 siblings, 1 reply; 43+ messages in thread
From: Rich Felker @ 2014-06-24 21:15 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

On Tue, Jun 24, 2014 at 04:24:47PM -0400, Stefan Monnier wrote:
> > Thanks for the feedback. Can you elaborate on how/why the hash
> > changes, and where it's stored that would need to be updated?
> 
> When placing an object in a hash-table, the hashing function often just
> uses the address as "the hash value".  So any hash-table that uses such
> a hash-function will need to be rehashed after relocation.

I see. Is this hashing all at the C level, or is it happening in lisp
code? Can the lisp code even see the address value for lisp objects?
If it's purely at the C level I doubt it would be hard to re-do the
hashes but I obviously haven't read the relevant code.

> > As far as the relocation, my impression is that it would just need to
> > be able to identify pointers in lisp objects (this is already possible
> > since the GC needs to do it, right?), and rewrite them to
> > (essentially) "static_lisp_heap + offset_of_pointed_to_object" when
> > writing the dump out as a C array.
> 
> Yes, the GC already knows how to find the references that are inside
> Lisp objects, but there can also be references coming from global
> variables (for sure) or non-Lisp data-structures or maybe from the stack
> (not sure about those last two).

How does the GC avoid freeing objects that have these kinds of
references?

BTW, at the point of dumping, my impression is that there should not
be relevant references from the stack; the whole call frame at the
time of dumping is thrown away and replaced by the new invocation of
main. Conceptually, the dumper can be thought of as a longjmp back to
the start of main.

> > This is the xemacs "portable dumper" approach, and I believe it's
> > inferrior because it depends on being able to map back at the same
> > location.
> 
> We could support relocation at mmap-time to solve this.

Yes, but that's conceptually just as difficult as dumping to a C
array: you have to patch up all the addresses and the hash values will
change.

> Neither solution is clearly superior to the other, it just depends on
> you priority.  For me, either way would be an improvement over what we
> have (tho, again, it might still depend on the constraints imposed by
> the need to perform relocation).

I agree completely. The current situation makes it nearly impossible
to port emacs to a system that's not making strong guarantees about
its implementation internals, and (at least from my understanding
reading list archives) it's imposing ugly constraints on existing
implementations (glibc) not to change internals in ways that would
break emacs' dumper. I would really like to see fixing this issue
treated as a priority in the future direction of emacs.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-24 21:15       ` Rich Felker
@ 2014-06-24 21:37         ` Stefan Monnier
  0 siblings, 0 replies; 43+ messages in thread
From: Stefan Monnier @ 2014-06-24 21:37 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

>> > Thanks for the feedback. Can you elaborate on how/why the hash
>> > changes, and where it's stored that would need to be updated?
>> When placing an object in a hash-table, the hashing function often just
>> uses the address as "the hash value".  So any hash-table that uses such
>> a hash-function will need to be rehashed after relocation.
> I see. Is this hashing all at the C level, or is it happening in lisp
> code?

It's in C.

> Can the lisp code even see the address value for lisp objects?

It usually doesn't see it, but the `sxhash' function does return values
which can depend on the address of objects (not for cons cells or
arrays, but for objects such as processes, markers, buffer, overlays,
...).
I think it happens rarely enough that we can hope to be OK on this front.

> If it's purely at the C level I doubt it would be hard to re-do the
> hashes but I obviously haven't read the relevant code.

Indeed, we just need to rehash all the hash-tables we find while
traversing the heap.

>> Yes, the GC already knows how to find the references that are inside
>> Lisp objects, but there can also be references coming from global
>> variables (for sure) or non-Lisp data-structures or maybe from the stack
>> (not sure about those last two).
> How does the GC avoid freeing objects that have these kinds of
> references?

It knows about some of those pointers (via `staticpro' for global
variables and via conservative stack scanning for the stack).

> BTW, at the point of dumping, my impression is that there should not
> be relevant references from the stack;

That'd be my hope as well.

>> We could support relocation at mmap-time to solve this.
> Yes, but that's conceptually just as difficult as dumping to a C
> array: you have to patch up all the addresses and the hash values will
> change.

Agreed.  Relocation is the big issue and pretty much any technique we
may like to use will need to address the problem.
I wonder how smalltalk machines deal with it.

> I agree completely. The current situation makes it nearly impossible
> to port emacs to a system that's not making strong guarantees about
> its implementation internals, and (at least from my understanding
> reading list archives) it's imposing ugly constraints on existing
> implementations (glibc) not to change internals in ways that would
> break emacs' dumper. I would really like to see fixing this issue
> treated as a priority in the future direction of emacs.

It's been a latent problem for the last 20 years or so, but it rarely
bites, so it's not of terribly high priority in general, especially
since new systems don't show up very often.
But it's important enough that we might be willing to pay some price
(e.g. the relocation code will likely either require significant
changes to the GC code, or it will duplicate significant chunks of the
GC code).


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-24 17:19 Dumper problems and a possible solutions Rich Felker
  2014-06-24 19:27 ` Stefan Monnier
@ 2014-06-25 18:03 ` Dmitry Antipov
  2014-06-25 18:08   ` Rich Felker
                     ` (2 more replies)
  1 sibling, 3 replies; 43+ messages in thread
From: Dmitry Antipov @ 2014-06-25 18:03 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

On 06/24/2014 09:19 PM, Rich Felker wrote:

> To solve ALL of the problems with the dumper (which seems to be a
> recurring theme), I have a proposed design to make it fully portable
> -- even moreso than xemacs "portable dumper" which is still an ugly
> hack. The idea is simple: after loading all of the lisp objects that
> need dumping, walk the lisp heap and output a representation for each
> object as a giant static array in C source format, then compile and
> link this new translation unit with the rest of the emacs .o files to
> produce a final emacs binary.

What about non-Lisp objects?

It's not too hard to walk through live (reachable) Lisp objects - this
is exactly what GC mark phase does. It's not too hard to walk through
all allocated Lisp objects - this is exactly what GC sweep phase does.
But what about lower-level stuff allocated with malloc at invisible
from Lisp? Of course, you can do your own serialization for these objects
as well - but only if you know about their internal structure. What about
stuff allocated by some external library? In general, you can't parse heap
(i.e. looking at object, you can't say where the next object is, what is the
type of next object, etc.). IIUC, "totally portable" heap dumper is impossible
without having a description of each possible heap object and ability to
distinguish between different types of objects.

Dmitry




^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:03 ` Dmitry Antipov
@ 2014-06-25 18:08   ` Rich Felker
  2014-06-25 18:30     ` Dmitry Antipov
                       ` (2 more replies)
  2014-06-25 18:20   ` Eli Zaretskii
  2014-06-25 18:38   ` Stefan Monnier
  2 siblings, 3 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 18:08 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: emacs-devel

On Wed, Jun 25, 2014 at 10:03:36PM +0400, Dmitry Antipov wrote:
> On 06/24/2014 09:19 PM, Rich Felker wrote:
> 
> >To solve ALL of the problems with the dumper (which seems to be a
> >recurring theme), I have a proposed design to make it fully portable
> >-- even moreso than xemacs "portable dumper" which is still an ugly
> >hack. The idea is simple: after loading all of the lisp objects that
> >need dumping, walk the lisp heap and output a representation for each
> >object as a giant static array in C source format, then compile and
> >link this new translation unit with the rest of the emacs .o files to
> >produce a final emacs binary.
> 
> What about non-Lisp objects?
> 
> It's not too hard to walk through live (reachable) Lisp objects - this
> is exactly what GC mark phase does. It's not too hard to walk through
> all allocated Lisp objects - this is exactly what GC sweep phase does.
> But what about lower-level stuff allocated with malloc at invisible
> from Lisp? Of course, you can do your own serialization for these objects
> as well - but only if you know about their internal structure. What about
> stuff allocated by some external library? In general, you can't parse heap
> (i.e. looking at object, you can't say where the next object is, what is the
> type of next object, etc.). IIUC, "totally portable" heap dumper is impossible
> without having a description of each possible heap object and ability to
> distinguish between different types of objects.

Are there such objects that need to be preserved across dumping? This
is a real question. I'm not familiar enough with emacs' internals to
know whether there are or not, but my impression is that emacs does
not need a fully general process-freeze-and-thaw dumper (in fact it
doesn't even try to be one), and my hope is that only the lisp state,
and perhaps some reasonably-trivial amount of non-lisp data with known
structure, actually needs to be preserved.

Can you or anyone else provide some answers to this question?

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:03 ` Dmitry Antipov
  2014-06-25 18:08   ` Rich Felker
@ 2014-06-25 18:20   ` Eli Zaretskii
  2014-06-25 18:32     ` Rich Felker
  2014-06-25 18:38   ` Stefan Monnier
  2 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-25 18:20 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: dalias, emacs-devel

> Date: Wed, 25 Jun 2014 22:03:36 +0400
> From: Dmitry Antipov <dmantipov@yandex.ru>
> Cc: emacs-devel@gnu.org
> 
> What about non-Lisp objects?
> 
> It's not too hard to walk through live (reachable) Lisp objects - this
> is exactly what GC mark phase does. It's not too hard to walk through
> all allocated Lisp objects - this is exactly what GC sweep phase does.
> But what about lower-level stuff allocated with malloc at invisible
> from Lisp? Of course, you can do your own serialization for these objects
> as well - but only if you know about their internal structure.

Is it possible to provide our own implementation of sbrk that
allocates memory from some large static array?  Or do modern malloc
implementations avoid calling sbrk when they need more memory?

If something like that is possible, we could do what the native and
Cygwin Windows builds already do: record all the objects, Lisp and C,
in that static array, which then gets dumped as part of the data
section.

> What about stuff allocated by some external library?

A valid concern, but I don't think we have that problem now.  If we
did, the Windows port would not be able to be built, because such
external libraries would call the malloc they were linked against, not
the replacement we provide during "-l loadup dump" phase of the build.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:08   ` Rich Felker
@ 2014-06-25 18:30     ` Dmitry Antipov
  2014-06-25 18:36       ` Rich Felker
  2014-06-25 18:36       ` Eli Zaretskii
  2014-06-25 18:41     ` Eli Zaretskii
  2014-06-26  0:16     ` Stephen J. Turnbull
  2 siblings, 2 replies; 43+ messages in thread
From: Dmitry Antipov @ 2014-06-25 18:30 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

On 06/25/2014 10:08 PM, Rich Felker wrote:

> Are there such objects that need to be preserved across dumping?

I don't know, and the worst thing is that we can't control over this.
With my debug build, 'ldd src/temacs  | wc -l' shows 112 external
libraries. What if just one of these libraries uses malloc() to allocate
an internal object in __attribute__((constructor)) function? There is no
way to handle this except intercepting all malloc() calls. This way we
move to our own heap management, which will have the same heap parsability
issues like system's malloc(), etc.

Dmitry





^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:20   ` Eli Zaretskii
@ 2014-06-25 18:32     ` Rich Felker
  2014-06-25 18:49       ` Eli Zaretskii
  2014-06-25 20:53       ` Samuel Bronson
  0 siblings, 2 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 18:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Dmitry Antipov, emacs-devel

On Wed, Jun 25, 2014 at 09:20:40PM +0300, Eli Zaretskii wrote:
> > Date: Wed, 25 Jun 2014 22:03:36 +0400
> > From: Dmitry Antipov <dmantipov@yandex.ru>
> > Cc: emacs-devel@gnu.org
> > 
> > What about non-Lisp objects?
> > 
> > It's not too hard to walk through live (reachable) Lisp objects - this
> > is exactly what GC mark phase does. It's not too hard to walk through
> > all allocated Lisp objects - this is exactly what GC sweep phase does.
> > But what about lower-level stuff allocated with malloc at invisible
> > from Lisp? Of course, you can do your own serialization for these objects
> > as well - but only if you know about their internal structure.
> 
> Is it possible to provide our own implementation of sbrk that
> allocates memory from some large static array?

That's exactly the hack I described which I'm using right now. But
since I didn't implement a free-like operation and since
load_charset_map_from_file allocates >700k every time it's called, I
had to make the static array 400MB. This obviously isn't acceptable. I
think it would work with a "real" mini-malloc implementation using the
static array, and a much smaller static array (maybe 8-15 MB) but my
attempts to write a quick one have been sloppy and buggy so far.

I would be reasonably happy with this solution (at least it would fix
the problems I'm experiencing), but I don't think it's as elegant as
fixing the portability problem completely by getting rid of the need
to dump executable binary files and instead dumping a C array. And it
doesn't fix the fact that you can't build a PIE emacs.

> Or do modern malloc
> implementations avoid calling sbrk when they need more memory?

In general avoiding using brk to expand the heap is a bad idea on
Linux since alternate methods are considerably slower and can't
automatically obtain contiguous virtual space when it's available.
However, behaviors may vary.

In musl's malloc, we use brk if it's available (note: with PIE, most
kernels give you almost no available brk space due to the way the
mappings are laid out) for extending the heap that's usef for small
allocations, and fallback to constructing a discontiguous heap with
mmap if brk fails. However musl always uses mmap for huge allocations
(greater than ~100-200k) since it has no freelists for sizes that
large and since we want to always return freed memory that large to
the system.

Also, musl does not provide a working sbrk at all, since synchronizing
with an application's use of sbrk would introduce performance costs
into all correct applications that don't poke at the brk.

> If something like that is possible, we could do what the native and
> Cygwin Windows builds already do: record all the objects, Lisp and C,
> in that static array, which then gets dumped as part of the data
> section.
> 
> > What about stuff allocated by some external library?
> 
> A valid concern, but I don't think we have that problem now.  If we
> did, the Windows port would not be able to be built, because such
> external libraries would call the malloc they were linked against, not
> the replacement we provide during "-l loadup dump" phase of the build.

Indeed.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:30     ` Dmitry Antipov
@ 2014-06-25 18:36       ` Rich Felker
  2014-06-25 18:36       ` Eli Zaretskii
  1 sibling, 0 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 18:36 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: emacs-devel

On Wed, Jun 25, 2014 at 10:30:22PM +0400, Dmitry Antipov wrote:
> On 06/25/2014 10:08 PM, Rich Felker wrote:
> 
> >Are there such objects that need to be preserved across dumping?
> 
> I don't know, and the worst thing is that we can't control over this.

Sure you can. If the lisp code doesn't reference such objects then
their existence of nonexistence is irrelevant to the new emacs
invocation after dumping.

> With my debug build, 'ldd src/temacs  | wc -l' shows 112 external
> libraries. What if just one of these libraries uses malloc() to allocate
> an internal object in __attribute__((constructor)) function?

If these libraries are shared libraries, all of that state will be
lost during dumping and reinitialized when the library is loaded again
at runtime.

As long as we're using the existing dumper system, where the whole
data segment gets written out to a new executable file, I agree
there's such a problem for static linking. But if emacs switched to
the new system I proposed, where ONLY the lisp state were dumped to a
static array, then none of these libraries' state could be saved at
all, and thus there would be no danger.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:30     ` Dmitry Antipov
  2014-06-25 18:36       ` Rich Felker
@ 2014-06-25 18:36       ` Eli Zaretskii
  1 sibling, 0 replies; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-25 18:36 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: dalias, emacs-devel

> Date: Wed, 25 Jun 2014 22:30:22 +0400
> From: Dmitry Antipov <dmantipov@yandex.ru>
> Cc: emacs-devel@gnu.org
> 
> On 06/25/2014 10:08 PM, Rich Felker wrote:
> 
> > Are there such objects that need to be preserved across dumping?
> 
> I don't know, and the worst thing is that we can't control over this.
> With my debug build, 'ldd src/temacs  | wc -l' shows 112 external
> libraries. What if just one of these libraries uses malloc() to allocate
> an internal object in __attribute__((constructor)) function?

If they do, the dumped Emacs will likely crash.  Unless these
libraries invoke those constructors again when the dumped Emacs comes
up, in which case this problem doesn't exist anyway, besides some
wasted memory that cannot be used.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:03 ` Dmitry Antipov
  2014-06-25 18:08   ` Rich Felker
  2014-06-25 18:20   ` Eli Zaretskii
@ 2014-06-25 18:38   ` Stefan Monnier
  2 siblings, 0 replies; 43+ messages in thread
From: Stefan Monnier @ 2014-06-25 18:38 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: Rich Felker, emacs-devel

> What about non-Lisp objects?

The core purpose of the dumper is to do a kind of "define functions and
variables" that's faster than loading the corresponding .elc files.

So  all we really need is basically to dump the content of the obarray
and reload it later on (if it's dumped into a C file, then it's like the
reload happens at link time).

So, the problem only appears if there are objects reachable from the
obarray which come from external libraries.


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:08   ` Rich Felker
  2014-06-25 18:30     ` Dmitry Antipov
@ 2014-06-25 18:41     ` Eli Zaretskii
  2014-06-26  0:16     ` Stephen J. Turnbull
  2 siblings, 0 replies; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-25 18:41 UTC (permalink / raw)
  To: Rich Felker; +Cc: dmantipov, emacs-devel

> Date: Wed, 25 Jun 2014 14:08:23 -0400
> From: Rich Felker <dalias@libc.org>
> Cc: emacs-devel@gnu.org
> 
> > What about non-Lisp objects?
> > 
> > It's not too hard to walk through live (reachable) Lisp objects - this
> > is exactly what GC mark phase does. It's not too hard to walk through
> > all allocated Lisp objects - this is exactly what GC sweep phase does.
> > But what about lower-level stuff allocated with malloc at invisible
> > from Lisp? Of course, you can do your own serialization for these objects
> > as well - but only if you know about their internal structure. What about
> > stuff allocated by some external library? In general, you can't parse heap
> > (i.e. looking at object, you can't say where the next object is, what is the
> > type of next object, etc.). IIUC, "totally portable" heap dumper is impossible
> > without having a description of each possible heap object and ability to
> > distinguish between different types of objects.
> 
> Are there such objects that need to be preserved across dumping? This
> is a real question. I'm not familiar enough with emacs' internals to
> know whether there are or not, but my impression is that emacs does
> not need a fully general process-freeze-and-thaw dumper (in fact it
> doesn't even try to be one), and my hope is that only the lisp state,
> and perhaps some reasonably-trivial amount of non-lisp data with known
> structure, actually needs to be preserved.
> 
> Can you or anyone else provide some answers to this question?

I don't think anyone knows the answer.  We've always dumped the entire
data segment, which includes everything, and never looked behind on
what exactly was dumped.

That said, I don't imagine we dump any non-Lisp data that is not
re-initialized after dumping anyway.  But the only way to know for
sure is to try.  E.g., run "temacs -l loadup dump" under a debugger or
some memory tracing tool, and see if there are any malloc calls that
allocate non-Lisp objects that are never freed before unexec runs.

Btw, would you like to subscribe to the list for the time being?  It
would definitely improve my life quality, as I would be spared the
need to release every of your messages for the list.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:32     ` Rich Felker
@ 2014-06-25 18:49       ` Eli Zaretskii
  2014-06-25 19:03         ` Rich Felker
  2014-06-25 20:53       ` Samuel Bronson
  1 sibling, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-25 18:49 UTC (permalink / raw)
  To: Rich Felker; +Cc: dmantipov, emacs-devel

> Date: Wed, 25 Jun 2014 14:32:41 -0400
> From: Rich Felker <dalias@libc.org>
> Cc: Dmitry Antipov <dmantipov@yandex.ru>, emacs-devel@gnu.org
> 
> > Is it possible to provide our own implementation of sbrk that
> > allocates memory from some large static array?
> 
> That's exactly the hack I described which I'm using right now. But
> since I didn't implement a free-like operation and since
> load_charset_map_from_file allocates >700k every time it's called, I
> had to make the static array 400MB.

That's not a problem, because those 700K are free'd before the next
one is allocated.  And in any case, they are all free'd before we call
unexec.  Just implement sbrk for negative increment.  The Windows port
already does that, see w32heap.c on the trunk.  It works with only
11MB of static array for 32-bit builds and 18MB for 64-bit.

> I think it would work with a "real" mini-malloc implementation using
> the static array, and a much smaller static array (maybe 8-15 MB)
> but my attempts to write a quick one have been sloppy and buggy so
> far.

If supporting deallocation in such an sbrk isn't feasible, how about
using gmalloc, as an malloc replacement before dumping?

> I would be reasonably happy with this solution (at least it would fix
> the problems I'm experiencing), but I don't think it's as elegant as
> fixing the portability problem completely by getting rid of the need
> to dump executable binary files and instead dumping a C array.

But it's conceptually much simpler and reliable.  That's "elegant" in
my book, when such hairy stuff is concerned.

> And it doesn't fix the fact that you can't build a PIE emacs.

Why is that important?



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:49       ` Eli Zaretskii
@ 2014-06-25 19:03         ` Rich Felker
  2014-06-25 19:18           ` Eli Zaretskii
  2014-06-25 20:06           ` Stefan Monnier
  0 siblings, 2 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 19:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: dmantipov, emacs-devel

On Wed, Jun 25, 2014 at 09:49:42PM +0300, Eli Zaretskii wrote:
> > Date: Wed, 25 Jun 2014 14:32:41 -0400
> > From: Rich Felker <dalias@libc.org>
> > Cc: Dmitry Antipov <dmantipov@yandex.ru>, emacs-devel@gnu.org
> > 
> > > Is it possible to provide our own implementation of sbrk that
> > > allocates memory from some large static array?
> > 
> > That's exactly the hack I described which I'm using right now. But
> > since I didn't implement a free-like operation and since
> > load_charset_map_from_file allocates >700k every time it's called, I
> > had to make the static array 400MB.
> 
> That's not a problem, because those 700K are free'd before the next
> one is allocated.  And in any case, they are all free'd before we call
> unexec.  Just implement sbrk for negative increment.  The Windows port

But load_charset_map_from_file doesn't call an sbrk-like interface; it
calls (indirectly) xmalloc and xfree. So there's at least some
nontrivial glue that goes in between.

> already does that, see w32heap.c on the trunk.  It works with only
> 11MB of static array for 32-bit builds and 18MB for 64-bit.

Nice to know.

> > I think it would work with a "real" mini-malloc implementation using
> > the static array, and a much smaller static array (maybe 8-15 MB)
> > but my attempts to write a quick one have been sloppy and buggy so
> > far.
> 
> If supporting deallocation in such an sbrk isn't feasible, how about
> using gmalloc, as an malloc replacement before dumping?

I suspect it's a lot of work to wire up gmalloc to (1) avoid
interposing on the malloc/free/etc. names, (2) use the static mini-brk
buffer, (3) only allocate from the mini-brk buffer before dumping
(otherwise pass to real malloc), but still check realloc/free calls
after dumping and handle the case where the old memory was in the
mini-brk.

What seems easier, and what I tried, is writing a completely naive
malloc with a single freelist that's linear-searched on malloc and
which does not support coalescing free chunks. But I think my
implementation has some bugs still, because it's not working. I'm not
sure if they're bugs in the allocator, or bugs in how it's used (maybe
missing some places that would have to be redirected through it and
which are still calling malloc or free directly).

> > I would be reasonably happy with this solution (at least it would fix
> > the problems I'm experiencing), but I don't think it's as elegant as
> > fixing the portability problem completely by getting rid of the need
> > to dump executable binary files and instead dumping a C array.
> 
> But it's conceptually much simpler and reliable.  That's "elegant" in
> my book, when such hairy stuff is concerned.

No, it's less reliable. See my other posts in the thread about what
happens if you have other libraries linked and they do nontrivial
things prior to dumping (e.g. from static ctors). Dumping JUST the
lisp object state in a C array ensures that none of the pre-dump state
from other libraries (or even libc) can pollute the state observed
after dumping. Both the current method, and the proposed simple fixes
above, suffer from this issue and are therefore very fragile. As an
example (I think I mentioned this earlier), if you static link, musl
libc is remembering the clock_gettime vdso pointer from the pre-dump
state and attempting to use it later (which is not valid because the
kernel maps it at a random address).

> > And it doesn't fix the fact that you can't build a PIE emacs.
> 
> Why is that important?

Since emacs is processing lots of potentially untrusted data, PIE
hardening may be beneficial for hardening against vulnerabilities
where an attacker would otherwise be able to perform arbitrary code
execution as the user running emacs. I'm not aware of such
vulnerabilities, but being that I found things that look suspiciously
like use-after-free while reading the allocator-related code, I
wouldn't be surprised if they exist.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 19:03         ` Rich Felker
@ 2014-06-25 19:18           ` Eli Zaretskii
  2014-06-25 19:57             ` Rich Felker
  2014-06-25 20:11             ` Stefan Monnier
  2014-06-25 20:06           ` Stefan Monnier
  1 sibling, 2 replies; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-25 19:18 UTC (permalink / raw)
  To: Rich Felker; +Cc: dmantipov, emacs-devel

> Date: Wed, 25 Jun 2014 15:03:33 -0400
> From: Rich Felker <dalias@libc.org>
> Cc: dmantipov@yandex.ru, emacs-devel@gnu.org
> 
> > > > Is it possible to provide our own implementation of sbrk that
> > > > allocates memory from some large static array?
> > > 
> > > That's exactly the hack I described which I'm using right now. But
> > > since I didn't implement a free-like operation and since
> > > load_charset_map_from_file allocates >700k every time it's called, I
> > > had to make the static array 400MB.
> > 
> > That's not a problem, because those 700K are free'd before the next
> > one is allocated.  And in any case, they are all free'd before we call
> > unexec.  Just implement sbrk for negative increment.  The Windows port
> 
> But load_charset_map_from_file doesn't call an sbrk-like interface; it
> calls (indirectly) xmalloc and xfree. So there's at least some
> nontrivial glue that goes in between.

Sorry, you are right.  What you need is non-toy malloc implementation
that is willing to work with your replacement sbrk.  Then support for
negative increments in sbrk isn't required.

But I still don't understand how you get to 400MB.  It's not that we
allocate hundreds of those 700K tables for charsets.  Do you have an
explanation for this?

> > If supporting deallocation in such an sbrk isn't feasible, how about
> > using gmalloc, as an malloc replacement before dumping?
> 
> I suspect it's a lot of work to wire up gmalloc to (1) avoid
> interposing on the malloc/free/etc. names, (2) use the static mini-brk
> buffer, (3) only allocate from the mini-brk buffer before dumping
> (otherwise pass to real malloc), but still check realloc/free calls
> after dumping and handle the case where the old memory was in the
> mini-brk.

Sorry, I don't see the difficulty.  Just make malloc/realloc/free be
pointers that point to gmalloc's implementation before dumping, and to
the libc implementation after it.  You may need some #define to rename
malloc to some other symbol, to avoid name clashes.  Am I missing
something?

> What seems easier, and what I tried, is writing a completely naive
> malloc with a single freelist that's linear-searched on malloc and
> which does not support coalescing free chunks. But I think my
> implementation has some bugs still, because it's not working.

The advantage of gmalloc is that it works out of the box.

> > > I would be reasonably happy with this solution (at least it would fix
> > > the problems I'm experiencing), but I don't think it's as elegant as
> > > fixing the portability problem completely by getting rid of the need
> > > to dump executable binary files and instead dumping a C array.
> > 
> > But it's conceptually much simpler and reliable.  That's "elegant" in
> > my book, when such hairy stuff is concerned.
> 
> No, it's less reliable. See my other posts in the thread about what
> happens if you have other libraries linked and they do nontrivial
> things prior to dumping (e.g. from static ctors).

But in those other posts I thought we agreed that whatever those ctors
do is irrelevant, as the dumped Emacs cannot possibly use what they
allocate, and those ctors will be invoked again in the dumped Emacs.

> As an example (I think I mentioned this earlier), if you static
> link, musl libc is remembering the clock_gettime vdso pointer from
> the pre-dump state and attempting to use it later (which is not
> valid because the kernel maps it at a random address).

You need to fix your libc to detect that it is re-exec'ed, and
re-initialize this stuff.

> > > And it doesn't fix the fact that you can't build a PIE emacs.
> > 
> > Why is that important?
> 
> Since emacs is processing lots of potentially untrusted data, PIE
> hardening may be beneficial for hardening against vulnerabilities
> where an attacker would otherwise be able to perform arbitrary code
> execution as the user running emacs. I'm not aware of such
> vulnerabilities, but being that I found things that look suspiciously
> like use-after-free while reading the allocator-related code, I
> wouldn't be surprised if they exist.

Sounds like a secondary requirement to me.  We should first make the
dumping work along these lines, and worry about bonuses later.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 19:18           ` Eli Zaretskii
@ 2014-06-25 19:57             ` Rich Felker
  2014-06-25 20:15               ` Eli Zaretskii
  2014-06-25 20:11             ` Stefan Monnier
  1 sibling, 1 reply; 43+ messages in thread
From: Rich Felker @ 2014-06-25 19:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: dmantipov, emacs-devel

On Wed, Jun 25, 2014 at 10:18:16PM +0300, Eli Zaretskii wrote:
> > Date: Wed, 25 Jun 2014 15:03:33 -0400
> > From: Rich Felker <dalias@libc.org>
> > Cc: dmantipov@yandex.ru, emacs-devel@gnu.org
> > 
> > > > > Is it possible to provide our own implementation of sbrk that
> > > > > allocates memory from some large static array?
> > > > 
> > > > That's exactly the hack I described which I'm using right now. But
> > > > since I didn't implement a free-like operation and since
> > > > load_charset_map_from_file allocates >700k every time it's called, I
> > > > had to make the static array 400MB.
> > > 
> > > That's not a problem, because those 700K are free'd before the next
> > > one is allocated.  And in any case, they are all free'd before we call
> > > unexec.  Just implement sbrk for negative increment.  The Windows port
> > 
> > But load_charset_map_from_file doesn't call an sbrk-like interface; it
> > calls (indirectly) xmalloc and xfree. So there's at least some
> > nontrivial glue that goes in between.
> 
> Sorry, you are right.  What you need is non-toy malloc implementation
> that is willing to work with your replacement sbrk.  Then support for
> negative increments in sbrk isn't required.
> 
> But I still don't understand how you get to 400MB.  It's not that we
> allocate hundreds of those 700K tables for charsets.  Do you have an
> explanation for this?

Not hundreds at a time, but if the malloc operation is just positive
(fake-)sbrk and the free operation is a nop, hundreds of such charset
load operations will quickly add up. It might have succeeded with a
little less than 400 but that was the first guess I made that didn't
run out of memory (guesses were something like 10, 50, 100, 200, 400
IIRC).

> > > If supporting deallocation in such an sbrk isn't feasible, how about
> > > using gmalloc, as an malloc replacement before dumping?
> > 
> > I suspect it's a lot of work to wire up gmalloc to (1) avoid
> > interposing on the malloc/free/etc. names, (2) use the static mini-brk
> > buffer, (3) only allocate from the mini-brk buffer before dumping
> > (otherwise pass to real malloc), but still check realloc/free calls
> > after dumping and handle the case where the old memory was in the
> > mini-brk.
> 
> Sorry, I don't see the difficulty.  Just make malloc/realloc/free be
> pointers that point to gmalloc's implementation before dumping, and to
> the libc implementation after it.  You may need some #define to rename
> malloc to some other symbol, to avoid name clashes.  Am I missing
> something?

Yeah, what happens if, after dumping, the real emacs at runtime ends
up calling free() on one of the pre-dump pointers? Can't this happen?
This is why I want the whole pre-dump heap in a single C array: so we
can range-check addresses and determine if they're pre-dump
allocations (and in that case, NOP out free and do malloc+memcpy for
realloc).

> > > > I would be reasonably happy with this solution (at least it would fix
> > > > the problems I'm experiencing), but I don't think it's as elegant as
> > > > fixing the portability problem completely by getting rid of the need
> > > > to dump executable binary files and instead dumping a C array.
> > > 
> > > But it's conceptually much simpler and reliable.  That's "elegant" in
> > > my book, when such hairy stuff is concerned.
> > 
> > No, it's less reliable. See my other posts in the thread about what
> > happens if you have other libraries linked and they do nontrivial
> > things prior to dumping (e.g. from static ctors).
> 
> But in those other posts I thought we agreed that whatever those ctors
> do is irrelevant, as the dumped Emacs cannot possibly use what they
> allocate, and those ctors will be invoked again in the dumped Emacs.

Those ctors are free to inspect global data. For example one might
contain (this sort of idiom is necessary if you can't control the
relative order of ctors): if (!init) { do_something(); init=1; }. In
that case, the dump would save the value of init, and do_something()
would fail to happen at runtime. This issue is not something that
would be added with our proposed "simple fix"; it's an issue that
EXISTS NOW if any such libraries happen to be linked statically (if
they're dynamic, the dumper will fail to see/dump the data).

> > As an example (I think I mentioned this earlier), if you static
> > link, musl libc is remembering the clock_gettime vdso pointer from
> > the pre-dump state and attempting to use it later (which is not
> > valid because the kernel maps it at a random address).
> 
> You need to fix your libc to detect that it is re-exec'ed, and
> re-initialize this stuff.

I don't see any easy way to do that that's not a big violation of
encapsulation (startup code has no business knowing about
clock_gettime internals) and the whole efficiency of static linking
(startup code does not pull in any vdso stuff; that only gets pulled
in by using a function that needs a vdso lookup). This is some big
ugliness for the sake of supporting static-linked emacs. And it ends
up being a big case of whack-a-mole. Dumping and re-execing is not a
standard usage case and is way out there in the realm of undefined
behavior. Emacs is probably the only widely-used (or even known)
program that does it.

If this issue can't be fixed easily, I'd probably just recommend to
musl users not to static link emacs, or to patch in a global ctor that
clears AT_SYSINFO_EHDR from the aux vector so that vdso doesn't get
used at all.

> > > > And it doesn't fix the fact that you can't build a PIE emacs.
> > > 
> > > Why is that important?
> > 
> > Since emacs is processing lots of potentially untrusted data, PIE
> > hardening may be beneficial for hardening against vulnerabilities
> > where an attacker would otherwise be able to perform arbitrary code
> > execution as the user running emacs. I'm not aware of such
> > vulnerabilities, but being that I found things that look suspiciously
> > like use-after-free while reading the allocator-related code, I
> > wouldn't be surprised if they exist.
> 
> Sounds like a secondary requirement to me.  We should first make the
> dumping work along these lines, and worry about bonuses later.

That's fine with me.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 19:03         ` Rich Felker
  2014-06-25 19:18           ` Eli Zaretskii
@ 2014-06-25 20:06           ` Stefan Monnier
  2014-06-25 20:24             ` Rich Felker
  1 sibling, 1 reply; 43+ messages in thread
From: Stefan Monnier @ 2014-06-25 20:06 UTC (permalink / raw)
  To: Rich Felker; +Cc: Eli Zaretskii, dmantipov, emacs-devel

> Since emacs is processing lots of potentially untrusted data, PIE
> hardening may be beneficial for hardening against vulnerabilities

IIUC what you mean by PIE, it requires a dumped Emacs where the position
of the (pre-filled) heap can change at every invocation.  If so, that
means relocation of all the pointers in the heap, at startup.

I had the impression you didn't want such relocation-at-startup (since
you used it as an argument against XEmacs-style dumping into a separate
heap file).


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 19:18           ` Eli Zaretskii
  2014-06-25 19:57             ` Rich Felker
@ 2014-06-25 20:11             ` Stefan Monnier
  1 sibling, 0 replies; 43+ messages in thread
From: Stefan Monnier @ 2014-06-25 20:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Rich Felker, dmantipov, emacs-devel

> But I still don't understand how you get to 400MB.  It's not that we
> allocate hundreds of those 700K tables for charsets.  Do you have an
> explanation for this?

Probably that when the GC collects some space and passes it to `free'
that space gets "lost" since his `free' is a no-op.
Maybe a quick fix is to tell GC not to free any blocks that it could
free, and instead keep them in its pool of blocks ready for re-use.


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 19:57             ` Rich Felker
@ 2014-06-25 20:15               ` Eli Zaretskii
  2014-06-25 20:34                 ` Rich Felker
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-25 20:15 UTC (permalink / raw)
  To: Rich Felker; +Cc: dmantipov, emacs-devel

> Date: Wed, 25 Jun 2014 15:57:30 -0400
> From: Rich Felker <dalias@libc.org>
> Cc: dmantipov@yandex.ru, emacs-devel@gnu.org
> 
> > But I still don't understand how you get to 400MB.  It's not that we
> > allocate hundreds of those 700K tables for charsets.  Do you have an
> > explanation for this?
> 
> Not hundreds at a time, but if the malloc operation is just positive
> (fake-)sbrk and the free operation is a nop, hundreds of such charset
> load operations will quickly add up.

Free operation shouldn't be a no-op, not in malloc.

And still, there are only a few (maybe 10) times we allocate these
700K tables, so 400MB sound very strange to me.

> > Sorry, I don't see the difficulty.  Just make malloc/realloc/free be
> > pointers that point to gmalloc's implementation before dumping, and to
> > the libc implementation after it.  You may need some #define to rename
> > malloc to some other symbol, to avoid name clashes.  Am I missing
> > something?
> 
> Yeah, what happens if, after dumping, the real emacs at runtime ends
> up calling free() on one of the pre-dump pointers?

You intercept the call and do nothing.

> > > No, it's less reliable. See my other posts in the thread about what
> > > happens if you have other libraries linked and they do nontrivial
> > > things prior to dumping (e.g. from static ctors).
> > 
> > But in those other posts I thought we agreed that whatever those ctors
> > do is irrelevant, as the dumped Emacs cannot possibly use what they
> > allocate, and those ctors will be invoked again in the dumped Emacs.
> 
> Those ctors are free to inspect global data. For example one might
> contain (this sort of idiom is necessary if you can't control the
> relative order of ctors): if (!init) { do_something(); init=1; }. In
> that case, the dump would save the value of init, and do_something()
> would fail to happen at runtime.

That's the same problem as with your clock_gettime, and it must be
fixed anyway, because any ctor run at dump time is almost certainly
picking up data that is irrelevant to the run time.

> > > As an example (I think I mentioned this earlier), if you static
> > > link, musl libc is remembering the clock_gettime vdso pointer from
> > > the pre-dump state and attempting to use it later (which is not
> > > valid because the kernel maps it at a random address).
> > 
> > You need to fix your libc to detect that it is re-exec'ed, and
> > re-initialize this stuff.
> 
> I don't see any easy way to do that that's not a big violation of
> encapsulation (startup code has no business knowing about
> clock_gettime internals) and the whole efficiency of static linking
> (startup code does not pull in any vdso stuff; that only gets pulled
> in by using a function that needs a vdso lookup).

One way is to have a counter that gets incremented each re-exec.  Then
the initialization code of clock_gettime could examine the counter and
re-initialize when its value changes since last time.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 20:06           ` Stefan Monnier
@ 2014-06-25 20:24             ` Rich Felker
  2014-06-25 21:43               ` Stefan Monnier
  2014-06-25 22:33               ` Andreas Schwab
  0 siblings, 2 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 20:24 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, dmantipov, emacs-devel

On Wed, Jun 25, 2014 at 04:06:33PM -0400, Stefan Monnier wrote:
> > Since emacs is processing lots of potentially untrusted data, PIE
> > hardening may be beneficial for hardening against vulnerabilities
> 
> IIUC what you mean by PIE, it requires a dumped Emacs where the position
> of the (pre-filled) heap can change at every invocation.  If so, that
> means relocation of all the pointers in the heap, at startup.

With the approach of dumping a C array containing references to
offsets within itself, this is completely transparent to the
application. The linker (ld) produces the right R_${ARCH}_RELATIVE
relocation records in the data segment and the dynamic linker applies
them at runtime.

> I had the impression you didn't want such relocation-at-startup (since
> you used it as an argument against XEmacs-style dumping into a separate
> heap file).

I didn't mean for that to be "an argument against XEmacs-style
dumping" since the XEmacs style is still much better than what GNU
emacs has now, simply an observation that it's not the ideal system.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 20:15               ` Eli Zaretskii
@ 2014-06-25 20:34                 ` Rich Felker
  2014-06-26  2:44                   ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Rich Felker @ 2014-06-25 20:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: dmantipov, emacs-devel

On Wed, Jun 25, 2014 at 11:15:02PM +0300, Eli Zaretskii wrote:
> > Date: Wed, 25 Jun 2014 15:57:30 -0400
> > From: Rich Felker <dalias@libc.org>
> > Cc: dmantipov@yandex.ru, emacs-devel@gnu.org
> > 
> > > But I still don't understand how you get to 400MB.  It's not that we
> > > allocate hundreds of those 700K tables for charsets.  Do you have an
> > > explanation for this?
> > 
> > Not hundreds at a time, but if the malloc operation is just positive
> > (fake-)sbrk and the free operation is a nop, hundreds of such charset
> > load operations will quickly add up.
> 
> Free operation shouldn't be a no-op, not in malloc.

Agreed. But the question was about why my quick hack took 400MB, and
the answer is that it was using a static fake-brk with malloc=sbrk and
free=nop.

> And still, there are only a few (maybe 10) times we allocate these
> 700K tables, so 400MB sound very strange to me.

In my log, I see 768k allocations occuring roughly 94 times. Is it
possible that the temacs --batch commands I'm testing (IIRC taken from
commands that were failing in leim/Makefile, but perhaps I changed it
in some way I didn't notice?) are pulling in my .emacs file, which
might be causing more charsets to be loaded?

> > > Sorry, I don't see the difficulty.  Just make malloc/realloc/free be
> > > pointers that point to gmalloc's implementation before dumping, and to
> > > the libc implementation after it.  You may need some #define to rename
> > > malloc to some other symbol, to avoid name clashes.  Am I missing
> > > something?
> > 
> > Yeah, what happens if, after dumping, the real emacs at runtime ends
> > up calling free() on one of the pre-dump pointers?
> 
> You intercept the call and do nothing.

Right, but the free pointer can't directly point to the real (libc)
free. It has to point to the wrapper that does this range-check.

> > > > No, it's less reliable. See my other posts in the thread about what
> > > > happens if you have other libraries linked and they do nontrivial
> > > > things prior to dumping (e.g. from static ctors).
> > > 
> > > But in those other posts I thought we agreed that whatever those ctors
> > > do is irrelevant, as the dumped Emacs cannot possibly use what they
> > > allocate, and those ctors will be invoked again in the dumped Emacs.
> > 
> > Those ctors are free to inspect global data. For example one might
> > contain (this sort of idiom is necessary if you can't control the
> > relative order of ctors): if (!init) { do_something(); init=1; }. In
> > that case, the dump would save the value of init, and do_something()
> > would fail to happen at runtime.
> 
> That's the same problem as with your clock_gettime, and it must be
> fixed anyway, because any ctor run at dump time is almost certainly
> picking up data that is irrelevant to the run time.

Libc could _possibly_ work around it by virtue of having full control
over the init code. For other libraries, the issue is not fixable (see
my above example with code that has to control dependency order of
ctors), and shouldn't have to be fixed. If the library is written such
that static objects have a particular nominal initial value at the
source level, it should be able to rely on that value actually being
present at runtime. Failure to provide this guarantee is a bug in the
runtime (in this case, in the tool which produced the ELF file, i.e.
unexelf.c).

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:32     ` Rich Felker
  2014-06-25 18:49       ` Eli Zaretskii
@ 2014-06-25 20:53       ` Samuel Bronson
  2014-06-25 21:24         ` Rich Felker
  1 sibling, 1 reply; 43+ messages in thread
From: Samuel Bronson @ 2014-06-25 20:53 UTC (permalink / raw)
  To: Rich Felker; +Cc: Eli Zaretskii, Dmitry Antipov, emacs-devel

On 6/25/14, Rich Felker <dalias@libc.org> wrote:

> In musl's malloc, we use brk if it's available (note: with PIE, most
> kernels give you almost no available brk space due to the way the
> mappings are laid out) [...]

Yeah, that tiny gap has bitten in other ways, too:
<http://www.postgresql.org/message-id/20140519115318.GB7296@msgid.df7cb.de>
talks about a stack overflow with the same cause; I really think the
kernel should stop doing that.

> Also, musl does not provide a working sbrk at all, since synchronizing
> with an application's use of sbrk would introduce performance costs
> into all correct applications that don't poke at the brk.

Looking at the manpage, I can't really follow how having sbrk() would
involve a slowdown in everything?  Do you mean that musl's malloc gets
a speed bonus out of assuming it's the sole user of brk()/sbrk(), and
thus the whole region from the initial brk()point to the current
brk()point is belongs to it?  (Yeah, all (potentially) 125 MiB -
stacksize of it!)



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 20:53       ` Samuel Bronson
@ 2014-06-25 21:24         ` Rich Felker
  0 siblings, 0 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 21:24 UTC (permalink / raw)
  To: Samuel Bronson; +Cc: Eli Zaretskii, Dmitry Antipov, emacs-devel

On Wed, Jun 25, 2014 at 04:53:58PM -0400, Samuel Bronson wrote:
> On 6/25/14, Rich Felker <dalias@libc.org> wrote:
> 
> > In musl's malloc, we use brk if it's available (note: with PIE, most
> > kernels give you almost no available brk space due to the way the
> > mappings are laid out) [...]
> 
> Yeah, that tiny gap has bitten in other ways, too:
> <http://www.postgresql.org/message-id/20140519115318.GB7296@msgid.df7cb.de>
> talks about a stack overflow with the same cause; I really think the
> kernel should stop doing that.

Agreed. But it was a big enough issue (basically a show-stopper for
using PIE) that I just added a simple way to use mmap without having
to care about discontiguity because the waste is asymptotically zero.

> > Also, musl does not provide a working sbrk at all, since synchronizing
> > with an application's use of sbrk would introduce performance costs
> > into all correct applications that don't poke at the brk.
> 
> Looking at the manpage, I can't really follow how having sbrk() would
> involve a slowdown in everything? Do you mean that musl's malloc gets
> a speed bonus out of assuming it's the sole user of brk()/sbrk(), and
> thus the whole region from the initial brk()point to the current
> brk()point is belongs to it?

Yes, basically. malloc simply assumes the brk is where it last left
it, rather than querying it again, which would double the syscall
overhead. This could be avoided via a cooperating lock between sbrk
and malloc, but basically after sbrk touches the brk, malloc could not
safely use it anymore; if it did, the application might later clobber
malloc's heap.

brk/sbrk are documented as not being usable if malloc is used (see
http://pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html) and they
were later removed from the standards because that essentially makes
it impossible to use them at all.

There's an ongoing discussion on whether it's desirable to provide an
emulated sbrk for legacy applications (note: these applications would
not work with real sbrk anyway if compiled as PIE!) but since there
are basically no users of brk/sbrk left except malloc implementations,
nobody has really cared much one way or the other whether it gets
added.

> (Yeah, all (potentially) 125 MiB -
> stacksize of it!)

I don't follow. brk has nothing to do with the stack, and in practice
it can obtain nearly the full 3GB (for 32-bit) of available virtual
address space in non-PIE programs.

Anyway, discussion of musl's malloc implementation is largely
off-topic to this discussion except insomuch as it reflects the
diversity of implementation possibilities that it would be nice for
emacs to support without ugly hacks. I'd rather this thread not be
"please change emacs because __________ in musl" but rather "let's
address a long-standing portability issue in emacs in such a way that
it won't come up again, and possibly gives other benefits like support
for PIE and fixing ugly corner-cases that are going to arise now that
modern emacs is linking so many libraries".

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 20:24             ` Rich Felker
@ 2014-06-25 21:43               ` Stefan Monnier
  2014-06-25 22:07                 ` Rich Felker
  2014-06-25 22:33               ` Andreas Schwab
  1 sibling, 1 reply; 43+ messages in thread
From: Stefan Monnier @ 2014-06-25 21:43 UTC (permalink / raw)
  To: Rich Felker; +Cc: Eli Zaretskii, dmantipov, emacs-devel

> With the approach of dumping a C array containing references to
> offsets within itself, this is completely transparent to the
> application. The linker (ld) produces the right R_${ARCH}_RELATIVE
> relocation records in the data segment and the dynamic linker applies
> them at runtime.

Two problems, here:
- we're still talking about performing relocation of all heap references
  during startup (not that it's a problem, of course).  Maybe we don't
  need to do it ourselves, but it still has to happen.
- Can the ld.so loader generate the *tagged* references used in the heap?


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 21:43               ` Stefan Monnier
@ 2014-06-25 22:07                 ` Rich Felker
  2014-06-25 23:04                   ` Paul Eggert
                                     ` (2 more replies)
  0 siblings, 3 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 22:07 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, dmantipov, emacs-devel

On Wed, Jun 25, 2014 at 05:43:00PM -0400, Stefan Monnier wrote:
> > With the approach of dumping a C array containing references to
> > offsets within itself, this is completely transparent to the
> > application. The linker (ld) produces the right R_${ARCH}_RELATIVE
> > relocation records in the data segment and the dynamic linker applies
> > them at runtime.
> 
> Two problems, here:
> - we're still talking about performing relocation of all heap references
>   during startup (not that it's a problem, of course).  Maybe we don't
>   need to do it ourselves, but it still has to happen.

Indeed. The difference is just between having to write non-portable
code that does it manually, and having it happen automatically as
consequences of the requirements of the C language.

> - Can the ld.so loader generate the *tagged* references used in the heap?

My understanding is that the tagged references are using the low bits
of otherwise-aligned pointers as flags. Is this correct? If so, then
these are just constant offsets applied to an address, and thus they
are still valid C address constant expressions, so they have to be
supported.

My understanding is that emacs also supports a mode for targets where
alignment up to 8 bytes cannot be guaranteed, where the high bits of
the pointer are used rather than the low bits, and where all pointers
are required to reside in "low addresses". This should also be able to
be supported at the dynamic-linker level as an addend. But at the C
source level, it's undefined behavior since the offsets go outside the
range of the array object. Of course this model is also incompatible
with PIE and with most modern systems where malloc may return "high"
addresses, and thereby likely buggy even on the systems it's currently
used on (if any). It could probably be fixed by using mmap to ensure
that the entire "high" memory space is filled with PROT_NONE mappings
before doing anything else, though, but I think fixing this build mode
is low priority since, in practice, all modern targets support 8-byte
alignment.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 20:24             ` Rich Felker
  2014-06-25 21:43               ` Stefan Monnier
@ 2014-06-25 22:33               ` Andreas Schwab
  1 sibling, 0 replies; 43+ messages in thread
From: Andreas Schwab @ 2014-06-25 22:33 UTC (permalink / raw)
  To: Rich Felker; +Cc: Eli Zaretskii, dmantipov, Stefan Monnier, emacs-devel

Rich Felker <dalias@libc.org> writes:

> With the approach of dumping a C array containing references to
> offsets within itself, this is completely transparent to the
> application. The linker (ld) produces the right R_${ARCH}_RELATIVE
> relocation records in the data segment and the dynamic linker applies
> them at runtime.

1. Relocations are highly architecture dependent.  2. Relocations only
apply to compiler-generated references, not runtime references.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 22:07                 ` Rich Felker
@ 2014-06-25 23:04                   ` Paul Eggert
  2014-06-25 23:21                     ` Rich Felker
  2014-06-25 23:05                   ` Stefan Monnier
  2014-06-26  3:02                   ` Dmitry Antipov
  2 siblings, 1 reply; 43+ messages in thread
From: Paul Eggert @ 2014-06-25 23:04 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

Rich Felker wrote:
> this model is also incompatible
> with PIE and with most modern systems where malloc may return "high"
> addresses, and thereby likely buggy even on the systems it's currently
> used on (if any).

The model works just fine on a typical modern 32-bit host, so long as 
you configure --with-wide-int.  That's because the 32-bit addresses fit 
comfortably in the low half of 64-bit integers.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 22:07                 ` Rich Felker
  2014-06-25 23:04                   ` Paul Eggert
@ 2014-06-25 23:05                   ` Stefan Monnier
  2014-06-25 23:19                     ` Rich Felker
  2014-06-26  3:02                   ` Dmitry Antipov
  2 siblings, 1 reply; 43+ messages in thread
From: Stefan Monnier @ 2014-06-25 23:05 UTC (permalink / raw)
  To: Rich Felker; +Cc: Eli Zaretskii, dmantipov, emacs-devel

>> - we're still talking about performing relocation of all heap references
>> during startup (not that it's a problem, of course).  Maybe we don't
>> need to do it ourselves, but it still has to happen.
> Indeed. The difference is just between having to write non-portable
> code that does it manually, and having it happen automatically as
> consequences of the requirements of the C language.

The manual code would be fairly normal C code, very similar to the
mark_object routine.  It shouldn't be noticeably less portable than the
current pointer<->int conversions we use for tagging purposes.

Of course, it's always nice when we can use someone else's code, but
I get the impression that to get the right behavior from the
compiler/linker/loader we may have to generate a fairly enormous C file
which will generate an enormous .o file and the resulting binary will
end up with a humongous relocation table.

Of course, only time will tell.

> My understanding is that the tagged references are using the low bits
> of otherwise-aligned pointers as flags. Is this correct? If so, then
> these are just constant offsets applied to an address, and thus they
> are still valid C address constant expressions, so they have to be
> supported.

Indeed, it might work.


        Stefan



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 23:05                   ` Stefan Monnier
@ 2014-06-25 23:19                     ` Rich Felker
  0 siblings, 0 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 23:19 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, dmantipov, emacs-devel

On Wed, Jun 25, 2014 at 07:05:14PM -0400, Stefan Monnier wrote:
> >> - we're still talking about performing relocation of all heap references
> >> during startup (not that it's a problem, of course).  Maybe we don't
> >> need to do it ourselves, but it still has to happen.
> > Indeed. The difference is just between having to write non-portable
> > code that does it manually, and having it happen automatically as
> > consequences of the requirements of the C language.
> 
> The manual code would be fairly normal C code, very similar to the
> mark_object routine.  It shouldn't be noticeably less portable than the
> current pointer<->int conversions we use for tagging purposes.
> 
> Of course, it's always nice when we can use someone else's code, but
> I get the impression that to get the right behavior from the
> compiler/linker/loader we may have to generate a fairly enormous C file
> which will generate an enormous .o file and the resulting binary will
> end up with a humongous relocation table.

For non-PIE emacs, the relocations would only exist in the .o file,
which would only be "enormous" to the extent that the actual data is
(IIRC roughly 11 megs for 32-bit and 16 megs for 64-bit). For PIE,
the relocations are carried over to the executable, but they're all
relative (not symbolic) and thus trivial from a performance
standpoint.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 23:04                   ` Paul Eggert
@ 2014-06-25 23:21                     ` Rich Felker
  0 siblings, 0 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-25 23:21 UTC (permalink / raw)
  To: Paul Eggert; +Cc: emacs-devel

On Wed, Jun 25, 2014 at 04:04:26PM -0700, Paul Eggert wrote:
> Rich Felker wrote:
> >this model is also incompatible
> >with PIE and with most modern systems where malloc may return "high"
> >addresses, and thereby likely buggy even on the systems it's currently
> >used on (if any).
> 
> The model works just fine on a typical modern 32-bit host, so long
> as you configure --with-wide-int.  That's because the 32-bit
> addresses fit comfortably in the low half of 64-bit integers.

I see. I wasn't aware of that option. In any case it would work just
fine with the proposed C static array output: for 32-bit pointers, the
lower 32 bits would actually be the address constant reference and the
upper 32 bits would be an integer constant expression.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 18:08   ` Rich Felker
  2014-06-25 18:30     ` Dmitry Antipov
  2014-06-25 18:41     ` Eli Zaretskii
@ 2014-06-26  0:16     ` Stephen J. Turnbull
  2 siblings, 0 replies; 43+ messages in thread
From: Stephen J. Turnbull @ 2014-06-26  0:16 UTC (permalink / raw)
  To: Rich Felker; +Cc: Dmitry Antipov, emacs-devel

Rich Felker writes:

 > Can you or anyone else provide some answers to this question?

Sure.  src/dumper.c and the memory description objects in the XEmacs
sources.  If it's not tracked there (such as buffers and internal file
objects), then it's an implementation restriction but we havent't
needed it in practice, so a good first cut for you is to leave it out.
If it is handled there, then you can think about whether you need to
worry about it in your scheme or not.





^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 20:34                 ` Rich Felker
@ 2014-06-26  2:44                   ` Eli Zaretskii
  2014-06-26  4:28                     ` Rich Felker
  0 siblings, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-26  2:44 UTC (permalink / raw)
  To: Rich Felker; +Cc: dmantipov, emacs-devel

> Date: Wed, 25 Jun 2014 16:34:03 -0400
> From: Rich Felker <dalias@libc.org>
> Cc: dmantipov@yandex.ru, emacs-devel@gnu.org
> 
> > And still, there are only a few (maybe 10) times we allocate these
> > 700K tables, so 400MB sound very strange to me.
> 
> In my log, I see 768k allocations occuring roughly 94 times.

768K times 94 doesn't get anywhere close to 400MB.

> Is it possible that the temacs --batch commands I'm testing (IIRC
> taken from commands that were failing in leim/Makefile, but perhaps
> I changed it in some way I didn't notice?) are pulling in my .emacs
> file, which might be causing more charsets to be loaded?

No, it's more probable that I was mistaken about the count.  But
still, 400MB sounds way too much.

> > > > Sorry, I don't see the difficulty.  Just make malloc/realloc/free be
> > > > pointers that point to gmalloc's implementation before dumping, and to
> > > > the libc implementation after it.  You may need some #define to rename
> > > > malloc to some other symbol, to avoid name clashes.  Am I missing
> > > > something?
> > > 
> > > Yeah, what happens if, after dumping, the real emacs at runtime ends
> > > up calling free() on one of the pre-dump pointers?
> > 
> > You intercept the call and do nothing.
> 
> Right, but the free pointer can't directly point to the real (libc)
> free. It has to point to the wrapper that does this range-check.

Right.

> > > Those ctors are free to inspect global data. For example one might
> > > contain (this sort of idiom is necessary if you can't control the
> > > relative order of ctors): if (!init) { do_something(); init=1; }. In
> > > that case, the dump would save the value of init, and do_something()
> > > would fail to happen at runtime.
> > 
> > That's the same problem as with your clock_gettime, and it must be
> > fixed anyway, because any ctor run at dump time is almost certainly
> > picking up data that is irrelevant to the run time.
> 
> Libc could _possibly_ work around it by virtue of having full control
> over the init code. For other libraries, the issue is not fixable (see
> my above example with code that has to control dependency order of
> ctors), and shouldn't have to be fixed.

But the problem likely doesn't exist, because otherwise we will have
known about it by now.  Emacs cannot use such libraries.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-25 22:07                 ` Rich Felker
  2014-06-25 23:04                   ` Paul Eggert
  2014-06-25 23:05                   ` Stefan Monnier
@ 2014-06-26  3:02                   ` Dmitry Antipov
  2014-06-26  4:14                     ` Rich Felker
  2 siblings, 1 reply; 43+ messages in thread
From: Dmitry Antipov @ 2014-06-26  3:02 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

BTW, if you're doing your own libc, why do not implement Solaris-style dldump()?

Dmitry




^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-26  3:02                   ` Dmitry Antipov
@ 2014-06-26  4:14                     ` Rich Felker
  2014-06-26  4:32                       ` Dmitry Antipov
  0 siblings, 1 reply; 43+ messages in thread
From: Rich Felker @ 2014-06-26  4:14 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: emacs-devel

On Thu, Jun 26, 2014 at 07:02:40AM +0400, Dmitry Antipov wrote:
> BTW, if you're doing your own libc, why do not implement Solaris-style dldump()?

Because dumping isn't really possible to do in a correct and
meaningful way without serious restrictions on what the code can do.
See Eli Zaretskii's email (Message-id: <83simspexv.fsf@gnu.org>)
stating that "Emacs cannot use such libraries." For a single
application like Emacs that's a decision that can be made. But to say
"[X feature of] libc can't support such code" when the code is
perfectly valid C is not really appropriate.

There's all sorts of state that cannot be preserved across dumping but
that's completely reasonable to have, such as pid, lock owners (tids
will not be the same after a dump), open files, etc. At one point I
actually tried to do a Solaris-style forkall() -- I mention this
because it has a lot of the same issues -- and partly had it working,
but the lock ownership issue turned out to be impractical to solve and
I abandoned it.


Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-26  2:44                   ` Eli Zaretskii
@ 2014-06-26  4:28                     ` Rich Felker
  2014-06-26 15:02                       ` Eli Zaretskii
  0 siblings, 1 reply; 43+ messages in thread
From: Rich Felker @ 2014-06-26  4:28 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: dmantipov, emacs-devel

On Thu, Jun 26, 2014 at 05:44:44AM +0300, Eli Zaretskii wrote:
> > Date: Wed, 25 Jun 2014 16:34:03 -0400
> > From: Rich Felker <dalias@libc.org>
> > Cc: dmantipov@yandex.ru, emacs-devel@gnu.org
> > 
> > > And still, there are only a few (maybe 10) times we allocate these
> > > 700K tables, so 400MB sound very strange to me.
> > 
> > In my log, I see 768k allocations occuring roughly 94 times.
> 
> 768K times 94 doesn't get anywhere close to 400MB.

Yes, there were also a number of ~200k and ~400k allocations though,
which I did not get around to identifying the source of.

> > > > Those ctors are free to inspect global data. For example one might
> > > > contain (this sort of idiom is necessary if you can't control the
> > > > relative order of ctors): if (!init) { do_something(); init=1; }. In
> > > > that case, the dump would save the value of init, and do_something()
> > > > would fail to happen at runtime.
> > > 
> > > That's the same problem as with your clock_gettime, and it must be
> > > fixed anyway, because any ctor run at dump time is almost certainly
> > > picking up data that is irrelevant to the run time.
> > 
> > Libc could _possibly_ work around it by virtue of having full control
> > over the init code. For other libraries, the issue is not fixable (see
> > my above example with code that has to control dependency order of
> > ctors), and shouldn't have to be fixed.
> 
> But the problem likely doesn't exist, because otherwise we will have
> known about it by now.  Emacs cannot use such libraries.

I wouldn't be so sure. How much testing is even done with static
linking? With dynamic linking, the library's state will all be lost
across dump. Lots of the libraries emacs can optionally use have
sketchy global state, and I wouldn't be surprised at all if at least
one of them were failing to properly initialize in the post-dump
emacs. The symptoms might not even be immediately visible if the state
saved when dumping were "close enough" to correct to be used
post-dump.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-26  4:14                     ` Rich Felker
@ 2014-06-26  4:32                       ` Dmitry Antipov
  2014-06-26 11:49                         ` Rich Felker
  2014-06-26 15:03                         ` Eli Zaretskii
  0 siblings, 2 replies; 43+ messages in thread
From: Dmitry Antipov @ 2014-06-26  4:32 UTC (permalink / raw)
  To: Rich Felker; +Cc: emacs-devel

On 06/26/2014 08:14 AM, Rich Felker wrote:

> Because dumping isn't really possible to do in a correct and
> meaningful way without serious restrictions on what the code can do.

What do you think about this project: http://dmtcp.sourceforge.net/index.html?

 From their point of view, Emacs dumping is just a checkpointing in
the very special moment (when all Lisp libraries are loaded).

Dmitry




^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-26  4:32                       ` Dmitry Antipov
@ 2014-06-26 11:49                         ` Rich Felker
  2014-06-26 15:03                         ` Eli Zaretskii
  1 sibling, 0 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-26 11:49 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: emacs-devel

On Thu, Jun 26, 2014 at 08:32:55AM +0400, Dmitry Antipov wrote:
> On 06/26/2014 08:14 AM, Rich Felker wrote:
> 
> >Because dumping isn't really possible to do in a correct and
> >meaningful way without serious restrictions on what the code can do.
> 
> What do you think about this project: http://dmtcp.sourceforge.net/index.html?
> 
> From their point of view, Emacs dumping is just a checkpointing in
> the very special moment (when all Lisp libraries are loaded).

I consider dumping and checkpointing very different problems. With
dumping you just want to pre-generate and preserve some particular
data for future runs of the program, but you want these future runs to
behave as new processes with their own command lines, environment,
clean slate of open files, etc. With checkpointing, you want the
application not to even see that it was restarted. They also require
drastically different tools for implementation, e.g. non-hackish
checkpointing requires something like Linux namespaces so that the new
process (or family of processes, as some apps may be) sees itself as
having its original pid (and possibly pid tree), etc.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-26  4:28                     ` Rich Felker
@ 2014-06-26 15:02                       ` Eli Zaretskii
  0 siblings, 0 replies; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-26 15:02 UTC (permalink / raw)
  To: Rich Felker; +Cc: dmantipov, emacs-devel

> Date: Thu, 26 Jun 2014 00:28:39 -0400
> From: Rich Felker <dalias@libc.org>
> Cc: dmantipov@yandex.ru, emacs-devel@gnu.org
> 
> > > In my log, I see 768k allocations occuring roughly 94 times.
> > 
> > 768K times 94 doesn't get anywhere close to 400MB.
> 
> Yes, there were also a number of ~200k and ~400k allocations though,
> which I did not get around to identifying the source of.

If your 'free' is a no-op, I guess it could explain any number,
including 400MB.

Once again, I suggest to use gmalloc, or some existing less simplistic
implementation, instead.

Or, put it another way: if MS-Windows provides a way to use the libc
malloc with a custom 'sbrk' function, then perhaps the free software
platforms should have a similar feature as well (if they don't
already).  Once such a feature is provided, we could supply such a
custom 'sbrk' for the dumping phase, which will put all the data in a
static array, which will cleanly solve this issue for the observable
future.

> > > > > Those ctors are free to inspect global data. For example one might
> > > > > contain (this sort of idiom is necessary if you can't control the
> > > > > relative order of ctors): if (!init) { do_something(); init=1; }. In
> > > > > that case, the dump would save the value of init, and do_something()
> > > > > would fail to happen at runtime.
> > > > 
> > > > That's the same problem as with your clock_gettime, and it must be
> > > > fixed anyway, because any ctor run at dump time is almost certainly
> > > > picking up data that is irrelevant to the run time.
> > > 
> > > Libc could _possibly_ work around it by virtue of having full control
> > > over the init code. For other libraries, the issue is not fixable (see
> > > my above example with code that has to control dependency order of
> > > ctors), and shouldn't have to be fixed.
> > 
> > But the problem likely doesn't exist, because otherwise we will have
> > known about it by now.  Emacs cannot use such libraries.
> 
> I wouldn't be so sure. How much testing is even done with static
> linking?

In the past, quite a lot (the Emacs dumping method didn't change
significantly since about day one).  Nowadays, I don't think it is
tested much, except in the DJGPP (a.k.a. "MS-DOS") build of Emacs,
which uses static linking exclusively, because DJGPP doesn't support
shared libraries.  DJGPP's libc implements the startup code trick I
mentioned that forces reinitialization of state by functions which
need that, when they are first called in the dumped Emacs.  What's
left can be seen in unexcoff.c, where some of the global state is
explicitly reverted to its initial state before writing the image to
disk, see there in 'copy_text_and_data'.  Btw, one of these is the
'atexit' chain, which is probably relevant to other systems, if and
when they are statically linked.

> With dynamic linking, the library's state will all be lost
> across dump. Lots of the libraries emacs can optionally use have
> sketchy global state, and I wouldn't be surprised at all if at least
> one of them were failing to properly initialize in the post-dump
> emacs. The symptoms might not even be immediately visible if the state
> saved when dumping were "close enough" to correct to be used
> post-dump.

But if static linking is not used anymore on supported platforms
(putting MS-DOS aside), then this is not an issue, right?



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-26  4:32                       ` Dmitry Antipov
  2014-06-26 11:49                         ` Rich Felker
@ 2014-06-26 15:03                         ` Eli Zaretskii
  2014-06-26 15:10                           ` Rich Felker
  1 sibling, 1 reply; 43+ messages in thread
From: Eli Zaretskii @ 2014-06-26 15:03 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: dalias, emacs-devel

> Date: Thu, 26 Jun 2014 08:32:55 +0400
> From: Dmitry Antipov <dmantipov@yandex.ru>
> Cc: emacs-devel@gnu.org
> 
> What do you think about this project: http://dmtcp.sourceforge.net/index.html?
> 
>  From their point of view, Emacs dumping is just a checkpointing in
> the very special moment (when all Lisp libraries are loaded).

Yes, but their main focus is to preserve the system-side parts of the
program, like IP buffers and file descriptors, something that we
certainly don't want.



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: Dumper problems and a possible solutions
  2014-06-26 15:03                         ` Eli Zaretskii
@ 2014-06-26 15:10                           ` Rich Felker
  0 siblings, 0 replies; 43+ messages in thread
From: Rich Felker @ 2014-06-26 15:10 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Dmitry Antipov, emacs-devel

On Thu, Jun 26, 2014 at 06:03:33PM +0300, Eli Zaretskii wrote:
> > Date: Thu, 26 Jun 2014 08:32:55 +0400
> > From: Dmitry Antipov <dmantipov@yandex.ru>
> > Cc: emacs-devel@gnu.org
> > 
> > What do you think about this project: http://dmtcp.sourceforge.net/index.html?
> > 
> >  From their point of view, Emacs dumping is just a checkpointing in
> > the very special moment (when all Lisp libraries are loaded).
> 
> Yes, but their main focus is to preserve the system-side parts of the
> program, like IP buffers and file descriptors, something that we
> certainly don't want.

Indeed, this is why I consider emacs-style dumping and checkpointing
as essentially different problem domains.

Rich



^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2014-06-26 15:10 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-24 17:19 Dumper problems and a possible solutions Rich Felker
2014-06-24 19:27 ` Stefan Monnier
2014-06-24 19:40   ` Rich Felker
2014-06-24 20:24     ` Stefan Monnier
2014-06-24 21:15       ` Rich Felker
2014-06-24 21:37         ` Stefan Monnier
2014-06-25 18:03 ` Dmitry Antipov
2014-06-25 18:08   ` Rich Felker
2014-06-25 18:30     ` Dmitry Antipov
2014-06-25 18:36       ` Rich Felker
2014-06-25 18:36       ` Eli Zaretskii
2014-06-25 18:41     ` Eli Zaretskii
2014-06-26  0:16     ` Stephen J. Turnbull
2014-06-25 18:20   ` Eli Zaretskii
2014-06-25 18:32     ` Rich Felker
2014-06-25 18:49       ` Eli Zaretskii
2014-06-25 19:03         ` Rich Felker
2014-06-25 19:18           ` Eli Zaretskii
2014-06-25 19:57             ` Rich Felker
2014-06-25 20:15               ` Eli Zaretskii
2014-06-25 20:34                 ` Rich Felker
2014-06-26  2:44                   ` Eli Zaretskii
2014-06-26  4:28                     ` Rich Felker
2014-06-26 15:02                       ` Eli Zaretskii
2014-06-25 20:11             ` Stefan Monnier
2014-06-25 20:06           ` Stefan Monnier
2014-06-25 20:24             ` Rich Felker
2014-06-25 21:43               ` Stefan Monnier
2014-06-25 22:07                 ` Rich Felker
2014-06-25 23:04                   ` Paul Eggert
2014-06-25 23:21                     ` Rich Felker
2014-06-25 23:05                   ` Stefan Monnier
2014-06-25 23:19                     ` Rich Felker
2014-06-26  3:02                   ` Dmitry Antipov
2014-06-26  4:14                     ` Rich Felker
2014-06-26  4:32                       ` Dmitry Antipov
2014-06-26 11:49                         ` Rich Felker
2014-06-26 15:03                         ` Eli Zaretskii
2014-06-26 15:10                           ` Rich Felker
2014-06-25 22:33               ` Andreas Schwab
2014-06-25 20:53       ` Samuel Bronson
2014-06-25 21:24         ` Rich Felker
2014-06-25 18:38   ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).