Open Bug 1042134 Opened 10 years ago Updated 2 years ago

File>Save As... / Ctrl-S do nothing

Categories

(Toolkit :: Downloads API, defect)

31 Branch
x86_64
Linux
defect

Tracking

()

REOPENED

People

(Reporter: felix-mozilla, Unassigned)

References

Details

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0 (Beta/Release)
Build ID: 20140716183446

Steps to reproduce:

I have had this issue at least since Firefox 30 now.
I am compiling Firefox from source (the official release tarballs), with these build flags:

--x-includes=/usr/X11R7/include --x-libraries=/usr/X11R7/lib64 --prefix=/opt/firefox64 --with-system-zlib --enable-application=browser --enable-pango --enable-svg --enable-svg-renderer=cairo --enable-system-cairo --enable-strip --disable-debug --enable-optimize="-O2 -fPIC -pipe" --enable-official-branding --enable-default-toolkit=cairo-gtk2 --disable-necko-wifi --disable-gnomevfs --disable-gnomeui --disable-crashreporter --disable-pulseaudio

When I open a web page and want to save it, nothing happens. The "where do you want to save this" dialog does not show up.

When I reach this via a link that goes to an application/octet-stream, I get a temp file with a random name in /tmp, containing the download data, but again no save dialog.

I figured this would be an artifact of me building from source, so for Firefox 31, I decided to install the official binary tarball for linux-amd64.  I installed it, no improvement.

So I deleted my ~/.mozilla directory and started from scratch, figuring that one of my add-ons must be causing this.

No effect.

I think this is a bug in firefox.  I have this problem both on my laptop and my desktop (both running a custom Linux distribution I compile myself).

The installed software versions are:

glib-2.41.1 gtk+-2.24.24 cairo-1.12.16 atk-2.13.1 fontconfig-2.10.92 harfbuzz-0.9.19 freetype-2.5.3

While trying to get my profile up to snuff again, I found out that installing add-ons also fails reliably. With the error message "Error installing".  On the console this error message appears:

1406047522238	addons.xpi	WARN	Failed to install /tmp/tmp-zqy.xpi from https://addons.mozilla.org/firefox/downloads/file/261404/adblock_plus-2.6.3-fx+an+sm+tb.xpi?src=api: {"operation":"stat","path":"/home/leitner/.mozilla/firefox/goqtwzlg.default/extensions/staged/{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}.xpi","unixErrno":0}

unixErrno 0?  Srsly?
Unsurprisingly, this works for most people or we would have fixed it already. If you try to save a web page with the official binary tarball, do you get any errors in the browser console? (ctrl-shift-j)
Flags: needinfo?(felix-mozilla)
Yes, indeed.  Here it is:

Unix error 0 during operation makeDir on file /home/leitner/Downloads (No error information)

from Promise-backend.js

This looks like the error might be related to the add-on installation failure.

