Bug 4843 - Issue with pseudo on 64-bit build host
Summary: Issue with pseudo on 64-bit build host
Status: RESOLVED FIXED
Alias: None
Product: OE-Core
Classification: Build System, Metadata & Runtime
Component: configuration (show other bugs)
Version: unspecified
Hardware: x86 Multiple
: Medium+ normal
Target Milestone: 1.5
Assignee: Seebs
QA Contact:
URL:
Whiteboard:
Depends on:
Blocks:
 
Reported: 2013-07-11 14:28 UTC by Erik Botö
Modified: 2013-09-13 14:07 UTC (History)
7 users (show)

See Also:
OS type for building Yocto: ---
Type of Regression: ---
Verified:
Documentation change: No (bug/feature does not impact docs)


Attachments
Fix bug by checking incoming environment for PATCH_UNLOAD=1 (5.78 KB, patch)
2013-08-26 08:15 UTC, Peter A. Bigot
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Erik Botö 2013-07-11 14:28:54 UTC
In bitbake.conf FAKEROOTBASEENV is set to contain "PSEUDO_LIBDIR=${STAGING_BINDIR_NATIVE}/../lib/pseudo/lib" but on my buildhost libpseudo.so is in ${STAGING_BINDIR_NATIVE}/../lib/pseudo/lib64.

For me this causes rpm:s that use qemu_run_binary() to do stuff during do_rootfs() (using post-install scripts) to fail, since ld.so can't find libpseudo.so it gives an error that contains "ERR" which package_rpm.bbclass rpm_log_check() picks up.

The error is: 
ERROR: ld.so: object 'libpseudo.so' from LD_PRELOAD cannot be preloaded: ignored.

I got confused for a while since the command used in the post-install script worked ok in a devshell but not during do_rootfs(), but this is due to the fact that LD_LIBRARY_PATH in the devshell contains:
"<mybuilddir>/tmp/sysroots/x86_64-linux/usr/bin/../lib/pseudo/lib64" . So for devshells the environment is correctly set up.

So in short: 
The PSEUDO_UNLOAD=1 in qemu.bbclass's qemu_run_binary() should make pseudo remove the variable before running qemu, but since the host's libpseudo isn't found LD_PRELOAD is not stripped of libpseudo.so and the command run "inside" qemu will also display an error which is picked up in the log sanity check. 

This has also been discussed a bit on oe-core mailing list, http://lists.openembedded.org/pipermail/openembedded-core/2013-June/080328.html.
Comment 1 Laszlo Papp 2013-07-25 15:14:18 UTC
I can reproduce this issue on Arch 64 bit.

Is there a known workaround to get over the issue for now?
Comment 2 Ross Burton 2013-07-25 15:16:27 UTC
ACCEPTED means that the assignee is actively working on it.  Please don't set it for bugs that you are not the assignee of.
Comment 3 Seebs 2013-07-26 00:21:07 UTC
I should clarify a thing.

It *should be* okay for PSEUDO_LIBDIR not to be the actual library directory.

What happens is:
No matter what the host's naming conventions are, pseudo picks some directory (.../pseudo), and then stores 32-bit libpseudo in .../pseudo/lib, and 64-bit in .../pseudo/lib64. However, 32-bit libpseudo doesn't necessarily exist on 64-bit hosts.

We then store the name of just the base directory in PSEUDO_LIBDIR.

When pseudo wants to set up its environment, it checks for PSEUDO_LIBDIR in LD_LIBRARY_PATH. If that's not present, or if there is no LD_LIBRARY_PATH, pseudo sets LD_LIBRARY_PATH to contain ${PSEUDO_LIBDIR}:${PSEUDO_LIBDIR}64.

There *does* seem to be one way you could get past this: If you somehow managed to get LD_LIBRARY_PATH set to contain ${PSEUDO_LIBDIR}, but *not* to contain ${PSEUDO_LIBDIR}64, then pseudo wouldn't realize it needed to fix that up. But that shouldn't ever happen; either we remove all of those or we don't remove any of them.

I've been trying to find a system on which I can reproduce this. I can confirm that we aren't seeing this problem on at least a handful of different 64-bit systems, including both systems with a lib32 where lib is 64-bit, and those with a lib64.
Comment 4 Gary Thomas 2013-08-16 12:13:57 UTC
It fails for me on Ubuntu 12.04/x86_64 - have you tried this host yet?

Note: I can reproduce this error quite simply by building an image with 'systemd' in DISTRO_FEATURES.  On x86_64 it fails with this error, in i386 host it succeeds.
Comment 5 Laszlo Papp 2013-08-16 12:15:28 UTC
Gary, yes, I did.

