-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Add environment parsing #1091
Add environment parsing #1091
Conversation
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.
OK, I made an initial review but there's a lot to adjust here. In general:
- always indent with 4 spaces
- unless the function body is very small or you don't allocate any resource (e.g. a
malloc
, an openfd
etc.) ALWAYS usegoto;
. As a general rule, every time you want to doreturn NULL
think again and dogoto error;
instead. Forgetting to free resources every time you mean to return an error is very simple, it doesn't scale and that's the door which introduces memory leaks; also, if you want to test you made no mistakes, you can usemake test-memleaks
, which is not bullet proof as it doesn't cover all your code paths but it's something - write docstrings describing what the C function does and be explicit in stating what the possible return values are and what they mean so that the users of the function know how to deal with them
psutil/_pssunos.py
Outdated
@@ -383,6 +385,10 @@ def _proc_name_and_args(self): | |||
return cext.proc_name_and_args(self.pid, self._procfs_path) | |||
|
|||
@memoize_when_activated | |||
def _proc_environ(self): | |||
return cext.proc_environ(self.pid, self._procfs_path) |
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.
There's no need to use memoize_when_activated
as this function only return one thing.
psutil/_psutil_sunos.c
Outdated
const char *procfs_path; | ||
PyObject *py_retlist = NULL; | ||
PyObject *envname; | ||
PyObject *envval; |
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.
Please add a py_
prefix to all python-related variables. Also fix indentation.
psutil/_psutil_sunos.c
Outdated
char **env; | ||
ssize_t env_count = -1; | ||
char *dm; | ||
int i; |
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.
indentation
psutil/_psutil_sunos.c
Outdated
|
||
py_retlist = PyDict_New(); | ||
if (! py_retlist) | ||
return PyErr_NoMemory(); |
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.
indentation; also you should return NULL instead.
psutil/_psutil_sunos.c
Outdated
|
||
for (i=0; i<env_count; i++) { | ||
if (! env[i]) | ||
break; |
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.
indentation
} | ||
} | ||
|
||
result[len] = '\00'; |
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.
result
is not free
d
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.
No need to free it. If there is no data to read, then just return empty C string (len = 0, alloced size = 1, result[0] = 0 == valid zero length C string)
size_t pblock_size; | ||
int i; | ||
|
||
assert(ptr_size == 4 || ptr_size == 8); |
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.
what does this do?
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.
Explicitly checks that I didn't pass some invalid pointer size
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.
OK but what happens? A warning is print on stderr?
if (lseek(fd, offt, SEEK_SET) == (off_t)-1) { | ||
PyErr_SetFromErrno(PyExc_OSError); | ||
return -1; | ||
} |
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.
fd
is not closed (use goto error;
)
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.
Caller's responsibility
|
||
if (r != ptr_size) { | ||
PyErr_SetString( | ||
PyExc_ValueError, "Pointer block is truncated"); |
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'd rather throw a RuntimeError
here
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.
what about this?
as, info.pr_envp, ptr_size); | ||
|
||
if (env_count >= 0 && count) | ||
*count = env_count; |
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.
indentation
6d89c05
to
cd7a5a2
Compare
Updated |
cd7a5a2
to
1e8dd17
Compare
psutil/_psutil_sunos.c
Outdated
return py_retdict; | ||
|
||
enomem: | ||
PyErr_NoMemory(); |
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.
This does not free resources. Get rid of this and just do:
PyErr_NoMemory();
goto error;
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.
Which resources are not freed there?
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.
This, which you do in the error
body later:
+ if (env && env_count >= 0)
+ psutil_free_cstrings_array(env, env_count);
+
+ Py_XDECREF(py_envname);
+ Py_XDECREF(py_envval);
+ Py_XDECREF(py_retdict);
+ return NULL;
As a general rule you should only define one "error" goto block, not different gotos, and implement the whole free resource logic in there (in 1 place only). Apply this construct everywhere. It's safer and also consistent with the existent code base.
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 can do this, but I can't get this...
After landing enomem codeflow get to error. So It do the same + set NoMemory exception.
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.
Because before malloc
you may already have allocated other resources. Or maybe you didn't, but you change your code later and open a fd or use another malloc
before this one, or create a Python list or whatever.
The "free" logic should just live in one place (error:
) so that every time you want to raise an exception you set the error type (PyErr_NoMemory();
or whatever) and then just do goto error
.
This way you don't have to reason about what resources you allocated thus far and you don't have to infer whether to use goto errmem
, goto oserror
etc.
@@ -0,0 +1,302 @@ | |||
/* |
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.
you missed this comment
sprintf(proc_path, "%s/%i/as", procfs_path, pid); | ||
fd = open(proc_path, O_RDONLY); | ||
if (fd < 0) | ||
PyErr_SetFromErrno(PyExc_OSError); |
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.
oh you're right
Please split this in 2 files: |
1e8dd17
to
62c6407
Compare
62c6407
to
385bfeb
Compare
This is my last bump. I'm tired of rebasing and not going to do anything else. Feel free to reject or to change as you like if you don't like the code |
Dude, I appreciate what you are doing here, really, and I understand your frustration, but this is how code review works. Most of the nitpicks I provided in this review session are objectively correct and well motivated. psutil has very high code quality standards, pretty much the same as when you submit a PR for the cPython project (basically that is where I trained myself and I'm coming from being a core-dev myself). |
I will merge this now and fix the other few remaining nitpicks myself. I appreciate your contribution. |
I get this:
|
First two happens when you try to get environment of 64 bit process from 32 bit. It happens because psinfo_t has different fields size for 32 and 64 bit processes. So when you read psinfo_t structure of 64 bit process from 32 you will get truncated invalid pointers. That's the check is_ptr_dereference_possible about. |
What 3rd test is about I can't get, because as I understand http://pubs.opengroup.org/onlinepubs/9699919799/ it's not possible to not to have '=' sign. |
OK, got back from my vacation so looking back at this. There is another problem: when running as a limited user I'm able to query only the current process, whereas all other processes either raise AccessDenied (which is fine) or return an empty dict (which is not). |
OK I think I know why this happens. |
* rename C module * rename C file * fix compilation error * small refactoring * small refactoring * raise AccessDenied if info.pr_envp is empty, see #1091 (comment) * fix envs with no equal sign * style * update doc * style
OK, I should have fixed it: #1097 |
No description provided.