For the record: /home/leitner/Download exists and has lots of files in it.
Flags: needinfo?(felix-mozilla)
(In reply to felix-mozilla from comment #2)
> Yes, indeed.  Here it is:
> 
> Unix error 0 during operation makeDir on file /home/leitner/Downloads (No
> error information)
> 
> from Promise-backend.js
> 
> This looks like the error might be related to the add-on installation
> failure.
> 
> For the record: /home/leitner/Download exists and has lots of files in it.

Is there anything that would prevent Firefox and/or the user running Firefox from creating directories inside /home/leitner/Downloads (like the directory permissions, for instance, or quotas, or...) ?
Component: Untriaged → File Handling
Flags: needinfo?(felix-mozilla)
Nope.  It's on my root partition, no quotas, has 250 gigs free.

I download files into that directory all the time with Chrome, and I used to do it with Firefox as well.

Why would firefox want to create a directory there though?
I read this error message as "Firefox tried to do a mkdir on that directory to make sure it's there".
And then there was a mistake reporting the error upwards.

My about:config specifies this directory as the place where I want firefox to store downloaded files.
Flags: needinfo?(felix-mozilla)
(In reply to felix-mozilla from comment #4)
> Nope.  It's on my root partition, no quotas, has 250 gigs free.
> 
> I download files into that directory all the time with Chrome, and I used to
> do it with Firefox as well.
> 
> Why would firefox want to create a directory there though?
> I read this error message as "Firefox tried to do a mkdir on that directory
> to make sure it's there".
> And then there was a mistake reporting the error upwards.
> 
> My about:config specifies this directory as the place where I want firefox
> to store downloaded files.

The error is from Firefox's OS.File module, which calls makeDir in 3 different places in http://mxr.mozilla.org/mozilla-central/source/toolkit/components/jsdownloads/src/DownloadIntegration.jsm - all of which have ignoreExisting: true. In other words, if the directory exists there should be no error.

Oh, which reminds me - is it a "real" directory or a symlink?

Paolo, any idea on how to further debug what's going wrong here? I'm not an expert on our downloads code (nor unix permissions problems...)
Component: File Handling → Download Manager
Flags: needinfo?(paolo.mozmail)
Flags: needinfo?(felix-mozilla)
Product: Firefox → Toolkit
That would explain the error code 0 in the error message.

That begs the question: why does the code still think it's an error and aborts?
Flags: needinfo?(felix-mozilla)
Oh and answering your question: it's a directory (not a symlink), it's owned by my UID, and I have rwx permission to it.
(In reply to felix-mozilla from comment #6)
> That would explain the error code 0 in the error message.
> 
> That begs the question: why does the code still think it's an error and
> aborts?

I don't know.

The implementation ends up thin-wrapping system libraries for its mkdir call:

http://mxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/modules/osfile_unix_back.jsm

(using jsctypes, which is like python ctypes except for js)

the wrapper above that which deals with the flag is here:

http://mxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/modules/osfile_unix_front.jsm#433

which basically implies that the result of the mkdir operation is -1, but it returns 0 as an error code.

I don't know why it'd do that. Yoric or Paolo probably would, however... need moar needinfo. :-)
Flags: needinfo?(dteller)
Well the result of mkdir is supposed to be -1, and errno == EEXIST.
The directory is already there, after all.

And ignoring the error is OK too, since the directory is already there, and all we wanted is to make sure it is there.

The question is why the installation aborts then.
I actually have no idea why mkdir should return an errno of 0 instead of EEXIST on your system.

What do you see if you run "mkdir /home/leitner/Downloads" from a terminal?

I see the "File exists" error message on my system:

$ mkdir /home/paolo/Downloads
mkdir: cannot create directory `/home/paolo/Downloads': File exists
Flags: needinfo?(paolo.mozmail)
mkdir returns -1 EEXIST, obviously.

But as Gijs noted, the JS code turns that into error code 0 because the "it's OK if the directory already exists" flag is set.

The question is why the code above that is aborting the attempt then.
(In reply to felix-mozilla from comment #11)
> But as Gijs noted, the JS code turns that into error code 0 because the
> "it's OK if the directory already exists" flag is set.

I'm not following you. Looking at:

http://mxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/modules/osfile_unix_front.jsm#433

There is no code setting errno to 0, hence ctypes.errno must be 0 from the beginning, and this is why the check fails. If you see the "File exists" error in the terminal, I don't see how this wouldn't work in Firefox, except maybe if third-party software is changing the behavior of the mkdir API for the Firefox process only.
(In reply to :Paolo Amadini from comment #12)
> (In reply to felix-mozilla from comment #11)
> > But as Gijs noted, the JS code turns that into error code 0 because the
> > "it's OK if the directory already exists" flag is set.
> 
> I'm not following you. Looking at:
> 
> http://mxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/
> modules/osfile_unix_front.jsm#433
> 
> There is no code setting errno to 0, hence ctypes.errno must be 0 from the
> beginning, and this is why the check fails.

Indeed. We could theoretically add a an && errno != 0 check in the if (result == -1) line in that link (assuming that errno === 0 is always indicative of success or lack of an error), but the real question is what Paolo just said: why is errno 0 instead of EEXISTS ?
I don't know all the Firefox infrastructure, but return code 0 means "no error".
It does not matter where the 0 came from.  This should never be interpreted as an error anywhere.

433      File._makeDir = function makeDir(path, options = {}) {
434        let omode = options.unixMode !== undefined ? options.unixMode : DEFAULT_UNIX_MODE_DIR;
435        let result = UnixFile.mkdir(path, omode);
436        if (result == -1) {
437          if ((!("ignoreExisting" in options) || options.ignoreExisting) &&
438              (ctypes.errno == Const.EEXIST || ctypes.errno == Const.EISDIR)) {
439            return;
440          }
441          throw new File.Error("makeDir", ctypes.errno, path);
442        }
443      };

I'm not a Javascript programmer, but this looks to me like result is a local variable and is not returned. In case of an error, an exception is thrown in line 441.

Here is what happens when I do a mkdir /home/leitner/Downloads:

mkdir("/home/leitner/Downloads", 0755)  = -1 EEXIST (File exists)

So clearly mkdir(2) is working as expected.

Here, I'll do an strace on thunderbird while trying to install lightning:

$ grep mkdir tb.log
21812 mkdir("/home/leitner/.thunderbird/Crash Reports", 0700) = -1 EEXIST (File exists)
21812 mkdir("/home/leitner/.cache/thunderbird/2qjzbtj6.default/startupCache", 0777) = -1 EEXIST (File exists)
21812 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default", 0755) = -1 EEXIST (File exists)
21812 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default", 0755) = -1 EEXIST (File exists)
21812 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default", 0755) = -1 EEXIST (File exists)
21812 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default", 0755) = -1 EEXIST (File exists)
21812 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default", 0755) = -1 EEXIST (File exists)
21812 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default", 0755) = -1 EEXIST (File exists)
21867 mkdir("/home/leitner/.cache/thunderbird/2qjzbtj6.default/Cache/E/5E", 0700 <unfinished ...>
21867 <... mkdir resumed> )             = 0
21867 mkdir("/home/leitner/.cache/thunderbird/2qjzbtj6.default/Cache/1/DE", 0700) = 0
21835 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default/extensions", 0700 <unfinished ...>
21835 <... mkdir resumed> )             = -1 EEXIST (File exists)
21835 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default/extensions/staged", 0700 <unfinished ...>
21835 <... mkdir resumed> )             = 0

This is clearly all as expected.  mkdir on extensions fails because it already exists.
mkdir on staged works because it did not exist.

And here is the error message I'm getting on the console:

1406128701097   addons.xpi      WARN    Failed to install /home/leitner/lightning-3.3-sm+tb-linux.xpi from file:///home/leitner/lightning-3.3-sm+tb-linux.xpi: {"operation":"stat","path":"/home/leitner/.thunderbird/2qjzbtj6.default/extensions/staged/{e2fda1a4-762b-4020-b5ad-a41df1933103}","unixErrno":0}

As you can see in the strace, nobody even attempted to mkdir that directory.  Something is very wrong here, and I have no idea what is supposed to happen when this stuff works.  I can only show you what is happening on my system.
When I grep for e2fda1a4 from the GUID, I get this (sorted into the mkdirs for timing reference):

21835 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default/extensions", 0700 <unfinished ...>
21835 <... mkdir resumed> )             = -1 EEXIST (File exists)
21835 mkdir("/home/leitner/.thunderbird/2qjzbtj6.default/extensions/staged", 0700 <unfinished ...>
21835 <... mkdir resumed> )             = 0
21835 stat("/home/leitner/.thunderbird/2qjzbtj6.default/extensions/staged/{e2fda1a4-762b-4020-b5ad-a41df1933103}",  <unfinished ...>
21835 <... stat resumed> 0x7fba0b548470) = -1 ENOENT (No such file or directory)
21812 access("/home/leitner/.thunderbird/2qjzbtj6.default/extensions/staged/{e2fda1a4-762b-4020-b5ad-a41df1933103}", F_OK) = -1 ENOENT (No such file or directory)

Note, when reading this, the different PIDs.  The access is from a different thread.

Note how nobody is attempting to create that directory.  Why?
(In reply to felix-mozilla from comment #14)
> I don't know all the Firefox infrastructure, but return code 0 means "no
> error".
> It does not matter where the 0 came from.  This should never be interpreted
> as an error anywhere.
> 
> 433      File._makeDir = function makeDir(path, options = {}) {
> 434        let omode = options.unixMode !== undefined ? options.unixMode :
> DEFAULT_UNIX_MODE_DIR;
> 435        let result = UnixFile.mkdir(path, omode);
> 436        if (result == -1) {
> 437          if ((!("ignoreExisting" in options) || options.ignoreExisting)
> &&
> 438              (ctypes.errno == Const.EEXIST || ctypes.errno ==
> Const.EISDIR)) {
> 439            return;
> 440          }
> 441          throw new File.Error("makeDir", ctypes.errno, path);
> 442        }
> 443      };
> 
> I'm not a Javascript programmer, but this looks to me like result is a local
> variable and is not returned. In case of an error, an exception is thrown in
> line 441.

ctypes.errno is returned in the exception and not result, yes. But the check ctypes.errno == Const.EEXIST on line 438 fails, because ctypes.errno is 0, while the return value from mkdir (stored in |result|) is -1. In other words, mkdir returns a non-zero return value, but the last ctypes-returned error is 0. That's not expected.

However, the rest of your comment(s) is/are confusing - from comment #1 and comment #2 I was under the impression you tried to save a web page to a file, and this error showed up in the console, making it unrelated to the add-on installation issue. That may or may not be fixable with the same code fix on Firefox's end, but I'd like to focus on that first, instead of trying to simultaneously debug an add-on installation issue in Thunderbird which may or may not be related.
Oh, sorry, you are right.

The problem is that I'm not sure what I can do to help debug the Ctrl-S issue.

Here's the firefox strace:

22217 mkdir("/home/leitner/Downloads", 0700 <unfinished ...>
22217 <... mkdir resumed> )             = -1 EEXIST (File exists)
22217 write(18, "\372", 1 <unfinished ...>
22217 <... write resumed> )             = 1
22217 futex(0x7f11e80ff70c, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x7f11e80ff708, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
22217 futex(0x7f11cc86144c, FUTEX_WAIT_PRIVATE, 455, NULL <unfinished ...>

That is the only mention of Downloads in the whole strace.
And as you can see, it does exactly what it is supposed to do.

The log says:

Unix error 0 during operation makeDir on file /home/leitner/Downloads (No error information)

Note that:
1. error code 0 means no error
2. the code never attempted a stat, all it did was mkdir, and mkdir returned EEXIST, as it should.

If you have an idea how I can help debug this, I'd be happy to.
But it cannot involve building firefox myself, because the build process of firefox does not work with the current release versions of binutils (2.24) and gcc (2.9.1).  Something about hidden symbols.  I'll file a bug about that some other time.
Maybe this will help debug the issue:
I went to preferences and switched to "Always ask where to save files".
I still get the error message about /home/leitner/Downloads in the browser console.
How can that be?
Now I went to about:config and removed the browser.download string that pointed to /home/leitner/Downloads, and I _still_ get the same error string about /home/leitner/Downloads.

WTF?
(In reply to felix-mozilla from comment #19)
> Now I went to about:config and removed the browser.download string that
> pointed to /home/leitner/Downloads, and I _still_ get the same error string
> about /home/leitner/Downloads.
> 
> WTF?

This will be because it's used as the default for the prompt of where to save it - but for that to happen, we should obviously ensure it exists... If you pointed the same preference to a different string, I would expect this particular issue to go away (although considering how little we understand of *why* it's broken, it's quite possible you'll have other issues :-( ).
(In reply to felix-mozilla from comment #17)
> Oh, sorry, you are right.
> 
> The problem is that I'm not sure what I can do to help debug the Ctrl-S
> issue.
> 
> Here's the firefox strace:
> 
> 22217 mkdir("/home/leitner/Downloads", 0700 <unfinished ...>
> 22217 <... mkdir resumed> )             = -1 EEXIST (File exists)
> 22217 write(18, "\372", 1 <unfinished ...>
> 22217 <... write resumed> )             = 1
> 22217 futex(0x7f11e80ff70c, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x7f11e80ff708,
> {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
> 22217 futex(0x7f11cc86144c, FUTEX_WAIT_PRIVATE, 455, NULL <unfinished ...>
> 
> That is the only mention of Downloads in the whole strace.
> And as you can see, it does exactly what it is supposed to do.
> 
> The log says:
> 
> Unix error 0 during operation makeDir on file /home/leitner/Downloads (No
> error information)
> 
> Note that:
> 1. error code 0 means no error
> 2. the code never attempted a stat, all it did was mkdir, and mkdir returned
> EEXIST, as it should.


I wonder if the ctypes errno gets overwritten by something else... Yoric, is that possible?
I am getting a bit confused between the Thunderbird issue and the Downloads issue. Do we have any reason to believe that they are related?

Now, regarding errno. Normally, Unix offers one errno per thread and OS.File uses its own thread, so that shouldn't be overwritten. I believe it more likely that something is catching the error and rethrowing it incorrectly.

Felix, can you turn option `toolkit.osfile.log` to `true` in about:config and try again the steps? This should add plenty of logging for OS.File, which should at least tell us which error is coming from the worker thread.
Flags: needinfo?(dteller)
I figured they'd be related because for both thunderbird and firefox I can't install addons and in both cases the error messages look alike and have something to do with mkdir, and the save issue error message also says something about mkdir.  But never mind, if we can debug those separately, we should do so.

I enabled toolkit.osfile.log and did ctrl-s and this is what showed up on the console:

OS Controller Posting message {"fun":"makeDir","args":[{"string":"/home/leitner/Downloads"},{"ignoreExisting":true}],"id":183}
OS Controller Message posted
OS Controller Received message from worker {"fail":{"operation":"makeDir","unixErrno":0,"path":"/home/leitner/Downloads"},"id":183}

That points the finger at the worker being wrong, right?
It should not say fail and then have an errno of 0.
The problem went away with Firefox 33.1, maybe because I also updated my gcc to 4.9.2 from 4.9.1.
Status: UNCONFIRMED → RESOLVED
Closed: 10 years ago
Resolution: --- → WORKSFORME
I have the same problem which I reported in https://bugzilla.mozilla.org/show_bug.cgi?id=1135003.
I had a similar problem on Debian linux (intel x86);
the reason was a 'libc.so' symlink in directory /lib:

/lib/libc.so -> libc-2.11.3.so

When firefox tried 'dlopen(libc)', it successfully loaded this, so it had two loaded libc.so:

0xf7500a80  0xf75f647c  Yes (*)     /lib/i686/cmov/libc.so.6
0xdd8cea70  0xdd9c29bc  Yes (*)     /lib/libc.so

This duplication caused problems with errno in ctypes; results were failed 'saves pages', failed 'install extensions' etc.
(In reply to Lőrinczy Zsigmond from comment #26)
> I had a similar problem on Debian linux (intel x86);
> the reason was a 'libc.so' symlink in directory /lib:
> 
> /lib/libc.so -> libc-2.11.3.so
> 
> When firefox tried 'dlopen(libc)', it successfully loaded this, so it had
> two loaded libc.so:
> 
> 0xf7500a80  0xf75f647c  Yes (*)     /lib/i686/cmov/libc.so.6
> 0xdd8cea70  0xdd9c29bc  Yes (*)     /lib/libc.so
> 
> This duplication caused problems with errno in ctypes; results were failed
> 'saves pages', failed 'install extensions' etc.

Yoric, is there something we can do on our side to prevent this from happening?
Status: RESOLVED → REOPENED
Ever confirmed: true
Flags: needinfo?(dteller)
Resolution: WORKSFORME → ---
The problem is certainly here: https://dxr.mozilla.org/mozilla-central/source/toolkit/components/osfile/modules/osfile_unix_allthreads.jsm#41

I suppose that we could explicitly look for libc.so.6 before libc.so.
Flags: needinfo?(dteller)
In linux/glibc-2.2+, dlopen has an option RTLD_NOLOAD which could be useful (usually libc *is* loaded by this time).
I solved my problem described in bug 1135003 (marked duplicate of this bug). I've installed musl libc and because of that I have libc.so symlink. Once I removed libc.so symlink firefox started working as expected.

The problematic "configuration" was:

root@gf:/lib# ls -l /lib/libc.so*
lrwxrwxrwx 1 root root 17 Mar 14  2012 /lib/libc.so -> ld-musl-i386.so.1
lrwxrwxrwx 1 root root 12 Mar 14  2013 /lib/libc.so.6 -> libc-2.17.so
See Also: → 1342689
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.