Assert in DYLDRendezvous::UpdateSOEntries

I just hit the below assert on line 138 stepping over a dlclose().

120| bool
121| DYLDRendezvous::UpdateSOEntries()
122| {
123| SOEntry entry;
124|
125| if (m_current.map_addr == 0)
126| return false;
127|
128| // When the previous and current states are consistent this is the first
129| // time we have been asked to update. Just take a snapshot of the currently
130| // loaded modules.
131| if (m_previous.state == eConsistent && m_current.state == eConsistent)
132| return TakeSnapshot(m_soentries);
133|
134| // If we are about to add or remove a shared object clear out the current
135| // state and take a snapshot of the currently loaded images.
136| if (m_current.state == eAdd || m_current.state == eDelete)
137| {
138+> assert(m_previous.state == eConsistent);
139| m_soentries.clear();
140| m_added_soentries.clear();
141| m_removed_soentries.clear();
142| return TakeSnapshot(m_soentries);
143| }

It’s called by this code in DYLDRendezvous::Resolve():

106| // The rendezvous was successfully read. Update our internal state.
107| m_rendezvous_addr = info_addr;
108| m_previous = m_current;
109| m_current = info;
110|
111+> return UpdateSOEntries();

m_previous is being set to m_current and both are eDelete now, but that assert above is claiming it should be eConsistent.

Is this a bogus assert, or is the Resolve() function messing with m_previous when it shouldn’t be?
-Mike

Unfortunately, the original author of the majority of the original POSIX/Linux code isn't around anymore.

However, looking into the issue, I think the code here is expecting an eConsistent state after an eAdd/eDelete since the library entries don't get updated until you actually get the eConsistent state. This is probably why there is an m_previous and m_current.

Maybe the behaviour you see is ok. I'm not sure. I think better understanding of the system dynamic linker/loader behaviour here may be needed.

Curiously, do you get the same assert without a step? i.e. just running?

Thanks,
Matt

No. And, actually, it turns out I don't always get it stepping over the
dlclose(). I just tried to sprinkle some printfs() in there to help debug
this, and that causes it to not repro as well. Grumble, grumble.

I'll poke around more and see if I can get more data.
-Mike

I’ve come up with a consistent repro for this.

#include <stdio.h>
#include <dlfcn.h>
int main( int argc, char *argv[] )
{
printf( “hello world\n” );
void *blah = dlopen("/usr/lib/libbfd.so", RTLD_NOW);
printf(“blah is %p\n”, blah);
if (blah)
dlclose(blah);
}

  1. Compile the above program.
  2. run “lldb -x – blah”
  3. b main
  4. r
  5. expr argc = 2
  6. n
  7. n

You should hit the assert on step 7 when you “next” over the dlopen() statement. If you don’t do step 5, everything is fine. The difference is info.state comes in as add in the assert case and consistent otherwise.

I’ll look at this more tomorrow.

-Mike