It would be nice to see any progress in here ...
Comment 6 Gary Thomas 2013-08-16 13:12:09 UTC
(In reply to comment #5)
> Gary, yes, I did.
> 
> It would be nice to see any progress in here ...

I ran it on a pretty much virgin system install.  Perhaps you have some support library installed that I don't have?  Do you have the pseudo package 'ia32-libs' installed?
Comment 7 Laszlo Papp 2013-08-16 13:13:44 UTC
I mean, it fails for me, too, on Ubuntu x86_64, 12.04.
Comment 8 Seebs 2013-08-16 14:16:08 UTC
I haven't been able to make it fail on a host which can correctly build 32-bit binaries. Ubuntu 12.04/x86_64 is one of my default test environments.

There's one obvious shortcoming in the current setup, which is that the pseudo recipe tries to build a 32-bit libpseudo if and only if NO32LIBS is "0" *and* it can find a stubs-32.h, indicating that a 32-bit build is likely to succeed. But I'm not sure whether that's related to the failure case here.

The obvious thing to do would be to set NO32LIBS to "0" and make sure you have 32-bit libraries/compiler available. If that "fixes" this, then we're down to the question of why this particular thing is needing to run a 32-bit binary for some people but doesn't seem to be for others.
Comment 9 Gary Thomas 2013-08-16 14:40:24 UTC
(In reply to comment #8)
> I haven't been able to make it fail on a host which can correctly build
> 32-bit binaries. Ubuntu 12.04/x86_64 is one of my default test environments.
> 
> There's one obvious shortcoming in the current setup, which is that the
> pseudo recipe tries to build a 32-bit libpseudo if and only if NO32LIBS is
> "0" *and* it can find a stubs-32.h, indicating that a 32-bit build is likely
> to succeed. But I'm not sure whether that's related to the failure case here.
> 
> The obvious thing to do would be to set NO32LIBS to "0" and make sure you
> have 32-bit libraries/compiler available. If that "fixes" this, then we're
> down to the question of why this particular thing is needing to run a 32-bit
> binary for some people but doesn't seem to be for others.

One thing we can do is compare what's on my host vs what's on yours, since it
fails for me but succeeds for you.  If you could email me the packages you have
installed, I can compare and experiment a bit.  I'm not a Debian guru so I may
not know the best way to get this list but 'sudo dpkg -l | grep ^ii' will work.  You
could also just attach the list to this bug if you want.
Comment 10 Seebs 2013-08-16 18:13:46 UTC
I have normally been running our locally-modified build system, so it may be I'm just out of sync with oe-core.

Just to clarify, you're getting this with a stock oe-core, default local.conf, with

DISTRO_FEATURES += " systemd"

or the equivalent?
Comment 11 Gary Thomas 2013-08-16 21:51:02 UTC
(In reply to comment #10)
> I have normally been running our locally-modified build system, so it may be
> I'm just out of sync with oe-core.
> 
> Just to clarify, you're getting this with a stock oe-core, default
> local.conf, with
> 
> DISTRO_FEATURES += " systemd"
> 
> or the equivalent?

Correct - I adjusted DISTRO_FEATURES (directly in poky.conf but I'm sure you could do it using _append) and built a stock image (core-image-minimal).  The error happens every time on my x86_64 system.
Comment 12 Ross Burton 2013-08-20 09:43:13 UTC
As another data point to show how bizarre this problem is: I have a 64-bit build host (Debian 7) with no 32-bit compat libraries present.  Suddenly I started getting this error with no obvious cause, and "fixed" it by building just ipkg instead of rpm and ipkg.  A few weeks later I re-enabled rpms and it works fine...
Comment 13 Gary Thomas 2013-08-23 16:07:22 UTC
(In reply to comment #12)
> As another data point to show how bizarre this problem is: I have a 64-bit
> build host (Debian 7) with no 32-bit compat libraries present.  Suddenly I
> started getting this error with no obvious cause, and "fixed" it by building
> just ipkg instead of rpm and ipkg.  A few weeks later I re-enabled rpms and
> it works fine...

I'm not sure it has anything to do with the packaging - I only ever use ipk.

I have two Ubuntu 12.04 systems here - it runs on one and fails on the other.  I've made sure that they both have identical packages installed (to the tune of installing some 975 packages today to make them match!).  Still fails on one but not the other.

I'm *really* confused by this...
Comment 14 Peter A. Bigot 2013-08-26 08:15:59 UTC
Created attachment 1440 [details]
Fix bug by checking incoming environment for PATCH_UNLOAD=1

This fixes the manifestation of the bug in my environment.  See also http://patches.openembedded.org/patch/56589/
Comment 15 Gary Thomas 2013-08-26 19:50:04 UTC
(In reply to comment #14)
> Created attachment 1440 [details]
> Fix bug by checking incoming environment for PATCH_UNLOAD=1
> 
> This fixes the manifestation of the bug in my environment.  See also
> http://patches.openembedded.org/patch/56589/

Verified that this patch solves my problems with building on Ubuntu 12.04/x86_64
Comment 16 Seebs 2013-09-03 15:29:29 UTC
D'oh! Very good catch -- I think the key thing is "checking the wrong environment".

I have now changed my position from "I can't see how this could fail" to "I can't see how this could work".

It's true that there's a memory leak; the historical explanation for this is "we know we are about to call exec(), so we don't care", but it may be better to clean it up.

The one pending question I see: Obviously, in the execve case, we want to unload pseudo if PSEUDO_UNLOAD is in envp.

But what if PSEUDO_UNLOAD was in *our* environment, previously, and is NOT in the provided envp? My intuition is to say that we probably want it unloaded anyway. So I think it should probably be checking both for a PSEUDO_UNLOAD= in envp, and for an existing set value of PSEUDO_UNLOAD. I'm going to ponder this a bit.

Thanks a ton for figuring this one out.
Comment 17 Peter A. Bigot 2013-09-03 16:00:16 UTC
(In reply to comment #16)
> D'oh! Very good catch -- I think the key thing is "checking the wrong
> environment".
> 
> I have now changed my position from "I can't see how this could fail" to "I
> can't see how this could work".

Yes.

> It's true that there's a memory leak; the historical explanation for this is
> "we know we are about to call exec(), so we don't care", but it may be
> better to clean it up.

I think so.

> The one pending question I see: Obviously, in the execve case, we want to
> unload pseudo if PSEUDO_UNLOAD is in envp.
> 
> But what if PSEUDO_UNLOAD was in *our* environment, previously, and is NOT
> in the provided envp? My intuition is to say that we probably want it
> unloaded anyway. So I think it should probably be checking both for a
> PSEUDO_UNLOAD= in envp, and for an existing set value of PSEUDO_UNLOAD. I'm
> going to ponder this a bit.

I believe the effect of the approach I took was to unload if PSEUDO_UNLOAD appeared in either the provided or current environment.  It's not clear to me what would cause PSEUDO_UNLOAD to be meaningfully set in the current environment:

  PSEUDO_UNLOAD=1 psuedo no i am not root

?

> Thanks a ton for figuring this one out.

You're welcome.
Comment 18 Seebs 2013-09-04 19:32:51 UTC
So, this converted from "how did this sometimes fail?" to "how did this sometimes work?"

I hate those, so I spent some time looking at it. In particular, I modified a local copy of pseudo to perform the extra check, and diagnose cases where PSEUDO_UNLOAD was in envp but the existing check came up empty, and then I made a program which called id using execve, and setting PSEUDO_UNLOAD in envp.

Aaaand... it still worked, for me. So I studied it more. And I finally found out roughly what's up.

First off: The pseudo client will act as though pseudo were disabled if you successfully cause it to get loaded when PSEUDO_UNLOAD is set to 1. So we might simply fail to notice the problems.

Secondly, the behavior when dealing with an unload is to set everything else up in the environment... Then unset the LD_PRELOAD value, but leave the others there.

Finally, a plausible explanation for why this is affecting some people and not others:

$ pseudo bash -c "PSEUDO_UNLOAD=1 env" | grep LD_PRELOAD
$ pseudo dash -c "PSEUDO_UNLOAD=1 env" | grep LD_PRELOAD
LD_PRELOAD=libpseudo.so
$

It turns out that, in bash, PSEUDO_UNLOAD is in the environment before execve() is called, and in dash, it's not. And that is probably the underlying quirk that was causing this to fire some of the time.
Comment 19 Peter A. Bigot 2013-09-04 19:53:28 UTC
(In reply to comment #18)
> It turns out that, in bash, PSEUDO_UNLOAD is in the environment before
> execve() is called, and in dash, it's not. And that is probably the
> underlying quirk that was causing this to fire some of the time.

Good work.

Over the years I've developed the habit of reconfiguring vendor-supplied environments only when I absolutely cannot tolerate the defaults, instead adapting my habits and expectations to the local "standard".  I don't redirect /bin/sh on Ubuntu from dash to bash, and your result explains why the original approach didn't work for me.
Comment 21 Laszlo Papp 2013-09-13 11:15:33 UTC
Well, thanks.
Comment 22 Erik Botö 2013-09-13 14:07:07 UTC
Super, thanks!