New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bootloader: Ensure that symlinks to binaries do not get resolved. #3829
Bootloader: Ensure that symlinks to binaries do not get resolved. #3829
Conversation
The current issue on appveyor seems unrelated. I added a second commit to make the builds work on windows but as far as I know, the new function should never be called from _WIN32.. so why is it being called/built? |
@DavidVentura, I agree. I looks like the failures originated with 6f9a912 per https://ci.appveyor.com/project/matysek/pyinstaller/builds/19649436. I'll open a separate issue for that. |
Great - Can you clarify why I needed to |
I would assume that #if !defined(_WIN32) && !defined(__APPLE__)
/*
* Return full path to a file. Does not resolve symlinks.
*
* Returns false if the path could not be resolved; otherwise, the resolved path is place in ``abs``.
*/
int
pyi_path_fullpath_no_resolve(
/* If ``abs`` is NULL, allocates and returns a new buffer which the caller
* is responsible for freeing. Otherwise, ``abs`` should be a buffer of at
* least PATH_MAX characters. */
char *abs,
/* A relative path to be resolved. */
const char *rel)
{
char dirname[PATH_MAX];
char full_dirname[PATH_MAX];
char basename[PATH_MAX];
pyi_path_basename(basename, rel);
pyi_path_dirname(dirname, rel);
if (realpath(dirname, full_dirname) == NULL) {
return false;
}
/* ****** TODO ******: Shouldn't this be !=, so that a successful path join return true? */
return (pyi_path_join(abs, full_dirname, basename) == NULL);
}
#endif |
Thanks for the pull-request. Some remarks prior to any code-review.
Regarding the code: These You also need to submit a changelog entry so our users can learn about your change. (This is a new requirement since last September to speed up releasing.) Thanks. |
I have just pushed a change with the changelog entry and proper ifdef - I do not see how this breaks current tests and I do not understand either
Tests do not seem to be broken:
If there's a I added a test that compares |
Thanks for the adding the test. What I don't understand: What does it actually test? The script compares argv[0] and the name /proc/self/status. But I can't see where there is a symlink involved?! As written above: You need to provide a spec-file, which creates a symlink after running EXE. Then you need another test-case, also using a spec-file creating a symlink, but passing |
Indeed, the test is what should be executed after I figure out how to get the symlinks to work.. |
I have created this broken spec file which creates a symlink in the appropiate directory pointing to the generated binary -- I am still unsure on how to get the tests to run the symlinked lrwxrwxrwx 1 david dialout 18 Oct 28 00:46 qqqq -> spec-with-symlink1*
-rwxr-xr-x 1 david dialout 1212624 Oct 28 00:46 spec-with-symlink1* |
Ok, so I tried setting
|
Thanks so far! You made big progress and this is the way to go. Now we go into the not-well-documented corners of PyInstaller's test-suite:-) Looks like you already digged into this and I gave bad advise :-) If you pass the normal app name ( After you made this work, I'll do a detailed code-review. |
I just pushed these changes and indeed now they are being detected. I had to run Also - As you can see I am creating 2 links: one in Is there a less hacky way for me to create the symlink in |
And now I added an |
Thanks for the update. Great to see it is working. I'll review the code whenI find some time for (this can become next week, so please be patient).
Simply run pytest with -s to make it output stdout in any case. At ravis-ci stdout is only printed in case of an error.
Because the executable is searched in dist, and thus the symlink. dist contains the output defined be calling COLLECT. E.g. dynlibs are missing in build and only copied to dist. Since
This is not what xfail is meant for. xfail will continue it the test-case passes and only report at the end of the test-run. If some test-code should fail, then you should assert the code is actually failing. Actually your second test-case doe not test anything usefull: The spec-file does not create a file called More remarks to come in the code review. |
thanks
how can i pass the symlink to be copied over as well?
How can i have a test that I want to fail?
Whoops - I meant for it to work so i will revisit it later
My point is not testing linux' behavior but rather ensure that if for some reason the implementation of the script were replaced by |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I now found time for reviewing the code.Please see the in-line comments, most of which are nit-picking.
Also:
- Please remove the bootloader binaries. We only distribute bineries compilerd by one of the core developers.
- I wonder whether we should add more test-cases:
- one where the symlink points to an absolute path (
os.path.abspath(DISTPATH)
, untested). Maybe this could be put into the same test-case to speed up the test- suite. OTOH this makes it much more complicated to find out which of the cases failed. What do you think? Any idea? - one using a onefile build
- one where the symlink points to an absolute path (
... COLLECT ...
how can i pass the symlink to be copied over as well?
I was wrong here. It's much simpler to create the symlink in the DISTDIR than to tell COLLECT to copy a symlink.
This is not what xfail is meant for.
How can i have a test that I want to fail?
You want the test to pass :-) It's just that your test is "I want this to fail". See https://docs.pytest.org/en/latest/skipping.html?highlight=xfail for how xfail works. Thus you would need to wrap the pyi_builder_spec.test_spec(...)
call by with pytest.raises(...)
see https://docs.pytest.org/en/latest/assert.html#assertions-about-expected-exceptions. Altough I cant't tell you ATM which exception to expect here.
Anyway I don't see any reason for test_symlink_is_not_resolved_fails_long
.
My point is not testing linux' behavior but rather ensure that if for some reason the implementation of the script were replaced by sys.exit(0) we would notice the tests are still working
If this happens, the test-suite is broken and no longer reliable anyway. We would need to ensure this for all other tests, too. Thus I suggest to remove that test-case completely.
@DavidVentura I'd appreciate if you could finish this pull-request as I'm eager to merge it. |
Trigger re-running the tests |
Co-authored-by: Hartmut Goebel <h.goebel@crazy-compilers.com>
The issue occurs in one-file mode only, thus we need to test this.
Test-case for resolving a symlink residing in another directory.
@DavidVentura Thanks for this pull-request. I finally found time merging it. You could have had helped me on this a lot if you would have worked on my remarks. |
This fixes #3823
As far as I understand; the current behavior is wrong: when doing
execvp()
we are passing the resolvedargv[0]
. This means that the name under/proc/self/status
will be incorrect.If the new behavior is desired (it is for me at least; telegraf is reporting parent and child as different processes and that confuses my monitoring system) then the whole reading from
/proc/
to get our full path is not needed anymore (as that will resolve all symlinks).Let me know if you want me to change anything